pax_global_header00006660000000000000000000000064147762655440014536gustar00rootroot0000000000000052 comment=ae7ecb01e898631f2d32ab957f839f4a465447d5 uwsgi-2.0.29/000077500000000000000000000000001477626554400127665ustar00rootroot00000000000000uwsgi-2.0.29/.github/000077500000000000000000000000001477626554400143265ustar00rootroot00000000000000uwsgi-2.0.29/.github/workflows/000077500000000000000000000000001477626554400163635ustar00rootroot00000000000000uwsgi-2.0.29/.github/workflows/compile-test.yml000066400000000000000000000042501477626554400215140ustar00rootroot00000000000000name: Compile test on: push: branches: [ master, uwsgi-2.0 ] pull_request: branches: [ master, uwsgi-2.0 ] jobs: build: strategy: matrix: libpcre: ["libpcre3-dev", "libpcre2-dev"] os: ["ubuntu-22.04"] cc: [gcc, clang] include: - os: ubuntu-22.04 php: "php8.1" php-config: "php-config8.1" runs-on: ${{ matrix.os }} steps: - name: remove sury php ppa that does not ship libphpX.Y-embed run: | sudo add-apt-repository --remove ppa:ondrej/php sudo apt remove ${{ matrix.php }}-dev ${{ matrix.php }} ${{ matrix.php }}-common - name: Install dependencies run: | sudo apt update -qq sudo apt install --no-install-recommends -qqyf python3-dev \ libxml2-dev ${{ matrix.libpcre }} libcap2-dev \ libargon2-0-dev libsodium-dev \ ${{ matrix.php }}-dev lib${{ matrix.php }}-embed \ liblua5.1-0-dev ruby-dev \ libjansson-dev libldap2-dev libpq-dev \ libpam0g-dev libsqlite3-dev libyaml-dev \ libzmq3-dev libmatheval-dev libperl-dev \ libonig-dev libdb-dev libqdbm-dev libbz2-dev \ libwrap0-dev libgeoip-dev libv8-dev libxslt1-dev \ libboost-thread-dev libboost-filesystem-dev \ libssl-dev libacl1-dev python-greenlet-dev \ libcurl4-openssl-dev \ openjdk-11-jdk libgloox-dev gccgo \ cli-common-dev mono-devel mono-mcs uuid-dev \ curl check ${{ matrix.cc == 'clang' && 'clang' || '' }} - uses: actions/checkout@v4 - name: Build kitchensink uWSGI binary with gcc or default with clang run: CC=${{ matrix.cc }} UWSGICONFIG_PHPPATH=${{ matrix.php-config }} /usr/bin/python3 uwsgiconfig.py --build ${{ matrix.cc == 'gcc' && 'travis' || '' }} - name: Build uWSGI binary run: | CC=${{ matrix.cc }} /usr/bin/python3 uwsgiconfig.py --build base - name: Build cgi plugin run: | CC=${{ matrix.cc }} /usr/bin/python3 uwsgiconfig.py --plugin plugins/cgi base - name: Build dummy plugin run: | CC=${{ matrix.cc }} /usr/bin/python3 uwsgiconfig.py --plugin plugins/dummy base uwsgi-2.0.29/.github/workflows/test.yml000066400000000000000000000057731477626554400201010ustar00rootroot00000000000000name: Test on: push: branches: [ master, uwsgi-2.0 ] pull_request: branches: [ master, uwsgi-2.0 ] jobs: unittest: runs-on: ubuntu-22.04 steps: - name: Install dependencies run: | sudo apt update -qq sudo apt install --no-install-recommends -qqyf \ libpcre3-dev libjansson-dev libcap2-dev \ check - uses: actions/checkout@v4 - name: Run unit tests run: make unittests test: runs-on: ubuntu-22.04 steps: - name: Install dependencies run: | sudo apt update -qq sudo apt install --no-install-recommends -qqyf \ libpcre2-dev libjansson-dev libcap2-dev \ php-dev libphp-embed libargon2-dev libsodium-dev \ pypy3 default-jdk-headless libperl-dev \ ruby-dev ruby-rack - uses: actions/checkout@v4 - name: Set env run: echo "PROFILE=integration-tests" >> $GITHUB_ENV - name: Run integration tests run: make all tests python: runs-on: ubuntu-22.04 strategy: matrix: python-version: ["2.7", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] test-suite: [python, deadlocks] steps: - name: Add deadnakes ppa run: sudo add-apt-repository ppa:deadsnakes/ppa -y - name: Install dependencies run: | sudo apt update -qq sudo apt install --no-install-recommends -qqyf python${{ matrix.python-version }}-dev \ libpcre2-dev libjansson-dev libcap2-dev \ curl - name: Install distutils if: contains(fromJson('["3.7","3.8","3.9","3.10","3.11"]'), matrix.python-version) run: | sudo apt install --no-install-recommends -qqyf python${{ matrix.python-version }}-distutils \ - uses: actions/checkout@v4 - name: Build uWSGI binary run: make - name: Build python${{ matrix.python-version }} plugin run: | PYTHON_VERSION=${{ matrix.python-version }} PYTHON_VERSION=python${PYTHON_VERSION//.} /usr/bin/python${{ matrix.python-version }} -V /usr/bin/python${{ matrix.python-version }} uwsgiconfig.py --plugin plugins/python base $PYTHON_VERSION - name: run smoke tests run: | PYTHON_VERSION=${{ matrix.python-version }} PYTHON_VERSION=python${PYTHON_VERSION//.} ./tests/gh-${{ matrix.test-suite }}.sh ${PYTHON_VERSION} rack: runs-on: ubuntu-22.04 strategy: matrix: rack-version: ["300"] steps: - name: Install dependencies run: | sudo apt update -qq sudo apt install --no-install-recommends -qqyf python3-dev \ libpcre2-dev libjansson-dev libcap2-dev ruby3.0-dev \ curl - uses: actions/checkout@v4 - name: Build uWSGI binary run: make - name: Build rack plugin run: | ruby -v UWSGICONFIG_RUBYPATH=ruby /usr/bin/python uwsgiconfig.py --plugin plugins/rack base rack${{ matrix.rack-version }} - name: run smoke tests run: | ./tests/gh-rack.sh rack${{ matrix.rack-version}} uwsgi-2.0.29/.gitignore000066400000000000000000000003571477626554400147630ustar00rootroot00000000000000*.o *.py[co] *.class *.jar *~ *.so *.gox *.a *.dll *.key *.orig *.rej /uwsgi /uwsgibuild.* /core/config_py.c /t/ring/target /t/spooler/spooldir/uwsgi_* core/dot_h.c +# coverity +/cov-int/ +uwsgi.tar.xz /build/ /dist/ /uWSGI.egg-info/ uwsgi-2.0.29/CONTRIBUTORS000066400000000000000000000015711477626554400146520ustar00rootroot00000000000000- this is a incomplete list of all the contributors of the project - Roberto De Ioris, Unbit, Riccardo Magliocchetti Yann Malet, Lincoln Loop Simon Litchfield Masahiro Honma, Łukasz Wróblewski Giacomo Bagnoli, Asidev Guido Notari, Link I.T. S.p.a. Marco Beri, Link I.T. S.p.a. Leonid Borisenko Cal Leeming, Simplicity Media Ltd Luigi Scarso Corey Farwell Charles Duffy Lukas Lalinsky Steven Fernandez Łukasz Mierzwa Roy Marples Aarni Koskela C Anthony Risinger Stephen Pierce Mingli Yuan Natanael Copa Roberto Leandrini Ryan Petrello Danila Shtan Ævar Arnfjörð Bjarmason Yu Zhao (getcwd) Mathieu Dupuy Adriano Di Luzio (adriano@unbit.it) Curtis Maloney Vladimir Didenko Alexandre Bonnetain Darvame Hleran Sokolov Yura Marcin Lulek Derzsi Dániel uwsgi-2.0.29/INSTALL000066400000000000000000000000001477626554400140050ustar00rootroot00000000000000uwsgi-2.0.29/LICENSE000066400000000000000000000443041477626554400140000ustar00rootroot00000000000000---------------------------------------------------------------------- LINKING EXCEPTION In addition to the permissions in the GNU General Public License, the authors give you unlimited permission to link the compiled version of this library into combinations with other programs, and to distribute those combinations without any restriction coming from the use of this file. (The General Public License restrictions do apply in other respects; for example, they cover modification of the file, and distribution when not linked into a combined executable.) ---------------------------------------------------------------------- GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. uwsgi-2.0.29/Makefile000066400000000000000000000006551477626554400144340ustar00rootroot00000000000000PYTHON := python3 all: $(PYTHON) uwsgiconfig.py --build $(PROFILE) clean: $(PYTHON) uwsgiconfig.py --clean cd unittest && make clean check: $(PYTHON) uwsgiconfig.py --check plugin.%: $(PYTHON) uwsgiconfig.py --plugin plugins/$* $(PROFILE) unittests: $(PYTHON) uwsgiconfig.py --build unittest cd unittest && make test tests: $(PYTHON) t/runner %: $(PYTHON) uwsgiconfig.py --build $@ .PHONY: all clean check tests uwsgi-2.0.29/PKG-INFO000066400000000000000000000003431477626554400140630ustar00rootroot00000000000000Metadata-Version: 1.0 Name: uWSGI Version: 2.0.29 Summary: The uWSGI server Home-page: https://uwsgi-docs.readthedocs.io/en/latest/ Author: Unbit Author-email: info@unbit.it License: GPL2 Description: UNKNOWN Platform: UNKNOWN uwsgi-2.0.29/README000066400000000000000000000005351477626554400136510ustar00rootroot00000000000000The uWSGI project For official documentation check: https://uwsgi-docs.readthedocs.io/en/latest/ Note: The project is in maintenance mode (only bugfixes and updates for new languages apis) uWSGI development has been sponsored by: http://unbit.com https://www.pythonanywhere.com/ https://lincolnloop.com/ https://yourlabs.io/oss https://fili.com uwsgi-2.0.29/apache2/000077500000000000000000000000001477626554400142715ustar00rootroot00000000000000uwsgi-2.0.29/apache2/mod_Ruwsgi.c000066400000000000000000000602351477626554400165620ustar00rootroot00000000000000/* *** uWSGI/mod_Ruwsgi *** Copyright 2009-2010 Roger Florkowski Copyright 2009-2010 Unbit S.a.s. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #define MOD_UWSGI_VERSION "1.0" #include "ap_config.h" #include "apr_version.h" #include "apr_lib.h" #include "apr_strings.h" #include "httpd.h" #include "http_core.h" #include "http_request.h" #include "http_config.h" #include "http_log.h" #include "http_protocol.h" #include "util_script.h" #include #include #include #include #include #include #define DEFAULT_TIMEOUT 60 /* default socket timeout */ #define DEFAULT_CGIMODE 0 /* not enabled */ #define UNSET 0 #define ENABLED 1 #define DISABLED 2 #if APR_MAJOR_VERSION == 0 #define apr_socket_send apr_send #define GET_PORT(port, addr) apr_sockaddr_port_get(&(port), addr) #define CREATE_SOCKET(sock, family, pool) \ apr_socket_create(sock, family, SOCK_STREAM, pool) #else #define GET_PORT(port, addr) ((port) = (addr)->port) #define CREATE_SOCKET(sock, family, pool) \ apr_socket_create(sock, family, SOCK_STREAM, APR_PROTO_TCP, pool) #endif typedef struct { char *path; char *addr; apr_port_t port; } mount_entry; /* * Configuration record. Used per-directory configuration data. */ typedef struct { mount_entry mount; int enabled; /* mod_uwsgi is enabled from this directory */ int timeout; int cgi_mode; uint8_t modifier1; uint8_t modifier2; } uwsgi_cfg; /* Server level configuration */ typedef struct { apr_array_header_t *mounts; int timeout; int cgi_mode; } uwsgi_server_cfg; module AP_MODULE_DECLARE_DATA uwsgi_module; /* * Locate our directory configuration record for the current request. */ static uwsgi_cfg * our_dconfig(request_rec *r) { return (uwsgi_cfg *) ap_get_module_config(r->per_dir_config, &uwsgi_module); } static uwsgi_server_cfg *our_sconfig(server_rec *s) { return (uwsgi_server_cfg *) ap_get_module_config(s->module_config, &uwsgi_module); } static int mount_entry_matches(const char *url, const char *prefix, const char **path_info) { int i; for (i=0; prefix[i] != '\0'; i++) { if (url[i] == '\0' || url[i] != prefix[i]) return 0; } if (url[i] == '\0' || url[i] == '/') { *path_info = url + i; return 1; } return 0; } static int uwsgi_translate(request_rec *r) { uwsgi_cfg *cfg = our_dconfig(r); if (cfg->enabled == DISABLED) { return DECLINED; } if (cfg->mount.addr != UNSET) { ap_assert(cfg->mount.port != UNSET); r->handler = "uwsgi-handler"; r->filename = r->uri; return OK; } else { int i; uwsgi_server_cfg *scfg = our_sconfig(r->server); mount_entry *entries = (mount_entry *) scfg->mounts->elts; for (i = 0; i < scfg->mounts->nelts; ++i) { const char *path_info; mount_entry *mount = &entries[i]; if (mount_entry_matches(r->uri, mount->path, &path_info)) { r->handler = "uwsgi-handler"; r->path_info = apr_pstrdup(r->pool, path_info); r->filename = r->uri; ap_set_module_config(r->request_config, &uwsgi_module, mount); return OK; } } } return DECLINED; } static int uwsgi_map_location(request_rec *r) { if (r->handler && strcmp(r->handler, "uwsgi-handler") == 0) { return OK; /* We don't want directory walk. */ } return DECLINED; } #if AP_MODULE_MAGIC_AT_LEAST(20111130,0) static void log_err(const char *file, int line, int ami, request_rec *r, apr_status_t status, const char *msg) { ap_log_rerror(file, line, APLOG_MODULE_INDEX, APLOG_ERR, status, r, "uwsgi: %s", msg); #else static void log_err(const char *file, int line, request_rec *r, apr_status_t status, const char *msg) { ap_log_rerror(file, line, APLOG_ERR, status, r, "uwsgi: %s", msg); #endif } #if AP_MODULE_MAGIC_AT_LEAST(20111130,0) static void log_debug(const char *file, int line, int ami, request_rec *r, const char *msg) { /* ap_log_rerror(file, line, APLOG_DEBUG, APR_SUCCESS, r, msg); ap_log_rerror(file, line, APLOG_WARNING, APR_SUCCESS, r, "uwsgi: %s", msg); */ ap_log_rerror(file, line, APLOG_MODULE_INDEX, APLOG_DEBUG, APR_SUCCESS, r, "uwsgi: %s", msg); #else static void log_debug(const char *file, int line, request_rec *r, const char *msg) { ap_log_rerror(file, line, APLOG_DEBUG, APR_SUCCESS, r, "uwsgi: %s", msg); #endif } /* buffered socket implementation (buckets are overkill) */ #define BUFFER_SIZE 8000 struct sockbuff { apr_socket_t *sock; char buf[BUFFER_SIZE]; int used; }; static void binit(struct sockbuff *s, apr_socket_t *sock) { s->sock = sock; s->used = 0; } static apr_status_t sendall(apr_socket_t *sock, char *buf, apr_size_t len) { apr_status_t rv; apr_size_t n; while (len > 0) { n = len; if ((rv = apr_socket_send(sock, buf, &n))) return rv; buf += n; len -= n; } return APR_SUCCESS; } static apr_status_t bflush(struct sockbuff *s) { apr_status_t rv; ap_assert(s->used >= 0 && s->used <= BUFFER_SIZE); if (s->used) { if ((rv = sendall(s->sock, s->buf, s->used))) return rv; s->used = 0; } return APR_SUCCESS; } static apr_status_t bwrite(struct sockbuff *s, char *buf, apr_size_t len) { apr_status_t rv; if (len >= BUFFER_SIZE - s->used) { if ((rv = bflush(s))) return rv; while (len >= BUFFER_SIZE) { if ((rv = sendall(s->sock, buf, BUFFER_SIZE))) return rv; buf += BUFFER_SIZE; len -= BUFFER_SIZE; } } if (len > 0) { ap_assert(len < BUFFER_SIZE - s->used); memcpy(s->buf + s->used, buf, len); s->used += len; } return APR_SUCCESS; } static apr_status_t bputs(struct sockbuff *s, char *buf) { return bwrite(s, buf, strlen(buf)); } static apr_status_t bputc(struct sockbuff *s, char c) { char buf[1]; buf[0] = c; return bwrite(s, buf, 1); } static apr_status_t bputh(struct sockbuff *s, unsigned short h) { return bwrite(s, (char *)&h, 2); } #define CONFIG_VALUE(value, fallback) ((value) != UNSET ? (value) : (fallback)) static apr_status_t open_socket(apr_socket_t **sock, request_rec *r) { int timeout; int retries = 4; int sleeptime = 1; apr_status_t rv; apr_sockaddr_t *sockaddr; uwsgi_server_cfg *scfg = our_sconfig(r->server); uwsgi_cfg *cfg = our_dconfig(r); mount_entry *m = (mount_entry *) ap_get_module_config(r->request_config, &uwsgi_module); if (!m) { m = &cfg->mount; } timeout = CONFIG_VALUE(cfg->timeout, CONFIG_VALUE(scfg->timeout, DEFAULT_TIMEOUT)); rv = apr_sockaddr_info_get(&sockaddr, CONFIG_VALUE(m->addr, "localhost"), APR_UNSPEC, CONFIG_VALUE(m->port, 5000), 0, r->pool); if (rv) { log_err(APLOG_MARK, r, rv, "apr_sockaddr_info_get() error"); return rv; } restart: *sock = NULL; rv = CREATE_SOCKET(sock, sockaddr->family, r->pool); if (rv) { log_err(APLOG_MARK, r, rv, "apr_socket_create() error"); return rv; } rv = apr_socket_timeout_set(*sock, apr_time_from_sec(timeout)); if (rv) { log_err(APLOG_MARK, r, rv, "apr_socket_timeout_set() error"); return rv; } rv = apr_socket_connect(*sock, sockaddr); if (rv) { apr_socket_close(*sock); if ((APR_STATUS_IS_ECONNREFUSED(rv) | APR_STATUS_IS_EINPROGRESS(rv)) && retries > 0) { /* server may be temporarily down, retry */ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, rv, r, "uwsgi: connection failed, retrying"); apr_sleep(apr_time_from_sec(sleeptime)); --retries; sleeptime *= 2; goto restart; } log_err(APLOG_MARK, r, rv, "uwsgi: can't connect to server"); return rv; } #ifdef APR_TCP_NODELAY /* disable Nagle, we don't send small packets */ apr_socket_opt_set(*sock, APR_TCP_NODELAY, 1); #endif return APR_SUCCESS; } /* This code is a duplicate of what's in util_script.c. We can't use * r->unparsed_uri because it gets changed if there was a redirect. */ static char *original_uri(request_rec *r) { char *first, *last; if (r->the_request == NULL) { return (char *) apr_pcalloc(r->pool, 1); } first = r->the_request; /* use the request-line */ while (*first && !apr_isspace(*first)) { ++first; /* skip over the method */ } while (apr_isspace(*first)) { ++first; /* and the space(s) */ } last = first; while (*last && !apr_isspace(*last)) { ++last; /* end at next whitespace */ } return apr_pstrmemdup(r->pool, first, last - first); } static char *lookup_name(apr_table_t *t, const char *name) { const apr_array_header_t *hdrs_arr = apr_table_elts(t); apr_table_entry_t *hdrs = (apr_table_entry_t *) hdrs_arr->elts; int i; for (i = 0; i < hdrs_arr->nelts; ++i) { if (hdrs[i].key == NULL) continue; if (strcasecmp(hdrs[i].key, name) == 0) return hdrs[i].val; } return NULL; } static char *lookup_header(request_rec *r, const char *name) { return lookup_name(r->headers_in, name); } static void add_header(apr_table_t *t, const char *name, const char *value) { if (name != NULL && value != NULL) apr_table_addn(t, name, value); } static int find_path_info(const char *uri, const char *path_info) { int n; n = strlen(uri) - strlen(path_info); ap_assert(n >= 0); return n; } static char *http2env(apr_pool_t *p, const char *name) { char *env_name = apr_pstrcat(p, "HTTP_", name, NULL); char *cp; for (cp = env_name + 5; *cp != 0; cp++) { if (*cp == '-') { *cp = '_'; } else { *cp = apr_toupper(*cp); } } return env_name; } static apr_status_t send_headers(request_rec *r, struct sockbuff *s) { int i; const apr_array_header_t *hdrs_arr, *env_arr; apr_table_entry_t *hdrs, *env; char *buf; unsigned short int n = 0; apr_table_t *t; apr_status_t rv = 0; apr_port_t port = 0; #if AP_MODULE_MAGIC_AT_LEAST(20111130,0) GET_PORT(port, r->useragent_addr); #else GET_PORT(port, r->connection->remote_addr); #endif uwsgi_cfg *cfg = our_dconfig(r); log_debug(APLOG_MARK,r, "sending headers"); t = apr_table_make(r->pool, 40); if (!t) return APR_ENOMEM; /* headers to send */ /* CONTENT_LENGTH must come first and always be present */ buf = lookup_header(r, "Content-Length"); if (buf == NULL) buf = "0"; add_header(t, "CONTENT_LENGTH", buf); add_header(t, "REQUEST_METHOD", (char *) r->method); add_header(t, "QUERY_STRING", r->args ? r->args : ""); #if AP_MODULE_MAGIC_AT_LEAST(20111130,0) add_header(t, "SERVER_SOFTWARE", ap_get_server_description()); #else add_header(t, "SERVER_SOFTWARE", ap_get_server_version()); #endif add_header(t, "SERVER_ADMIN", r->server->server_admin); add_header(t, "SERVER_NAME", (char *) ap_get_server_name(r)); add_header(t, "SERVER_PORT", apr_psprintf(r->pool, "%u",ap_get_server_port(r))); add_header(t, "SERVER_ADDR", r->connection->local_ip); add_header(t, "SERVER_PROTOCOL", r->protocol); add_header(t, "REQUEST_URI", original_uri(r)); #if AP_MODULE_MAGIC_AT_LEAST(20111130,0) add_header(t, "REMOTE_ADDR", r->useragent_ip); #else add_header(t, "REMOTE_ADDR", r->connection->remote_ip); #endif add_header(t, "REMOTE_PORT", apr_psprintf(r->pool, "%d", port)); add_header(t, "REMOTE_USER", r->user); add_header(t, "DOCUMENT_ROOT", (char *) ap_document_root(r)); if (r->path_info) { int path_info_start = find_path_info(r->uri, r->path_info); add_header(t, "SCRIPT_NAME", apr_pstrndup(r->pool, r->uri, path_info_start)); add_header(t, "PATH_INFO", r->path_info); } else { /* skip PATH_INFO, don't know it */ add_header(t, "SCRIPT_NAME", r->uri); } add_header(t, "CONTENT_TYPE", lookup_header(r, "Content-type")); /* HTTP headers */ hdrs_arr = apr_table_elts(r->headers_in); hdrs = (apr_table_entry_t *) hdrs_arr->elts; for (i = 0; i < hdrs_arr->nelts; ++i) { if (hdrs[i].key) { add_header(t, http2env(r->pool, hdrs[i].key), hdrs[i].val); } } /* environment variables */ env_arr = apr_table_elts(r->subprocess_env); env = (apr_table_entry_t*) env_arr->elts; for (i = 0; i < env_arr->nelts; ++i) { add_header(t, env[i].key, env[i].val); } hdrs_arr = apr_table_elts(t); hdrs = (apr_table_entry_t*) hdrs_arr->elts; /* calculate length of header data */ for (i = 0; i < hdrs_arr->nelts; ++i) { n += strlen(hdrs[i].key); n += strlen(hdrs[i].val); n += 4; /* XXX */ } log_debug(APLOG_MARK,r, apr_psprintf(r->pool, "pktheader size is %u", n)); log_debug(APLOG_MARK,r, apr_psprintf(r->pool, "num headers %u", hdrs_arr->nelts)); /* write pkt header */ rv = bputc(s, cfg->modifier1); /* marker */ if (rv) return rv; rv = bputh(s, n); /* length of header data */ if (rv) return rv; rv = bputc(s, cfg->modifier2); /* marker */ if (rv) return rv; /* write out headers */ for (i = 0; i < hdrs_arr->nelts; ++i) { rv = bputh(s, strlen(hdrs[i].key)); /* length */ if (rv) return rv; rv = bputs(s, hdrs[i].key); /* key */ if (rv) return rv; rv = bputh(s, strlen(hdrs[i].val)); /* length */ if (rv) return rv; rv = bputs(s, hdrs[i].val); /* data */ if (rv) return rv; } return APR_SUCCESS; } static apr_status_t send_request_body(request_rec *r, struct sockbuff *s) { if (ap_should_client_block(r)) { char buf[BUFFER_SIZE]; apr_status_t rv; apr_off_t len; while ((len = ap_get_client_block(r, buf, sizeof buf)) > 0) { if ((rv = bwrite(s, buf, len))) return rv; } if (len == -1) return HTTP_INTERNAL_SERVER_ERROR; /* what to return? */ } return APR_SUCCESS; } static int uwsgi_handler(request_rec *r) { apr_status_t rv = 0; int cgi_mode, http_status = 0; struct sockbuff s; apr_socket_t *sock; apr_bucket_brigade *bb = NULL; apr_bucket *b = NULL; const char *location; uwsgi_cfg *cfg = our_dconfig(r); uwsgi_server_cfg *scfg = our_sconfig(r->server); if (strcmp(r->handler, "uwsgi-handler")) return DECLINED; http_status = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR); if (http_status != OK) return http_status; log_debug(APLOG_MARK, r, "connecting to server"); rv = open_socket(&sock, r); if (rv) { return HTTP_INTERNAL_SERVER_ERROR; } binit(&s, sock); rv = send_headers(r, &s); if (rv) { log_err(APLOG_MARK, r, rv, "error sending request headers"); return HTTP_INTERNAL_SERVER_ERROR; } rv = send_request_body(r, &s); if (rv) { log_err(APLOG_MARK, r, rv, "error sending request body"); return HTTP_INTERNAL_SERVER_ERROR; } rv = bflush(&s); if (rv) { log_err(APLOG_MARK, r, rv, "error sending request"); return HTTP_INTERNAL_SERVER_ERROR; } log_debug(APLOG_MARK, r, "reading response headers"); bb = apr_brigade_create(r->connection->pool, r->connection->bucket_alloc); cgi_mode = CONFIG_VALUE(cfg->cgi_mode, CONFIG_VALUE(scfg->cgi_mode, DEFAULT_CGIMODE)); if (!cgi_mode) { /* receive implemented with http-0.9 based protocol */ apr_interval_time_t timeout; char buf[4096]; apr_pollfd_t pollfd = {r->pool, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, NULL }; pollfd.desc.s = sock; timeout = CONFIG_VALUE(cfg->timeout, CONFIG_VALUE(scfg->timeout, DEFAULT_TIMEOUT)) * 1000 * 1000; r->assbackwards = 1; /* XXX */ for(;;) { apr_int32_t nsds; apr_size_t len; if ((rv = apr_poll(&pollfd, 1, &nsds, timeout)) == APR_TIMEUP) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: recv() timeout"); break; } if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: poll() %s", strerror(errno)); break; } len = 4096; rv = apr_socket_recv(sock, buf, &len); if (rv == APR_SUCCESS) { apr_brigade_write(bb, NULL, NULL, buf, len); } else if (rv == APR_EOF) { break; } else { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: recv() %s", strerror(errno)); } } log_debug(APLOG_MARK,r, "recv finished"); b = apr_bucket_flush_create(r->connection->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); b = apr_bucket_eos_create(r->connection->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); } else { /* receive implemented with http-1.x based protocol */ b = apr_bucket_socket_create(sock, r->connection->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); b = apr_bucket_eos_create(r->connection->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); rv = ap_scan_script_header_err_brigade(r, bb, NULL); if (rv) { if (rv == HTTP_INTERNAL_SERVER_ERROR) { log_err(APLOG_MARK, r, rv, "error reading response headers"); } else { /* Work around an Apache bug whereby the returned status is * ignored and status_line is used instead. This bug is * present at least in 2.0.54. */ r->status_line = NULL; } apr_brigade_destroy(bb); return rv; } location = apr_table_get(r->headers_out, "Location"); if (location && location[0] == '/' && ((r->status == HTTP_OK) || ap_is_HTTP_REDIRECT(r->status))) { apr_brigade_destroy(bb); /* Internal redirect -- fake-up a pseudo-request */ r->status = HTTP_OK; /* This redirect needs to be a GET no matter what the original * method was. */ r->method = apr_pstrdup(r->pool, "GET"); r->method_number = M_GET; ap_internal_redirect_handler(location, r); return OK; } } rv = ap_pass_brigade(r->output_filters, bb); if (rv) { log_err(APLOG_MARK, r, rv, "ap_pass_brigade()"); return HTTP_INTERNAL_SERVER_ERROR; } return OK; } static int uwsgi_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *base_server) { ap_add_version_component(p, "mod_uwsgi/" MOD_UWSGI_VERSION); return OK; } static void * uwsgi_create_dir_config(apr_pool_t *p, char *dirspec) { uwsgi_cfg *cfg = apr_pcalloc(p, sizeof(uwsgi_cfg)); cfg->enabled = UNSET; cfg->mount.addr = UNSET; cfg->mount.port = UNSET; cfg->timeout = UNSET; cfg->cgi_mode = UNSET; cfg->modifier1 = UNSET; cfg->modifier2 = UNSET; return cfg; } #define MERGE(b, n, a) (n->a == UNSET ? b->a : n->a) static void * uwsgi_merge_dir_config(apr_pool_t *p, void *basev, void *newv) { uwsgi_cfg* cfg = apr_pcalloc(p, sizeof(uwsgi_cfg)); uwsgi_cfg* base = basev; uwsgi_cfg* new = newv; cfg->enabled = MERGE(base, new, enabled); cfg->mount.addr = MERGE(base, new, mount.addr); cfg->mount.port = MERGE(base, new, mount.port); cfg->timeout = MERGE(base, new, timeout); cfg->cgi_mode = MERGE(base, new, cgi_mode); cfg->modifier1 = MERGE(base, new, modifier1); cfg->modifier2 = MERGE(base, new, modifier2); return cfg; } static void * uwsgi_create_server_config(apr_pool_t *p, server_rec *s) { uwsgi_server_cfg *c = (uwsgi_server_cfg *) apr_pcalloc(p, sizeof(uwsgi_server_cfg)); c->mounts = apr_array_make(p, 20, sizeof(mount_entry)); c->timeout = UNSET; c->cgi_mode = UNSET; return c; } static void * uwsgi_merge_server_config(apr_pool_t *p, void *basev, void *overridesv) { uwsgi_server_cfg *c = (uwsgi_server_cfg *) apr_pcalloc(p, sizeof(uwsgi_server_cfg)); uwsgi_server_cfg *base = (uwsgi_server_cfg *) basev; uwsgi_server_cfg *overrides = (uwsgi_server_cfg *) overridesv; c->mounts = apr_array_append(p, overrides->mounts, base->mounts); c->timeout = MERGE(base, overrides, timeout); c->cgi_mode = MERGE(base, overrides, cgi_mode); return c; } static const char * cmd_uwsgi_mount(cmd_parms *cmd, void *dummy, const char *path, const char *addr) { int n; apr_status_t rv; char *scope_id = NULL; /* A ip6 parameter - not used here. */ uwsgi_server_cfg *scfg = our_sconfig(cmd->server); mount_entry *new = apr_array_push(scfg->mounts); n = strlen(path); while (n > 0 && path[n-1] == '/') { n--; /* strip trailing slashes */ } new->path = apr_pstrndup(cmd->pool, path, n); rv = apr_parse_addr_port(&new->addr, &scope_id, &new->port, addr, cmd->pool); if (rv) return "error parsing address:port string"; return NULL; } static const char * cmd_uwsgi_server(cmd_parms *cmd, void *pcfg, const char *addr_and_port) { apr_status_t rv; uwsgi_cfg *cfg = pcfg; char *scope_id = NULL; /* A ip6 parameter - not used here. */ if (cmd->path == NULL) return "not a server command"; rv = apr_parse_addr_port(&cfg->mount.addr, &scope_id, &cfg->mount.port, addr_and_port, cmd->pool); if (rv) return "error parsing address:port string"; return NULL; } static const char * cmd_uwsgi_handler(cmd_parms* cmd, void* pcfg, int flag) { uwsgi_cfg *cfg = pcfg; if (cmd->path == NULL) /* server command */ return "not a server command"; if (flag) cfg->enabled = ENABLED; else cfg->enabled = DISABLED; return NULL; } static const char * cmd_uwsgi_timeout(cmd_parms *cmd, void* pcfg, const char *strtimeout) { uwsgi_cfg *dcfg = pcfg; int timeout = atoi(strtimeout); if (cmd->path == NULL) { uwsgi_server_cfg *scfg = our_sconfig(cmd->server); scfg->timeout = timeout; } else { dcfg->timeout = timeout; } return NULL; } static const char * cmd_uwsgi_force_cgi_mode(cmd_parms *cmd, void *pcfg, const char *value) { int cgi_mode; if (!strcmp("yes", value) || !strcmp("on", value) || !strcmp("enable", value) || !strcmp("1", value)) { cgi_mode = 1; } else { cgi_mode = 0; } if (cmd->path == NULL) { uwsgi_server_cfg *scfg = our_sconfig(cmd->server); scfg->cgi_mode = cgi_mode; } else { uwsgi_cfg *dcfg = pcfg; dcfg->cgi_mode = cgi_mode; } return NULL; } static const char * cmd_uwsgi_modifier1(cmd_parms *cmd, void *pcfg, const char *value) { uwsgi_cfg *cfg = pcfg; int val; if (cmd->path == NULL) /* server command */ return "not a server command"; val = atoi(value); if (val < 0 || val > 255) { return "ignored uWSGImodifier1. Value must be between 0 and 255"; } else { cfg->modifier1 = (uint8_t) val; } return NULL; } static const char * cmd_uwsgi_modifier2(cmd_parms *cmd, void *pcfg, const char *value) { uwsgi_cfg *cfg = pcfg; int val; if (cmd->path == NULL) /* server command */ return "not a server command"; val = atoi(value); if (val < 0 || val > 255) { return "ignored uWSGImodifier2. Value must be between 0 and 255"; } else { cfg->modifier2 = (uint8_t) val; } return NULL; } static const command_rec uwsgi_cmds[] = { AP_INIT_TAKE2("uWSGImount", cmd_uwsgi_mount, NULL, RSRC_CONF, "path prefix and address of UWSGI server"), AP_INIT_TAKE1("uWSGIserver", cmd_uwsgi_server, NULL, ACCESS_CONF, "Address and port of an UWSGI server (e.g. localhost:4000)"), AP_INIT_FLAG( "uWSGIhandler", cmd_uwsgi_handler, NULL, ACCESS_CONF, "On or Off to enable or disable the UWSGI handler"), AP_INIT_TAKE1("uWSGIserverTimeout", cmd_uwsgi_timeout, NULL, ACCESS_CONF|RSRC_CONF, "Timeout (in seconds) for communication with the UWSGI server."), AP_INIT_TAKE1("uWSGIforceCGImode", cmd_uwsgi_force_cgi_mode, NULL, ACCESS_CONF|RSRC_CONF, "Force uWSGI CGI mode for perfect integration with apache filter"), AP_INIT_TAKE1("uWSGImodifier1", cmd_uwsgi_modifier1, NULL, ACCESS_CONF, "Set uWSGI modifier1"), AP_INIT_TAKE1("uWSGImodifier2", cmd_uwsgi_modifier2, NULL, ACCESS_CONF, "Set uWSGI modifier2"), /* AP_INIT_TAKE12("uWSGIsocket", cmd_uwsgi_socket, NULL, RSRC_CONF|ACCESS_CONF, "Absolute path and optional timeout in seconds of uwsgi server socket"), AP_INIT_TAKE1("uWSGIsocket2", cmd_uwsgi_socket2, NULL, RSRC_CONF|ACCESS_CONF, "Absolute path of failover uwsgi server socket"), AP_INIT_TAKE1("uWSGIforceScriptName", cmd_uwsgi_force_script_name, NULL, ACCESS_CONF, "Fix for PATH_INFO/SCRIPT_NAME when the location has filesystem correspondence"), */ {NULL} }; static void uwsgi_register_hooks(apr_pool_t *p) { ap_hook_post_config(uwsgi_init, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_handler(uwsgi_handler, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_translate_name(uwsgi_translate, NULL, NULL, APR_HOOK_LAST); ap_hook_map_to_storage(uwsgi_map_location, NULL, NULL, APR_HOOK_FIRST); } /* Dispatch list for API hooks */ module AP_MODULE_DECLARE_DATA uwsgi_module = { STANDARD20_MODULE_STUFF, uwsgi_create_dir_config, /* create per-dir config structs */ uwsgi_merge_dir_config, /* merge per-dir config structs */ uwsgi_create_server_config, /* create per-server config structs */ uwsgi_merge_server_config, /* merge per-server config structs */ uwsgi_cmds, /* table of config file commands */ uwsgi_register_hooks, /* register hooks */ }; uwsgi-2.0.29/apache2/mod_proxy_uwsgi.c000066400000000000000000000405511477626554400177000ustar00rootroot00000000000000/* *** mod_proxy_uwsgi *** Copyright 2009-2017 Unbit S.a.s. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. To build: apxs2 -i -c mod_proxy_uwsgi.c To use: LoadModule proxy_uwsgi_module /usr/lib/apache2/modules/mod_proxy_uwsgi.so ProxyPass / uwsgi://127.0.0.1:3031/ Docs: http://uwsgi-docs.readthedocs.org/en/latest/Apache.html#mod-proxy-uwsgi */ #define APR_WANT_MEMFUNC #define APR_WANT_STRFUNC #include "apr_strings.h" #include "apr_hooks.h" #include "apr_optional_hooks.h" #include "apr_buckets.h" #include "httpd.h" #include "http_config.h" #include "http_log.h" #include "http_protocol.h" #include "http_request.h" #include "util_script.h" #include "mod_proxy.h" #define UWSGI_SCHEME "uwsgi" #define UWSGI_DEFAULT_PORT 3031 module AP_MODULE_DECLARE_DATA proxy_uwsgi_module; static int uwsgi_canon(request_rec *r, char *url) { char *host, sport[sizeof(":65535")]; const char *err, *path; apr_port_t port = UWSGI_DEFAULT_PORT; if (strncasecmp(url, UWSGI_SCHEME "://", sizeof(UWSGI_SCHEME) + 2)) { return DECLINED; } url += sizeof(UWSGI_SCHEME); /* Keep slashes */ err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port); if (err) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "error parsing URL %s: %s", url, err); return HTTP_BAD_REQUEST; } if (port != UWSGI_DEFAULT_PORT) apr_snprintf(sport, sizeof(sport), ":%u", port); else sport[0] = '\0'; if (ap_strchr(host, ':')) { /* if literal IPv6 address */ host = apr_pstrcat(r->pool, "[", host, "]", NULL); } path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0, r->proxyreq); if (!path) { return HTTP_BAD_REQUEST; } r->filename = apr_pstrcat(r->pool, "proxy:" UWSGI_SCHEME "://", host, sport, "/", path, NULL); return OK; } static int uwsgi_send(proxy_conn_rec *conn, const char *buf, apr_size_t length, request_rec *r) { apr_status_t rv; apr_size_t written; while (length > 0) { written = length; if ((rv = apr_socket_send(conn->sock, buf, &written)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "sending data to %s:%u failed", conn->hostname, conn->port); return HTTP_SERVICE_UNAVAILABLE; } /* count for stats */ conn->worker->s->transferred += written; buf += written; length -= written; } return OK; } /* * Send uwsgi header block */ static int uwsgi_send_headers(request_rec *r, proxy_conn_rec *conn) { char *buf, *ptr; const apr_array_header_t *env_table; const apr_table_entry_t *env; int j; apr_size_t headerlen = 4; uint16_t pktsize, keylen, vallen; ap_add_common_vars(r); ap_add_cgi_vars(r); // this is not a security problem (in Linux) as uWSGI destroy the env memory area readable in /proc // and generally if you host untrusted apps in your server and allows them to read others uid /proc/ // files you have higher problems... const char *auth = apr_table_get(r->headers_in, "Authorization"); if (auth) { apr_table_setn(r->subprocess_env, "HTTP_AUTHORIZATION", auth); } const char *script_name = apr_table_get(r->subprocess_env, "SCRIPT_NAME"); const char *path_info = apr_table_get(r->subprocess_env, "PATH_INFO"); if (script_name && path_info) { if (strcmp(path_info, "/")) { apr_table_set(r->subprocess_env, "SCRIPT_NAME", apr_pstrndup(r->pool, script_name, strlen(script_name)-strlen(path_info))); } else { if (!strcmp(script_name, "/")) { apr_table_set(r->subprocess_env, "SCRIPT_NAME", ""); } } } env_table = apr_table_elts(r->subprocess_env); env = (apr_table_entry_t *)env_table->elts; for (j = 0; j < env_table->nelts; ++j) { headerlen += 2 + strlen(env[j].key) + 2 + strlen(env[j].val) ; } ptr = buf = apr_palloc(r->pool, headerlen); ptr+=4; for (j = 0; j < env_table->nelts; ++j) { keylen = strlen(env[j].key); *ptr++= (uint8_t) (keylen & 0xff); *ptr++= (uint8_t) ((keylen >> 8) & 0xff); memcpy(ptr, env[j].key, keylen) ; ptr+=keylen; vallen = strlen(env[j].val); *ptr++= (uint8_t) (vallen & 0xff); *ptr++= (uint8_t) ((vallen >> 8) & 0xff); memcpy(ptr, env[j].val, vallen) ; ptr+=vallen; } pktsize = headerlen-4; buf[0] = 0; buf[1] = (uint8_t) (pktsize & 0xff); buf[2] = (uint8_t) ((pktsize >> 8) & 0xff); buf[3] = 0; return uwsgi_send(conn, buf, headerlen, r); } static int uwsgi_send_body(request_rec *r, proxy_conn_rec *conn) { if (ap_should_client_block(r)) { char *buf = apr_palloc(r->pool, AP_IOBUFSIZE); int status; apr_size_t readlen; readlen = ap_get_client_block(r, buf, AP_IOBUFSIZE); while (readlen > 0) { status = uwsgi_send(conn, buf, readlen, r); if (status != OK) { return HTTP_SERVICE_UNAVAILABLE; } readlen = ap_get_client_block(r, buf, AP_IOBUFSIZE); } if (readlen == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "receiving request body failed"); return HTTP_INTERNAL_SERVER_ERROR; } } return OK; } #if AP_MODULE_MAGIC_AT_LEAST(20111130,0) static request_rec *ap_proxy_make_fake_req(conn_rec *c, request_rec *r) { apr_pool_t *pool; request_rec *rp; apr_pool_create(&pool, c->pool); rp = apr_pcalloc(pool, sizeof(*r)); rp->pool = pool; rp->status = HTTP_OK; rp->headers_in = apr_table_make(pool, 50); rp->subprocess_env = apr_table_make(pool, 50); rp->headers_out = apr_table_make(pool, 12); rp->err_headers_out = apr_table_make(pool, 5); rp->notes = apr_table_make(pool, 5); rp->server = r->server; rp->log = r->log; rp->proxyreq = r->proxyreq; rp->request_time = r->request_time; rp->connection = c; rp->output_filters = c->output_filters; rp->input_filters = c->input_filters; rp->proto_output_filters = c->output_filters; rp->proto_input_filters = c->input_filters; rp->useragent_ip = c->client_ip; rp->useragent_addr = c->client_addr; rp->request_config = ap_create_request_config(pool); proxy_run_create_req(r, rp); return rp; } apr_status_t ap_proxy_buckets_lifetime_transform(request_rec *r, apr_bucket_brigade *from, apr_bucket_brigade *to) { apr_bucket *e; apr_bucket *new; const char *data; apr_size_t bytes; apr_status_t rv = APR_SUCCESS; apr_brigade_cleanup(to); for (e = APR_BRIGADE_FIRST(from); e != APR_BRIGADE_SENTINEL(from); e = APR_BUCKET_NEXT(e)) { if (!APR_BUCKET_IS_METADATA(e)) { apr_bucket_read(e, &data, &bytes, APR_BLOCK_READ); new = apr_bucket_transient_create(data, bytes, r->connection->bucket_alloc); APR_BRIGADE_INSERT_TAIL(to, new); } else if (APR_BUCKET_IS_FLUSH(e)) { new = apr_bucket_flush_create(r->connection->bucket_alloc); APR_BRIGADE_INSERT_TAIL(to, new); } else if (APR_BUCKET_IS_EOS(e)) { new = apr_bucket_eos_create(r->connection->bucket_alloc); APR_BRIGADE_INSERT_TAIL(to, new); } else { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00964) "Unhandled bucket type of type %s in" " proxy_buckets_lifetime_transform", e->type->name); apr_bucket_delete(e); rv = APR_EGENERAL; } } return rv; } #endif static int uwsgi_response(request_rec *r, proxy_conn_rec *backend, proxy_server_conf *conf) { char buffer[HUGE_STRING_LEN]; const char *buf; char *value, *end; int len; int backend_broke = 0; apr_status_t rc; conn_rec *c = r->connection; apr_off_t readbytes; apr_status_t rv; apr_bucket *e; apr_read_type_e mode = APR_NONBLOCK_READ; request_rec *rp = ap_proxy_make_fake_req(backend->connection, r); rp->proxyreq = PROXYREQ_RESPONSE; apr_bucket_brigade *bb = apr_brigade_create(r->pool, c->bucket_alloc); apr_bucket_brigade *pass_bb = apr_brigade_create(r->pool, c->bucket_alloc); len = ap_getline(buffer, sizeof(buffer), rp, 1); if (len <= 0) { /* invalid or empty */ return HTTP_INTERNAL_SERVER_ERROR; } backend->worker->s->read += len; if ((apr_size_t)len >= sizeof(buffer)) { /* too long */ return HTTP_INTERNAL_SERVER_ERROR; } /* Position of http status code */ int status_start; if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) { status_start = 9; } else if (apr_date_checkmask(buffer, "HTTP/# ###*")) { status_start = 7; } else { /* not HTTP */ return HTTP_BAD_GATEWAY; } int status_end = status_start + 3; char keepchar = buffer[status_end]; buffer[status_end] = '\0'; r->status = atoi(&buffer[status_start]); if (keepchar != '\0') { buffer[status_end] = keepchar; } else { /* 2616 requires the space in Status-Line; the origin * server may have sent one but ap_rgetline_core will * have stripped it. */ buffer[status_end] = ' '; buffer[status_end+1] = '\0'; } r->status_line = apr_pstrdup(r->pool, &buffer[status_start]); /* parse headers */ while ((len = ap_getline(buffer, sizeof(buffer), rp, 1)) > 0) { if ((apr_size_t)len >= sizeof(buffer)) { /* too long */ len = -1; break; } value = strchr(buffer, ':'); if (!value) { /* invalid header */ len = -1; break; } *value++ = '\0'; if (*ap_scan_http_token(buffer)) { /* invalid name */ len = -1; break; } while (apr_isspace(*value)) ++value; for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); --end) *end = '\0'; if (*ap_scan_http_field_content(value)) { /* invalid value */ len = -1; break; } apr_table_add(r->headers_out, buffer, value); } if (len < 0) { /* Reset headers, but not to NULL because things below the chain expect * this to be non NULL e.g. the ap_content_length_filter. */ r->headers_out = apr_table_make(r->pool, 1); return HTTP_BAD_GATEWAY; } /* T-E wins over C-L */ if (apr_table_get(r->headers_out, "Transfer-Encoding")) { apr_table_unset(r->headers_out, "Content-Length"); backend->close = 1; } if ((buf = apr_table_get(r->headers_out, "Content-Type"))) { ap_set_content_type(r, apr_pstrdup(r->pool, buf)); } // honor ProxyErrorOverride and ErrorDocument #if AP_MODULE_MAGIC_AT_LEAST(20101106,0) proxy_dir_conf *dconf = ap_get_module_config(r->per_dir_config, &proxy_module); if (dconf->error_override && ap_is_HTTP_ERROR(r->status)) { #else if (conf->error_override && ap_is_HTTP_ERROR(r->status)) { #endif int status = r->status; r->status = HTTP_OK; r->status_line = NULL; apr_brigade_cleanup(bb); apr_brigade_cleanup(pass_bb); return status; } int finish = 0; while(!finish) { rv = ap_get_brigade(rp->input_filters, bb, AP_MODE_READBYTES, mode, conf->io_buffer_size); if (APR_STATUS_IS_EAGAIN(rv) || (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb)) ) { e = apr_bucket_flush_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, e); if (ap_pass_brigade(r->output_filters, bb) || c->aborted) { break; } apr_brigade_cleanup(bb); mode = APR_BLOCK_READ; continue; } else if (rv == APR_EOF) { break; } else if (rv != APR_SUCCESS) { ap_proxy_backend_broke(r, bb); ap_pass_brigade(r->output_filters, bb); backend_broke = 1; break; } mode = APR_NONBLOCK_READ; apr_brigade_length(bb, 0, &readbytes); backend->worker->s->read += readbytes; if (APR_BRIGADE_EMPTY(bb)) { apr_brigade_cleanup(bb); break; } ap_proxy_buckets_lifetime_transform(r, bb, pass_bb); // found the last brigade? if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) finish = 1; // do not pass chunk if it is zero_sized apr_brigade_length(pass_bb, 0, &readbytes); if ((readbytes > 0 && ap_pass_brigade(r->output_filters, pass_bb) != APR_SUCCESS) || c->aborted) { finish = 1; } apr_brigade_cleanup(bb); apr_brigade_cleanup(pass_bb); } e = apr_bucket_eos_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, e); ap_pass_brigade(r->output_filters, bb); apr_brigade_cleanup(bb); if (c->aborted || backend_broke) { return DONE; } return OK; } static int uwsgi_handler(request_rec *r, proxy_worker *worker, proxy_server_conf *conf, char *url, const char *proxyname, apr_port_t proxyport) { int status; proxy_conn_rec *backend = NULL; apr_pool_t *p = r->pool; apr_uri_t *uri = apr_palloc(r->pool, sizeof(*uri)); char server_portstr[32]; if (strncasecmp(url, UWSGI_SCHEME "://", sizeof(UWSGI_SCHEME) + 2)) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "declining URL %s", url); return DECLINED; } // ADD PATH_INFO #if AP_MODULE_MAGIC_AT_LEAST(20111130,0) size_t w_len = strlen(worker->s->name); #else size_t w_len = strlen(worker->name); #endif char *u_path_info = r->filename + 6 + w_len; int delta = 0; if (u_path_info[0] != '/') { delta = 1; } int decode_status = ap_unescape_url(url+w_len-delta); if (decode_status) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unable to decode uri: %s", url+w_len-delta); return HTTP_INTERNAL_SERVER_ERROR; } apr_table_add(r->subprocess_env, "PATH_INFO", url+w_len-delta); /* Create space for state information */ status = ap_proxy_acquire_connection(UWSGI_SCHEME, &backend, worker, r->server); if (status != OK) { goto cleanup; } backend->is_ssl = 0; /* Step One: Determine Who To Connect To */ status = ap_proxy_determine_connection(p, r, conf, worker, backend, uri, &url, proxyname, proxyport, server_portstr, sizeof(server_portstr)); if (status != OK) { goto cleanup; } /* Step Two: Make the Connection */ if (ap_proxy_connect_backend(UWSGI_SCHEME, backend, worker, r->server)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "failed to make connection to backend: %s:%u", backend->hostname, backend->port); status = HTTP_SERVICE_UNAVAILABLE; goto cleanup; } /* Step Three: Create conn_rec */ if (!backend->connection) { if ((status = ap_proxy_connection_create(UWSGI_SCHEME, backend, r->connection, r->server)) != OK) goto cleanup; } /* Step Four: Process the Request */ if ( ((status = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK) || ((status = uwsgi_send_headers(r, backend)) != OK) || ((status = uwsgi_send_body(r, backend)) != OK) || ((status = uwsgi_response(r, backend, conf)) != OK)) { goto cleanup; } cleanup: if (backend) { backend->close = 1; /* always close the socket */ ap_proxy_release_connection(UWSGI_SCHEME, backend, r->server); } return status; } static void register_hooks(apr_pool_t *p) { proxy_hook_scheme_handler(uwsgi_handler, NULL, NULL, APR_HOOK_FIRST); proxy_hook_canon_handler(uwsgi_canon, NULL, NULL, APR_HOOK_FIRST); } module AP_MODULE_DECLARE_DATA proxy_uwsgi_module = { STANDARD20_MODULE_STUFF, NULL, /* create per-directory config structure */ NULL, /* merge per-directory config structures */ NULL, /* create per-server config structure */ NULL, /* merge per-server config structures */ NULL, /* command table */ register_hooks /* register hooks */ }; uwsgi-2.0.29/apache2/mod_uwsgi.c000066400000000000000000000542721477626554400164440ustar00rootroot00000000000000/* *** uWSGI/mod_uwsgi *** Copyright 2009-2014 Unbit S.a.s. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. To compile: (Linux) apxs2 -i -c mod_uwsgi.c (OSX) sudo apxs -i -a -c mod_uwsgi.c (OSX Universal binary) sudo apxs -i -a -c -Wc,"-arch ppc -arch i386 -arch x86_64" -Wl,"-arch ppc -arch i386 -arch x86_64" mod_uwsgi.c Configure: LoadModule uwsgi_module /mod_uwsgi.so SetHandler uwsgi-handler */ #include #include #include "apr_strings.h" #include #include #include #include "httpd.h" #include "http_core.h" #include "http_protocol.h" #include "http_config.h" #include "http_log.h" #include "util_script.h" #include #include #include #include #include #include #define DEFAULT_SOCK "/tmp/uwsgi.sock" typedef struct { union { struct sockaddr x_addr ; struct sockaddr_un u_addr ; struct sockaddr_in i_addr ; } s_addr; int addr_size; union { struct sockaddr x_addr ; struct sockaddr_un u_addr ; struct sockaddr_in i_addr ; } s_addr2; int addr_size2; int socket_timeout; uint8_t modifier1; uint8_t modifier2; char script_name[256]; char scheme[9]; int cgi_mode ; int max_vars; int empty_remote_user; } uwsgi_cfg; module AP_MODULE_DECLARE_DATA uwsgi_module; #if APR_IS_BIGENDIAN static uint16_t uwsgi_swap16(uint16_t x) { return (uint16_t) ((x & 0xff) << 8 | (x & 0xff00) >> 8); } #endif static int uwsgi_add_var(struct iovec *vec, int i, request_rec *r, char *key, char *value, uint16_t *pkt_size) { uwsgi_cfg *c = ap_get_module_config(r->per_dir_config, &uwsgi_module); #if APR_IS_BIGENDIAN if (i+6 > c->max_vars) { #else if (i+4 > c->max_vars) { #endif ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: max number of uwsgi variables reached. consider increasing it with uWSGImaxVars directive"); return i; } #if APR_IS_BIGENDIAN char *ptr; vec[i+2].iov_base = key ; vec[i+2].iov_len = strlen(key) ; #else vec[i+1].iov_base = key ; vec[i+1].iov_len = strlen(key) ; #endif #if APR_IS_BIGENDIAN ptr = (char *) &vec[i+2].iov_len; vec[i].iov_base = ptr+sizeof(long)-1 ; vec[i].iov_len = 1 ; vec[i+1].iov_base = ptr+sizeof(long)-2 ; vec[i+1].iov_len = 1 ; #else vec[i].iov_base = &vec[i+1].iov_len ; vec[i].iov_len = 2 ; #endif #if APR_IS_BIGENDIAN vec[i+5].iov_base = value ; vec[i+5].iov_len = strlen(value) ; #else vec[i+3].iov_base = value ; vec[i+3].iov_len = strlen(value) ; #endif #if APR_IS_BIGENDIAN ptr = (char *) &vec[i+5].iov_len; vec[i+3].iov_base = ptr+sizeof(long)-1 ; vec[i+3].iov_len = 1 ; vec[i+4].iov_base = ptr+sizeof(long)-2 ; vec[i+4].iov_len = 1 ; #else vec[i+2].iov_base = &vec[i+3].iov_len ; vec[i+2].iov_len = 2 ; #endif #if APR_IS_BIGENDIAN *pkt_size+= vec[i+2].iov_len + vec[i+5].iov_len + 4 ; #else *pkt_size+= vec[i+1].iov_len + vec[i+3].iov_len + 4 ; #endif #if APR_IS_BIGENDIAN return i+6; #else return i+4; #endif } static void *uwsgi_server_config(apr_pool_t *p, server_rec *s) { uwsgi_cfg *c = (uwsgi_cfg *) apr_pcalloc(p, sizeof(uwsgi_cfg)); strcpy(c->s_addr.u_addr.sun_path, DEFAULT_SOCK); c->s_addr.u_addr.sun_family = AF_UNIX; c->addr_size = strlen(DEFAULT_SOCK) + ( (void *)&c->s_addr.u_addr.sun_path - (void *)&c->s_addr ) ; c->socket_timeout = 0 ; c->modifier1 = 0 ; c->modifier2 = 0 ; c->cgi_mode = 0 ; c->max_vars = 128; c->script_name[0] = 0; c->empty_remote_user = 1; return c; } static void *uwsgi_dir_config(apr_pool_t *p, char *dir) { uwsgi_cfg *c = (uwsgi_cfg *) apr_pcalloc(p, sizeof(uwsgi_cfg)); strcpy(c->s_addr.u_addr.sun_path, DEFAULT_SOCK); c->s_addr.u_addr.sun_family = AF_UNIX; c->addr_size = strlen(DEFAULT_SOCK) + ( (void *)&c->s_addr.u_addr.sun_path - (void *)&c->s_addr ) ; c->socket_timeout = 0 ; c->modifier1 = 0 ; c->modifier2 = 0 ; c->cgi_mode = 0 ; c->max_vars = 128; c->empty_remote_user = 1; c->script_name[0] = 0; if (dir) { if (strcmp(dir, "/")) { strncpy(c->script_name, dir, 255); } } return c; } static int timed_connect(struct pollfd *fdpoll , struct sockaddr *addr, int addr_size, int timeout, request_rec *r) { int arg, ret; int soopt ; socklen_t solen = sizeof(int) ; int cnt; /* set non-blocking socket */ arg = fcntl(fdpoll->fd, F_GETFL, NULL) ; if (arg < 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: unable to set non-blocking socket: %s", strerror(errno)); return HTTP_INTERNAL_SERVER_ERROR; } arg |= O_NONBLOCK; if (fcntl(fdpoll->fd, F_SETFL, arg) < 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: unable to set non-blocking socket: %s", strerror(errno)); return HTTP_INTERNAL_SERVER_ERROR; } ret = connect(fdpoll->fd, addr, addr_size) ; if (ret < 0) { /* check what happened */ // in progress ? if (errno == EINPROGRESS) { if (timeout < 1) timeout = 3; fdpoll->events = POLLOUT ; cnt = poll(fdpoll, 1, timeout*1000) ; /* check for errors */ if (cnt < 0 && errno != EINTR) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: unable to connect to uWSGI server: %s", strerror(errno)); return HTTP_BAD_GATEWAY; } /* something hapened on the socket ... */ else if (cnt > 0) { if (getsockopt(fdpoll->fd, SOL_SOCKET, SO_ERROR, (void*)(&soopt), &solen) < 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: unable to connect to uWSGI server: %s", strerror(errno)); return HTTP_BAD_GATEWAY; } /* is something bad ? */ if (soopt) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: unable to connect to uWSGI server: %s", strerror(errno)); return HTTP_BAD_GATEWAY; } } /* timeout */ else { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: unable to connect to uWSGI server: connect() timeout"); return HTTP_GATEWAY_TIME_OUT; } } else { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: unable to connect to uWSGI server: %s", strerror(errno)); return HTTP_BAD_GATEWAY; } } /* re-set blocking socket */ arg &= (~O_NONBLOCK); if (fcntl(fdpoll->fd, F_SETFL, arg) < 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: unable to re-set blocking socket: %s", strerror(errno)); return HTTP_INTERNAL_SERVER_ERROR; } return 0 ; } static int uwsgi_handler(request_rec *r) { struct pollfd uwsgi_poll; uwsgi_cfg *c = ap_get_module_config(r->per_dir_config, &uwsgi_module); struct iovec *uwsgi_vars; int vecptr = 1 ; char pkt_header[4]; uint16_t pkt_size = 0; char buf[4096] ; int i ; ssize_t cnt ; const apr_array_header_t *headers; apr_table_entry_t *h; char *penv, *cp; int ret; apr_status_t hret ; apr_bucket *b = NULL; char uwsgi_http_status[13] ; int uwsgi_http_status_read = 0; apr_bucket_brigade *bb; if (strcmp(r->handler, "uwsgi-handler")) return DECLINED; cnt = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR); if (cnt != OK) { return cnt; } if (c == NULL) { c = ap_get_module_config(r->server->module_config, &uwsgi_module); } uwsgi_poll.fd = socket(c->s_addr.x_addr.sa_family, SOCK_STREAM, 0); if (uwsgi_poll.fd < 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: unable to create socket: %s", strerror(errno)); return HTTP_INTERNAL_SERVER_ERROR; } if ( (ret = timed_connect(&uwsgi_poll, (struct sockaddr *) &c->s_addr, c->addr_size, c->socket_timeout, r) ) != 0) { close(uwsgi_poll.fd); if (c->addr_size2 > 0) { uwsgi_poll.fd = socket(c->s_addr2.x_addr.sa_family, SOCK_STREAM, 0); if (uwsgi_poll.fd < 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: unable to create failover socket: %s", strerror(errno)); return HTTP_INTERNAL_SERVER_ERROR; } ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: trying failover server."); if ( (ret = timed_connect(&uwsgi_poll, (struct sockaddr *) &c->s_addr2, c->addr_size2, c->socket_timeout, r)) != 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: failover connect failed."); close(uwsgi_poll.fd); return ret ; } } else { return ret ; } } #if APR_IS_BIGENDIAN uwsgi_vars = malloc(sizeof(struct iovec) * (c->max_vars*6)+1); #else uwsgi_vars = malloc(sizeof(struct iovec) * (c->max_vars*4)+1); #endif vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REQUEST_METHOD", (char *) r->method, &pkt_size) ; vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "QUERY_STRING", r->args ? r->args : "", &pkt_size) ; vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "SERVER_NAME", (char *) ap_get_server_name(r), &pkt_size) ; vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "SERVER_PORT", apr_psprintf(r->pool, "%u",ap_get_server_port(r)), &pkt_size) ; vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "SERVER_PROTOCOL", r->protocol, &pkt_size) ; vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REQUEST_URI", r->unparsed_uri, &pkt_size) ; #if AP_MODULE_MAGIC_AT_LEAST(20111130,0) vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REMOTE_ADDR", r->useragent_ip, &pkt_size) ; #else vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REMOTE_ADDR", r->connection->remote_ip, &pkt_size) ; #endif // if (r->user) { vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REMOTE_USER", r->user, &pkt_size) ; } else if (c->empty_remote_user) { vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "REMOTE_USER", "", &pkt_size) ; } if (ap_auth_type(r) != NULL) { vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "AUTH_TYPE", (char *) ap_auth_type(r), &pkt_size) ; } vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "DOCUMENT_ROOT", (char *) ap_document_root(r), &pkt_size) ; if (c->scheme[0] != 0) { vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "UWSGI_SCHEME", c->scheme, &pkt_size) ; } // SCRIPT_NAME = "/" is like SCRIPT_NAME = "" if (c->script_name[0] != 0 && !(c->script_name[0] == '/' && c->script_name[1] == 0)) { vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "SCRIPT_NAME", c->script_name, &pkt_size) ; vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "PATH_INFO", r->uri+strlen(c->script_name), &pkt_size) ; } else { vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "SCRIPT_NAME", "", &pkt_size) ; vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "PATH_INFO", r->uri, &pkt_size) ; } headers = apr_table_elts(r->headers_in); h = (apr_table_entry_t *) headers->elts; for(i=0;i< headers->nelts;i++) { if (h[i].key){ if (!strcasecmp(h[i].key, "Content-Type")) { vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "CONTENT_TYPE", h[i].val, &pkt_size) ; } else if (!strcasecmp(h[i].key, "Content-Length")) { vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, "CONTENT_LENGTH", h[i].val, &pkt_size) ; } else { penv = apr_pstrcat(r->pool, "HTTP_", h[i].key, NULL); for(cp = penv+5; *cp !=0; cp++) { if (*cp == '-') { *cp = '_'; } else { *cp = toupper(*cp); } } vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, penv, h[i].val, &pkt_size) ; } } } /* environment variables */ headers = apr_table_elts(r->subprocess_env); h = (apr_table_entry_t*) headers->elts; for (i = 0; i < headers->nelts; ++i) { vecptr = uwsgi_add_var(uwsgi_vars, vecptr, r, h[i].key, h[i].val, &pkt_size) ; } uwsgi_vars[0].iov_base = pkt_header; uwsgi_vars[0].iov_len = 4; pkt_header[0] = c->modifier1 ; #if APR_IS_BIGENDIAN pkt_size = uwsgi_swap16(pkt_size); memcpy(pkt_header+1, &pkt_size, 2); pkt_size = uwsgi_swap16(pkt_size); #else memcpy(pkt_header+1, &pkt_size, 2); #endif pkt_header[3] = c->modifier2 ; cnt = writev( uwsgi_poll.fd, uwsgi_vars, vecptr ); if (cnt < 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: writev() %s", strerror(errno)); close(uwsgi_poll.fd); free(uwsgi_vars); return HTTP_INTERNAL_SERVER_ERROR; } else if (cnt != pkt_size+4) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: writev() returned wrong size"); close(uwsgi_poll.fd); free(uwsgi_vars); return HTTP_INTERNAL_SERVER_ERROR; } if (ap_should_client_block(r)) { while ((cnt = ap_get_client_block(r, buf, 4096)) > 0) { cnt = send( uwsgi_poll.fd, buf, cnt, 0); if (cnt < 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: read() client block failed !"); close(uwsgi_poll.fd); free(uwsgi_vars); return HTTP_INTERNAL_SERVER_ERROR; } } } if (!c->cgi_mode) { r->assbackwards = 1 ; uwsgi_http_status[12] = 0 ; } bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); uwsgi_poll.events = POLLIN ; for(;;) { /* put -1 to disable timeout on zero */ cnt = poll(&uwsgi_poll, 1, (c->socket_timeout*1000)-1) ; if (cnt == 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: recv() timeout"); apr_brigade_destroy(bb); free(uwsgi_vars); return HTTP_INTERNAL_SERVER_ERROR; } else if (cnt > 0) { if (uwsgi_poll.revents & POLLIN || uwsgi_poll.revents & POLLHUP) { cnt = recv(uwsgi_poll.fd, buf, 4096, 0) ; if (cnt < 0) { if (errno != ECONNRESET) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: recv() %s", strerror(errno)); apr_brigade_destroy(bb); free(uwsgi_vars); return HTTP_INTERNAL_SERVER_ERROR; } else { break; } } else if (cnt > 0) { if (!c->cgi_mode && uwsgi_http_status_read < 12) { if (uwsgi_http_status_read + cnt >= 12) { memcpy(uwsgi_http_status+uwsgi_http_status_read, buf, 12-uwsgi_http_status_read); r->status = atoi(uwsgi_http_status+8); uwsgi_http_status_read+=cnt; } else { memcpy(uwsgi_http_status+uwsgi_http_status_read, buf, cnt); uwsgi_http_status_read+=cnt; } } // check for client disconnect if (r->connection->aborted) { close(uwsgi_poll.fd); apr_brigade_destroy(bb); free(uwsgi_vars); return HTTP_INTERNAL_SERVER_ERROR; } if (!c->cgi_mode) { b = apr_bucket_transient_create(buf, cnt, r->connection->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); b = apr_bucket_flush_create(r->connection->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS) { close(uwsgi_poll.fd); apr_brigade_destroy(bb); free(uwsgi_vars); return HTTP_INTERNAL_SERVER_ERROR; } apr_brigade_cleanup(bb); } else { apr_brigade_write(bb, NULL, NULL, buf, cnt); } } else { // EOF break; } } // error if (uwsgi_poll.revents & POLLERR || uwsgi_poll.revents & POLLNVAL) { break; } } else { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "uwsgi: poll() %s", strerror(errno)); close(uwsgi_poll.fd); apr_brigade_destroy(bb); free(uwsgi_vars); return HTTP_INTERNAL_SERVER_ERROR; } } close(uwsgi_poll.fd); b = apr_bucket_eos_create(r->connection->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); if (!c->cgi_mode) { if (uwsgi_http_status_read == 0) { free(uwsgi_vars); return HTTP_INTERNAL_SERVER_ERROR; } } else { if (hret = ap_scan_script_header_err_brigade(r, bb, NULL)) { apr_brigade_destroy(bb); free(uwsgi_vars); return hret; } } free(uwsgi_vars); return ap_pass_brigade(r->output_filters, bb) ; } static const char * cmd_uwsgi_force_script_name(cmd_parms *cmd, void *cfg, const char *location) { uwsgi_cfg *c = cfg; if (strlen(location) <= 255 && location[0] == '/') { strcpy(c->script_name, location); } else { return "ignored uWSGIforceScriptName. Invalid location" ; } return NULL ; } static const char * cmd_uwsgi_force_wsgi_scheme(cmd_parms *cmd, void *cfg, const char *scheme) { uwsgi_cfg *c = cfg; if (strlen(scheme) < 9 & strlen(scheme) > 0) { strcpy(c->scheme, scheme); } else { return "ignored uWSGIforceWSGIscheme. Invalid size (max 8 chars)" ; } return NULL ; } static const char *cmd_uwsgi_max_vars(cmd_parms *cmd, void *cfg, const char *value) { uwsgi_cfg *c ; int val ; if (cfg) { c = cfg ; } else { c = ap_get_module_config(cmd->server->module_config, &uwsgi_module); } c->max_vars = atoi(value); return NULL; } static const char * cmd_uwsgi_modifier1(cmd_parms *cmd, void *cfg, const char *value) { uwsgi_cfg *c ; int val ; if (cfg) { c = cfg ; } else { c = ap_get_module_config(cmd->server->module_config, &uwsgi_module); } val = atoi(value); if (val < 0 || val > 255) { return "ignored uWSGImodifier1. Value must be between 0 and 255" ; } else { c->modifier1 = (uint8_t) val; } return NULL; } static const char * cmd_uwsgi_force_cgi_mode(cmd_parms *cmd, void *cfg, const char *value) { uwsgi_cfg *c ; if (cfg) { c = cfg ; } else { c = ap_get_module_config(cmd->server->module_config, &uwsgi_module); } if (!strcmp("yes", value) || !strcmp("on", value) || !strcmp("enable", value) || !strcmp("1", value) || !strcmp("true", value)) { c->cgi_mode = 1 ; } return NULL ; } static const char * cmd_uwsgi_modifier2(cmd_parms *cmd, void *cfg, const char *value) { uwsgi_cfg *c ; int val ; if (cfg) { c = cfg ; } else { c = ap_get_module_config(cmd->server->module_config, &uwsgi_module); } val = atoi(value); if (val < 0 || val > 255) { return "ignored uWSGImodifier2. Value must be between 0 and 255" ; } else { c->modifier2 = (uint8_t) val; } return NULL; } static const char * cmd_uwsgi_socket2(cmd_parms *cmd, void *cfg, const char *path) { uwsgi_cfg *c ; char *tcp_port; if (cfg) { c = cfg ; } else { c = ap_get_module_config(cmd->server->module_config, &uwsgi_module); } if (tcp_port = strchr(path, ':')) { c->addr_size2 = sizeof(struct sockaddr_in); c->s_addr2.i_addr.sin_family = AF_INET; c->s_addr2.i_addr.sin_port = htons(atoi(tcp_port+1)); tcp_port[0] = 0; c->s_addr2.i_addr.sin_addr.s_addr = inet_addr(path); } else if (strlen(path) < 104) { strcpy(c->s_addr2.u_addr.sun_path, path); c->addr_size2 = strlen(path) + ( (void *)&c->s_addr.u_addr.sun_path - (void *)&c->s_addr ) ; // abstract namespace ?? if (path[0] == '@') { c->s_addr2.u_addr.sun_path[0] = 0 ; } c->s_addr2.u_addr.sun_family = AF_UNIX; } return NULL ; } static const char * cmd_uwsgi_socket(cmd_parms *cmd, void *cfg, const char *path, const char *timeout) { uwsgi_cfg *c ; char *tcp_port; if (cfg) { c = cfg ; } else { c = ap_get_module_config(cmd->server->module_config, &uwsgi_module); } if (tcp_port = strchr(path, ':')) { c->addr_size = sizeof(struct sockaddr_in); c->s_addr.i_addr.sin_family = AF_INET; c->s_addr.i_addr.sin_port = htons(atoi(tcp_port+1)); tcp_port[0] = 0; c->s_addr.i_addr.sin_addr.s_addr = inet_addr(path); } else if (strlen(path) < 104) { strcpy(c->s_addr.u_addr.sun_path, path); c->addr_size = strlen(path) + ( (void *)&c->s_addr.u_addr.sun_path - (void *)&c->s_addr ) ; // abstract namespace ?? if (path[0] == '@') { c->s_addr.u_addr.sun_path[0] = 0 ; } c->s_addr.u_addr.sun_family = AF_UNIX; } if (timeout) { c->socket_timeout = atoi(timeout); } return NULL ; } static const char * cmd_uwsgi_empty_remote_user(cmd_parms *cmd, void *cfg, const char *value) { uwsgi_cfg *c ; if (cfg) { c = cfg ; } else { c = ap_get_module_config(cmd->server->module_config, &uwsgi_module); } if (!strcmp("yes", value) || !strcmp("on", value) || !strcmp("enable", value) || !strcmp("1", value) || !strcmp("true", value)) { c->empty_remote_user = 1; } else { c->empty_remote_user = 0; } return NULL ; } static const command_rec uwsgi_cmds[] = { AP_INIT_TAKE12("uWSGIsocket", cmd_uwsgi_socket, NULL, RSRC_CONF|ACCESS_CONF, "Absolute path and optional timeout in seconds of uwsgi server socket"), AP_INIT_TAKE1("uWSGIsocket2", cmd_uwsgi_socket2, NULL, RSRC_CONF|ACCESS_CONF, "Absolute path of failover uwsgi server socket"), AP_INIT_TAKE1("uWSGImodifier1", cmd_uwsgi_modifier1, NULL, RSRC_CONF|ACCESS_CONF, "Set uWSGI modifier1"), AP_INIT_TAKE1("uWSGImodifier2", cmd_uwsgi_modifier2, NULL, RSRC_CONF|ACCESS_CONF, "Set uWSGI modifier2"), AP_INIT_TAKE1("uWSGIforceScriptName", cmd_uwsgi_force_script_name, NULL, ACCESS_CONF, "Fix for PATH_INFO/SCRIPT_NAME when the location has filesystem correspondence"), AP_INIT_TAKE1("uWSGIforceCGImode", cmd_uwsgi_force_cgi_mode, NULL, ACCESS_CONF, "Force uWSGI CGI mode for perfect integration with apache filter"), AP_INIT_TAKE1("uWSGIforceWSGIscheme", cmd_uwsgi_force_wsgi_scheme, NULL, ACCESS_CONF, "Force the WSGI scheme var (set by default to \"http\")"), AP_INIT_TAKE1("uWSGIemptyRemoteUser", cmd_uwsgi_empty_remote_user, NULL, ACCESS_CONF, "Always include REMOTE_USER in the environment, even with an empty value (default true)"), AP_INIT_TAKE1("uWSGImaxVars", cmd_uwsgi_max_vars, NULL, ACCESS_CONF, "Set the maximum allowed number of uwsgi variables (default 128)"), {NULL} }; static void register_hooks(apr_pool_t *p) { ap_hook_handler(uwsgi_handler, NULL, NULL, APR_HOOK_MIDDLE); } module AP_MODULE_DECLARE_DATA uwsgi_module = { STANDARD20_MODULE_STUFF, uwsgi_dir_config, NULL, uwsgi_server_config, NULL, uwsgi_cmds, register_hooks }; uwsgi-2.0.29/attach.py000066400000000000000000000002761477626554400146110ustar00rootroot00000000000000import struct import sys import os filename = sys.argv[1] size = os.path.getsize(filename) f = open(filename, 'r') os.write(1, f.read()) f.close() os.write(1, (struct.pack("new_from_fd($ENV{'UWSGI_FD'}, '+<'); } else { $server = IO::Socket::INET->new(LocalPort => $self->{port}, LocalAddr => $self->{host}, Listen => 100, ReuseAddr => 1); } while ( my $client = $server->accept ) { my $head = ''; my $remains = 4; while($remains) { $client->recv(my $buf, $remains); last unless $buf; $head.=$buf; $remains -= length($buf); } if (length($head) != 4) { $client->close; next; } my ($mod1, $envsize, $mod2) = unpack('CvC', $head); unless ($envsize) { $client->close; next; } $remains = $envsize; my $envbuf = ''; while($remains) { my $buf; if ($remains >= 4096) { $client->recv($buf, 4096); } else { $client->recv($buf, $remains); } unless($buf) { $client->close; next; } $envbuf.=$buf; $remains -= length($buf); } if (length($envbuf) != $envsize ) { $client->close; next; } my %env; my $i = 0; while($i < $envsize) { my $kl = unpack('v', substr($envbuf, $i, 2)); $i+=2; my $key = substr($envbuf, $i, $kl); $i+=$kl; my $vl = unpack('v', substr($envbuf, $i, 2)); $i+=2; $env{$key} = substr($envbuf, $i, $vl); $i+=$vl; } my $env = { %env, 'psgi.version' => [1,1], 'psgi.url_scheme' => ($env{HTTPS}||'off') =~ /^(?:on|1)$/i ? 'https' : 'http', 'psgi.input' => $client, 'psgi.errors' => *STDERR, 'psgi.multithread' => Plack::Util::FALSE, 'psgi.multiprocess' => Plack::Util::TRUE, 'psgi.run_once' => Plack::Util::FALSE, 'psgi.streaming' => Plack::Util::TRUE, 'psgi.nonblocking' => Plack::Util::FALSE, }; my $res = Plack::Util::run_app $app, $env; if (ref $res eq 'ARRAY') { $self->_handle_response($client, $env{'SERVER_PROTOCOL'}, $res); } elsif (ref $res eq 'CODE') { $res->(sub { $self->_handle_response($client, $env{'SERVER_PROTOCOL'}, $_[0]); }); } else { die "Bad response $res"; } $client->close; } } sub _handle_response { my ($self, $client, $protocol, $res) = @_; $client->send($protocol.' '.$res->[0].' '.HTTP::Status::status_message( $res->[0] )."\r\n"); my $headers = $res->[1]; my $hdrs = ''; while (my ($k, $v) = splice @$headers, 0, 2) { $hdrs .= "$k: $v\r\n"; } $hdrs .= "\r\n"; $client->send($hdrs); my $cb = sub { $client->send($_[0]) }; my $body = $res->[2]; if (defined $body) { Plack::Util::foreach($body, $cb); } else { return Plack::Util::inline_object write => $cb,close => sub { }; } } 1; uwsgi-2.0.29/contrib/binder.pl000066400000000000000000000012211477626554400162220ustar00rootroot00000000000000use POSIX; use IO::Socket::INET; use IO::Socket::INET6; use IO::Socket::UNIX; my $s = IO::Socket::INET->new(LocalAddr => '127.0.0.1', LocalPort => 1717, Proto => 'tcp', Reuse => 1); my $s2 = IO::Socket::INET->new(LocalAddr => '127.0.0.1', LocalPort => 3022, Proto => 'tcp', Reuse => 1); my $s3 = IO::Socket::INET6->new(LocalAddr => '::', LocalPort => 3017, Proto => 'tcp', Reuse => 1); my $s4 = IO::Socket::UNIX->new(Local => '/tmp/u.sock', Listen => 1); dup2($s->fileno, 17); dup2($s2->fileno, 22); dup2($s3->fileno, 30); dup2($s4->fileno, 0); exec './uwsgi','-M', '--socket','fd://17', '--http-socket','fd://22', '--socket','fd://30','--stats',':5001'; uwsgi-2.0.29/contrib/centos_init_script000066400000000000000000000031351477626554400202550ustar00rootroot00000000000000#!/bin/bash # uwsgi - Use uwsgi to run python and wsgi web apps. # # chkconfig: - 85 15 # description: Use uwsgi to run python and wsgi web apps. # processname: uwsgi # author: Roman Vasilyev # Source function library. . /etc/rc.d/init.d/functions PATH=/opt/uwsgi:/sbin:/bin:/usr/sbin:/usr/bin prog=/usr/sbin/uwsgi OWNER=nginx NAME=uwsgi DESC=uwsgi #DAEMON_OPTS="-s 127.0.0.1:9001 -M 4 -t 30 -A 4 -p 4 -d /var/log/uwsgi.log --pidfile /var/run/$NAME.pid --pythonpath $PYTHONPATH --module $MODULE" DAEMON_OPTS="-s 127.0.0.1:9001 -M 4 -t 30 -A 4 -p 16 -b 32768 -d /var/log/$NAME.log --pidfile /var/run/$NAME.pid --uid $OWNER" [ -f /etc/sysconfig/uwsgi ] && . /etc/sysconfig/uwsgi lockfile=/var/lock/subsys/uwsgi start () { echo -n "Starting $DESC: " daemon $prog $DAEMON_OPTS retval=$? echo [ $retval -eq 0 ] && touch $lockfile return $retval } stop () { echo -n "Stopping $DESC: " killproc $prog retval=$? echo [ $retval -eq 0 ] && rm -f $lockfile return $retval } reload () { echo "Reloading $NAME" killproc $prog -HUP RETVAL=$? echo } force-reload () { echo "Reloading $NAME" killproc $prog -TERM RETVAL=$? echo } restart () { stop start } rh_status () { status $prog } rh_status_q() { rh_status >/dev/null 2>&1 } case "$1" in start) rh_status_q && exit 0 $1 ;; stop) rh_status_q || exit 0 $1 ;; restart|force-reload) $1 ;; reload) rh_status_q || exit 7 $1 ;; status) rh_status ;; *) echo "Usage: $0 {start|stop|restart|reload|force-reload|status}" >&2 exit 2 ;; esac exit 0 uwsgi-2.0.29/contrib/cgi_python.c000066400000000000000000000030621477626554400167360ustar00rootroot00000000000000#include void uwsgi_cgi_load_python() { Py_Initialize(); } void uwsgi_cgi_run_python(char *filename) { char **e, *p; PyObject *k, *env_value; FILE *fp = fopen(filename, "r"); PySys_SetArgv(1, &filename); PyObject *os_module = PyImport_ImportModule("os"); if (os_module) { PyObject *os_module_dict = PyModule_GetDict(os_module); PyObject *py_environ = PyDict_GetItemString(os_module_dict, "environ"); if (py_environ) { for (e = environ; *e != NULL; e++) { p = strchr(*e, '='); if (p == NULL) continue; k = PyString_FromStringAndSize(*e, (int)(p-*e)); if (k == NULL) { PyErr_Print(); continue; } env_value = PyString_FromString(p+1); if (env_value == NULL) { PyErr_Print(); Py_DECREF(k); continue; } if (PyObject_SetItem(py_environ, k, env_value)) { PyErr_Print(); } Py_DECREF(k); Py_DECREF(env_value); } } } PyRun_AnyFileEx(fp, filename, 1); } uwsgi-2.0.29/contrib/cryptologger.rb000066400000000000000000000007021477626554400174720ustar00rootroot00000000000000require 'socket' require 'openssl' secret = 'ciaociao' iv = '' address = '127.0.0.1' port = 1717 algo = 'bf-cbc' s = UDPSocket.new s.bind(address, port) cipher = OpenSSL::Cipher.new(algo) cipher.decrypt cipher.key = secret + ("\0" * (cipher.key_len - secret.length)) cipher.iv = iv + ("0" * (cipher.iv_len - iv.length)) loop do msg, sender = s.recvfrom(8192) cipher.reset begin puts cipher.update(msg) + cipher.final rescue end end uwsgi-2.0.29/contrib/emperormon.ru000066400000000000000000000063631477626554400171710ustar00rootroot00000000000000require 'sinatra' require 'socket' require 'json' module EmperorStats def self.uwsgi_get_stats(server) parts = server.split(':') if parts.length > 1 s = TCPSocket.open(parts[0], parts[1]) else s = UNIXSocket.open(server) end return JSON.parse(s.read()) end end template = < <%=@title%>

Emperor: <%=@stats['emperor']%>


<% if @stats['emperor_tyrant'] == 1 %> <% end %> <% for vassal in @stats['vassals'] %> <% if @stats['emperor_tyrant'] == 1 %> <% end %> <% end %>
namepidfirst run last respawn last heartbeat loyal respawnsuid gid
<%=vassal['id']%> <%=vassal['pid']%> <%=Time.at(vassal['first_run']).strftime("%d %b %Y %H:%M:%S")%> <%=Time.at(vassal['last_run']).strftime("%d %b %Y %H:%M:%S")%> <% if vassal['last_heartbeat'] > 0 %><%=Time.at(vassal['last_heartbeat']).strftime("%d %b %Y %H:%M:%S")%><% end %> <% if vassal['loyal'] > 0 %><%=Time.at(vassal['last_loyal']).strftime("%d %b %Y %H:%M:%S")%><% end %> <%=vassal['respawns']%><%=vassal['uid']%> <%=vassal['gid']%>

blacklist

<% for bli in @stats['blacklist'] %> <% end %>
namethrottle
<%=bli['id']%> <%=bli['throttle_level']%>
eof get '/' do @stats = EmperorStats::uwsgi_get_stats(ENV['EMPEROR']) @title = 'uWSGI Emperor monitor' erb template end run Sinatra::Application uwsgi-2.0.29/contrib/fdconf.pl000066400000000000000000000001451477626554400162220ustar00rootroot00000000000000use POSIX; open CONFIG,'welcome.ini'; dup2(fileno(CONFIG), 17); exec './uwsgi','--ini','fd://17'; uwsgi-2.0.29/contrib/graphite_uwsgi.py000066400000000000000000000017541477626554400200300ustar00rootroot00000000000000# uwsgi --master --chdir /opt/graphite/webapp/graphite --module graphite_uwsgi ... # # # this module will update a carbon server (used by the graphite tool: http://graphite.wikidot.com/) # with requests count made by a Django app (and can track graphite itself as it is a Django app ;) # # import os import uwsgi import time from django.core.handlers.wsgi import WSGIHandler os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' CARBON_SERVER = "127.0.0.1:2003" def update_carbon(signum): # connect to the carbon server carbon_fd = uwsgi.connect(CARBON_SERVER) # send data to the carbon server uwsgi.send(carbon_fd, "uwsgi.%s.requests %d %d\n" % (uwsgi.hostname, uwsgi.total_requests(), int(time.time()))) # close the connection with the carbon server uwsgi.close(carbon_fd) # register a new uwsgi signal (signum: 17) uwsgi.register_signal(17, '', update_carbon) # attach a timer of 10 seconds to signal 17 uwsgi.add_timer(17, 10) # the Django app application = WSGIHandler() uwsgi-2.0.29/contrib/launchd/000077500000000000000000000000001477626554400160445ustar00rootroot00000000000000uwsgi-2.0.29/contrib/launchd/it.unbit.uwsgi.emperor.plist000066400000000000000000000007361477626554400234700ustar00rootroot00000000000000 Label it.unbit.uwsgi.emperor ProgramArguments /Users/roberta/uwsgi/uwsgi --emperor /Users/*/Library/uwsgi/*.{xml,ini,yml,yaml,js} uwsgi-2.0.29/contrib/launchd/it.unbit.uwsgi.plist000066400000000000000000000010401477626554400220050ustar00rootroot00000000000000 Label it.unbit.uwsgi ProgramArguments /Users/roberta/uwsgi/uwsgi --socket :3032 --module welcome --master --die-on-term uwsgi-2.0.29/contrib/loadapp.pl000066400000000000000000000010011477626554400163730ustar00rootroot00000000000000use IO::Socket::INET; my $s = IO::Socket::INET->new(PeerAddr => '127.0.0.1', PeerPort => $ARGV[0]); my $mountpoint = $ARGV[1]; my $app = $ARGV[2]; my $uwsgi_appid = pack('v', length('UWSGI_APPID')).'UWSGI_APPID'.pack('v', length($mountpoint)).$mountpoint; my $uwsgi_script = pack('v', length('UWSGI_SCRIPT')).'UWSGI_SCRIPT'.pack('v', length($app)).$app; $s->send(pack('CvC', 5, length($uwsgi_appid.$uwsgi_script),0).$uwsgi_appid.$uwsgi_script); while((my $cnt = $s->recv(my $buf, 4096))> 0) { print $buf; } uwsgi-2.0.29/contrib/pypy/000077500000000000000000000000001477626554400154275ustar00rootroot00000000000000uwsgi-2.0.29/contrib/pypy/uwsgi_pypy_greenlets.py000066400000000000000000000033431477626554400222730ustar00rootroot00000000000000""" Greenlets support simply --pypy-exec this file to enable PyPy's greenlet mode Example: uwsgi --http-socket :9090 --pypy-home /opt/pypy --pypy-wsgi werkzeug.testapp:test_app --pypy-exec contrib/pypy/uwsgi_pypy_greenlets.py --async 8 """ import greenlet uwsgi_pypy_greenlets = {} def uwsgi_pypy_greenlet_wrapper(): lib.async_schedule_to_req_green() @ffi.callback("void()") def uwsgi_pypy_greenlet_schedule(): id = lib.uwsgi.wsgi_req.async_id modifier1 = lib.uwsgi.wsgi_req.uh.modifier1 # generate a new greenlet if not lib.uwsgi.wsgi_req.suspended: uwsgi_pypy_greenlets[id] = greenlet.greenlet(uwsgi_pypy_greenlet_wrapper) lib.uwsgi.wsgi_req.suspended = 1 # this is called in the main stack if lib.uwsgi.p[modifier1].suspend: lib.uwsgi.p[modifier1].suspend(ffi.NULL) # let's switch uwsgi_pypy_greenlets[id].switch() # back to the main stack if lib.uwsgi.p[modifier1].resume: lib.uwsgi.p[modifier1].resume(ffi.NULL) @ffi.callback("void(struct wsgi_request *)") def uwsgi_pypy_greenlet_switch(wsgi_req): wsgi_req.async_id modifier1 = wsgi_req.uh.modifier1 # this is called in the current greenlet if lib.uwsgi.p[modifier1].suspend: lib.uwsgi.p[modifier1].suspend(wsgi_req) uwsgi_pypy_main_greenlet.switch() # back to the greenlet if lib.uwsgi.p[modifier1].resume: lib.uwsgi.p[modifier1].resume(wsgi_req) # update current running greenlet lib.uwsgi.wsgi_req = wsgi_req if lib.uwsgi.async < 1: raise Exception("pypy greenlets require async mode !!!") lib.uwsgi.schedule_to_main = uwsgi_pypy_greenlet_switch lib.uwsgi.schedule_to_req = uwsgi_pypy_greenlet_schedule uwsgi_pypy_main_greenlet = greenlet.getcurrent() uwsgi-2.0.29/contrib/pyuwsgi.py000066400000000000000000000005141477626554400165070ustar00rootroot00000000000000import sys import os import pyuwsgi orig_args = sys.argv orig_executable = sys.executable orig_args.insert(0, orig_executable) uwsgi_args = [] for arg in sys.argv[2:]: uwsgi_args.append(arg) # pyuwsgi.run('welcome.ini') pyuwsgi.run(uwsgi_args) # if you are here uWSGI has been reloaded os.execv(orig_executable, orig_args) uwsgi-2.0.29/contrib/runuwsgi.py000066400000000000000000000050221477626554400166620ustar00rootroot00000000000000import django from django.core.management.base import BaseCommand from django.conf import settings import os import sys class Command(BaseCommand): help = "Runs this project as a uWSGI application. Requires the uwsgi binary in system path." http_port = '8000' socket_addr = None def handle(self, *args, **options): for arg in args: k, v = arg.split('=') if k == 'http': if self.http_port: self.http_port = v elif k == 'socket': self.http_port = None self.socket_addr = v # load http and python plugin: first the specific version, otherwise try with the generic one if self.http_port: os.environ['UWSGI_PLUGINS'] = 'http,python%d%d:python' % (sys.version_info[0], sys.version_info[1]) else: os.environ['UWSGI_PLUGINS'] = 'python%d%d:python' % (sys.version_info[0], sys.version_info[1]) # load the Django WSGI handler os.environ['UWSGI_MODULE'] = 'django.core.handlers.wsgi:WSGIHandler()' # DJANGO settings if options['settings']: os.environ['DJANGO_SETTINGS_MODULE'] = options['settings'] else: os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' # bind the http server to the default port if self.http_port: os.environ['UWSGI_HTTP'] = ':%s' % self.http_port elif self.socket_addr: os.environ['UWSGI_SOCKET'] = self.socket_addr # map admin static files os.environ['UWSGI_STATIC_MAP'] = '%s=%s' % (settings.ADMIN_MEDIA_PREFIX, os.path.join(django.__path__[0], 'contrib', 'admin', 'media')) # remove sockets/pidfile at exit os.environ['UWSGI_VACUUM'] = '1' # retrieve/set the PythonHome os.environ['UWSGI_PYHOME'] = sys.prefix # increase buffer size a bit os.environ['UWSGI_BUFFER_SIZE'] = '8192' # add threads for concurrency os.environ['UWSGI_THREADS'] = '8' # enable the master process os.environ['UWSGI_MASTER'] = '1' # use uWSGI python module aliasing to fix the PYTHONPATH os.environ['UWSGI_PYMODULE_ALIAS'] = '%s=./' % os.path.basename(os.getcwd()) # exec the uwsgi binary os.execvp('uwsgi', ('uwsgi',)) def usage(self, subcommand): return r""" run this project on the uWSGI server http=PORT run the embedded http server on port PORT socket=ADDR bind the uwsgi server on address ADDR (this will disable the http server) """ uwsgi-2.0.29/contrib/securesubscribe.pl000066400000000000000000000014561477626554400201610ustar00rootroot00000000000000#!/usr/bin/perl use Crypt::OpenSSL::RSA; use IO::Socket::INET; open PK,$ARGV[3]; my @lines = ; close PK; $rsa_priv = Crypt::OpenSSL::RSA->new_private_key(join('',@lines)); my %items = {}; $items{'key'} = $ARGV[1]; $items{'address'} = $ARGV[2]; my $uwsgi_pkt = ''; foreach(keys %items) { $uwsgi_pkt .= pack('v', length($_)).$_.pack('v', length($items{$_})).$items{$_}; } my $unix_check = time(); $uwsgi_pkt .= pack('v', 4).'unix'.pack('v', length($unix_check)).$unix_check; my $signature = $rsa_priv->sign($uwsgi_pkt); $uwsgi_pkt .= pack('v', 4).'sign'.pack('v', length($signature)).$signature; my $udp = new IO::Socket::INET(PeerAddr => $ARGV[0], Proto => 'udp'); $udp->send(pack('CvC', 224, length($uwsgi_pkt), 0).$uwsgi_pkt); print ''.(length($uwsgi_pkt)+4).' bytes sent to '.$ARGV[0]."\n"; uwsgi-2.0.29/contrib/spoolqueue/000077500000000000000000000000001477626554400166275ustar00rootroot00000000000000uwsgi-2.0.29/contrib/spoolqueue/producer.py000066400000000000000000000002671477626554400210310ustar00rootroot00000000000000from tasksconsumer import enqueue def application(env, sr): sr('200 OK', [('Content-Type', 'text/html')]) enqueue(queue='fast', pippo='pluto') return "Task enqueued" uwsgi-2.0.29/contrib/spoolqueue/tasks.py000066400000000000000000000003661477626554400203330ustar00rootroot00000000000000from __future__ import print_function from tasksconsumer import queueconsumer @queueconsumer('fast', 4) def fast_queue(arguments): print("fast", arguments) @queueconsumer('slow') def slow_queue(arguments): print("foobar", arguments) uwsgi-2.0.29/contrib/spoolqueue/tasksconsumer.py000066400000000000000000000020501477626554400220770ustar00rootroot00000000000000from uwsgidecorators import spool from threading import Thread from six.moves import queue queues = {} class queueconsumer(object): def __init__(self, name, num=1, **kwargs): self.name = name self.num = num self.queue = queue.Queue() self.threads = [] self.func = None queues[self.name] = self @staticmethod def consumer(self): while True: req = self.queue.get() print(req) self.func(req) self.queue.task_done() def __call__(self, f): self.func = f for i in range(self.num): t = Thread(target=self.consumer, args=(self,)) self.threads.append(t) t.daemon = True t.start() @spool def spooler_enqueuer(arguments): if 'queue' in arguments: queue = arguments['queue'] queues[queue].queue.put(arguments) else: raise Exception("You have to specify a queue name") def enqueue(*args, **kwargs): return spooler_enqueuer.spool(*args, **kwargs) uwsgi-2.0.29/contrib/subscribe.pl000066400000000000000000000006751477626554400167540ustar00rootroot00000000000000#!/usr/bin/perl use IO::Socket::INET; my %items = {}; $items{'key'} = $ARGV[1]; $items{'address'} = $ARGV[2]; my $uwsgi_pkt = ''; foreach(keys %items) { $uwsgi_pkt .= pack('v', length($_)).$_.pack('v', length($items{$_})).$items{$_}; } my $udp = new IO::Socket::INET(PeerAddr => $ARGV[0], Proto => 'udp'); $udp->send(pack('CvC', 224, length($uwsgi_pkt), 0).$uwsgi_pkt); print ''.(length($uwsgi_pkt)+4).' bytes sent to '.$ARGV[0]."\n"; uwsgi-2.0.29/contrib/twuwsgi.py000066400000000000000000000101741477626554400165140ustar00rootroot00000000000000from twisted.internet import defer, protocol, reactor from twisted.protocols import basic from twisted.web2 import http, resource, responsecode, stream import struct class uWSGIClientResource(resource.LeafResource): def __init__(self, app='', port=3030, host='localhost'): resource.LeafResource.__init__(self) self.host = host self.port = port self.app = app def renderHTTP(self, request): return uWSGI(request, self.app, self.host, self.port) def uWSGI(request, app, host, port): if request.stream.length is None: return http.Response(responsecode.LENGTH_REQUIRED) request.uwsgi_app = app factory = uWSGIClientProtocolFactory(request) reactor.connectTCP(host, port, factory) return factory.deferred class uWSGIClientProtocol(basic.LineReceiver): def __init__(self, request, deferred): self.request = request self.deferred = deferred self.stream = stream.ProducerStream() self.response = http.Response(stream=self.stream) self.status_parsed = None def build_uwsgi_var(self, key, value): return struct.pack(' 1, :threads => 1, :master => false, :logging => true, :static => true, :config => nil, :cachehack => false } opts = OptionParser.new do |opts| opts.on("-p", "--processes=nproc", Integer, '') { |p| options[:processes] = p } opts.on("-t", "--threads=nthreads", Integer, '') { |t| options[:threads] = t } opts.on("-M", "--master", '') { options[:master] = true } opts.on("-L", "--no-logging", '') { options[:logging] = false } opts.on("-S", "--no-static", '') { options[:static] = false } opts.on("-C", "--cache-hack", '') { options[:cachehack] = true } opts.parse! ARGV end if ARGV[0] options[:config] = ARGV[0] end def human_round(float) (float * (10 ** 2)).round / (10 ** 2).to_f end $requests = 0 $workers = Array.new $mywid = 0 module Rack class RailsCachingHack def initialize app @app = app end def stripuri(uri) uri = uri.split('/') uri.slice!(1) val = uri.join('/') end def call env env['PATH_INFO'] = stripuri(env['PATH_INFO']) if env['PATH_INFO'] env['REQUEST_URI'] = stripuri(env['REQUEST_URI']) if env['REQUEST_URI'] env['REQUEST_URI'] = '/' if env['REQUEST_URI'] == '' @app.call env end end module Handler class Unbit def self.run(app, options={}) server = UNIXServer.for_fd(0) can_spawn = true if options[:master] $0 = 'uRack master' $workers[0] = Process.pid ulog("master process enabled (pid: #{$workers[0]})") $workers[1] = Process.fork if $workers[1].to_i > 0 ulog("spawned worker 1 (pid: #{$workers[1]})") elsif $workers[1].to_i == 0 $0 = "uRack worker 1" $mywid = 1 can_spawn = false end else $0 = 'uRack worker 1' $workers[0] = nil $workers[1] = Process.pid $mywid = 1 ulog("spawned worker 1 (pid: #{$workers[1]})") end if options[:processes] > 1 and can_spawn for p in 2..options[:processes] $workers[p] = Process.fork if $workers[p].to_i == 0 $0 = "uRack worker #{p}" $mywid = p break elsif $workers[p].to_i > 0 ulog("spawned worker #{p} (pid: #{$workers[p]})") end end end # am i the master ? if options[:master] and Process.pid == $workers[0] while 1 i_am_a_child = false pid = Process.waitpid for wid in 1..options[:processes] if $workers[wid] == pid ulog("worker #{wid} died ! (pid: #{pid})") $workers[wid] = Process.fork if $workers[wid].to_i == 0 $0 = "uRack worker #{wid}" i_am_a_child = true $mywid = wid break elsif $workers[wid].to_i > 0 ulog("respawned worker #{wid} (pid: #{$workers[wid]})") end end end break if i_am_a_child end end if options[:threads] > 2 for t in 2..options[:threads] wt = Thread.new do ulog("spawning thread #{t} on worker #{$mywid}") while client = server.accept serve client, app, options end end end end while client = server.accept serve client, app, options end end def self.serve(client, app, options) speed = Time.now head, sender = client.recvfrom(4) unless head client.close return end mod1, size, mod2 = head.unpack('CvC') if size == 0 or size.nil? client.close return end vars, sender = client.recvfrom(size) if vars.length != size client.close return end env = Hash.new i = 0 while i < size kl = vars[i, 2].unpack('v')[0] i = i + 2 key = vars[i, kl] i = i + kl vl = vars[i, 2].unpack('v')[0] i = i + 2 value = vars[i, vl] i = i + vl env[key] = value end env.delete "HTTP_CONTENT_LENGTH" env.delete "HTTP_CONTENT_TYPE" env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" env["QUERY_STRING"] ||= "" env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] env["REQUEST_PATH"] ||= "/" env.delete "PATH_INFO" if env["PATH_INFO"] == "" env.delete "CONTENT_TYPE" if env["CONTENT_TYPE"] == "" env.delete "CONTENT_LENGTH" if env["CONTENT_LENGTH"] == "" if env["CONTENT_LENGTH"].to_i > 4096 rack_input = Rack::RewindableInput::Tempfile.new('Rack_unbit_Input') rack_input.chmod(0000) rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding) rack_input.binmode rack_input.unlink remains = env["CONTENT_LENGTH"].to_i while remains > 0 if remains >= 4096 buf, sender = client.recvfrom(4096) else buf, sender = client.recvfrom(remains) end if buf.length == 0 break end rack_input.write( buf ) remains -= buf.length end elsif env["CONTENT_LENGTH"].to_i > 0 rack_input = StringIO.new(client.recvfrom(env["CONTENT_LENGTH"].to_i)[0]) else rack_input = StringIO.new('') end rack_input.rewind env.update({"rack.version" => [1,1], "rack.input" => rack_input, "rack.errors" => $stderr, "rack.multithread" => false, "rack.multiprocess" => true, "rack.run_once" => false, "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http" }) app = Rack::ContentLength.new(app) disconnected = false begin status, headers, body = app.call(env) begin send_headers client, env["HTTP_VERSION"] ,status, headers send_body client, body ensure body.close if body.respond_to? :close end rescue Errno::EPIPE, Errno::ECONNRESET disconnected = true ensure rack_input.close client.close end $requests = $requests+1 ulog("req: #{$requests} ip: #{env['REMOTE_ADDR']} pid: #{Process.pid} as: #{human_round(syscall(356).to_f/1024/1024)} MB => #{env['REQUEST_METHOD']} #{env['REQUEST_URI']} in #{Time.now-speed} secs [#{status}]#{' DISCONNECTED !!!' if disconnected}") if options[:logging] end def self.send_headers(client, protocol, status, headers) client.print "#{protocol} #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]}\r\n" headers.each { |k, vs| vs.split("\n").each { |v| client.print "#{k}: #{v}\r\n" } } client.print "\r\n" client.flush end def self.send_body(client, body) body.each { |part| client.print part client.flush } end end end end def ulog(message) $stderr.puts "[#{Time.new}] uRack: #{message}" end ulog("starting at #{Dir.getwd}") limit_as = human_round(Process.getrlimit(Process::RLIMIT_AS)[1].to_f/1024/1024) ulog("your process address space limit is #{limit_as} MB") server = Rack::Handler.get('Unbit') starttime = Time.now app = nil if options[:config] cfgfile = File.read(options[:config]) if cfgfile[/^#\\(.*)/] opts.parse! $1.split(/\s+/) end app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app", nil, options[:config] else # falling back to rails if Dir.getwd =~ /\/public\/?$/ require '../config/environment' else require 'config/environment' end app = Rack::Builder.new { if options[:cachehack] use Rack::RailsCachingHack end if options[:static] use Rails::Rack::Static end if ActionController.const_defined?(:Dispatcher) && (ActionController::Dispatcher.instance_methods.include?(:call) || ActionController::Dispatcher.instance_methods.include?("call")) run ActionController::Dispatcher.new else require 'thin' run Rack::Adapter::Rails.new(:environment => ENV['RAILS_ENV']) end } end ulog("your app is ready (in #{Time.now-starttime} seconds).") server.run(app, options) uwsgi-2.0.29/contrib/uwsgi-cache-monitor.py000066400000000000000000000113201477626554400206610ustar00rootroot00000000000000from __future__ import print_function import mmap import os import struct import array import time import sys from optparse import OptionParser class Cache: def __init__(self, filename, cache_slots, block_size=65536, sample_sleep=1): self.block_size = block_size self.cache_slots = cache_slots self.key_size = 2048 self.item_size = 2 + 2 + 4 + 8 + 8 + 8 + 8 + 8 + self.key_size self.block_size_start = self.item_size * self.cache_slots fd = os.open(filename, os.O_RDONLY) self.cache_store = mmap.mmap(fd, 0, mmap.MAP_SHARED, mmap.PROT_READ) self.sample_sleep = sample_sleep self.samples = 0 self.history = [] self.cache_full = 0 self.cache_empty = 0 self.cache_items = 0 self.block_sizes = 0 def store_read_item_block(self, position): pos = self.cache_store.tell() # uwsgi cache stores cache entries first and then the blocks self.cache_store.seek(self.block_size_start + (position * self.block_size)) buf = self.cache_store.read(self.block_size) self.cache_store.seek(pos) return buf def store_read_item(self, position): buf = self.cache_store.read(self.item_size) fields = struct.unpack_from('@HHIQQQQQ2048c', buf) key = array.array('c', fields[8:self.key_size+8]).tostring().rstrip('\x00') if [x for x in key if x != '\x00']: buf = self.store_read_item_block(position) value = array.array('c', buf).tostring().rstrip('\x00') else: value = '' return (position, key, value, len(value)) def read(self): data = [self.store_read_item(i) for i in range(self.cache_slots)] self.cache_store.seek(0) self.update_stats(data) if self.sample_sleep: time.sleep(self.sample_sleep) return data def update_stats(self, data): # data is a list of (position, key, value, len(value)) tuples items = len([1 for x in data if x[3] > 0]) self.cache_items += items full, empty = items == self.cache_slots, items == 0 if full: self.cache_full += 1 if empty: self.cache_empty += 1 self.samples += 1 block_sizes = sum([x[3] for x in data]) self.block_sizes += block_sizes self.history.append({ 'full': full, 'empty': empty, 'data': data, 'items': items, 'block_sizes': block_sizes }) def dump(self): return { 'samples': self.samples, 'history': self.history, 'cache_slots': self.cache_slots, 'sample_sleep': self.sample_sleep, 'cache_empty': self.cache_empty, 'cache_full': self.cache_full, 'cache_items': self.cache_items, 'block_sizes': self.block_sizes, } def show_dump(self): d = self.dump() print() print("Recorded %d samples (%d second(s) sleep between samples)" % ( d['samples'], d['sample_sleep'] )) print("Cache empty %d times, full %d times, %.2f items on average" % ( d['cache_empty'], d['cache_full'], d['cache_items'] / d['samples'] )) print("Block size average size: %d bytes" % ( d['block_sizes'] / d['cache_items'] * 8 )) print("Data in cache average: %d bytes" % ( d['block_sizes'] / d['samples'] * 8 )) def main(options): cache = Cache(options.cache_store, options.cache_slots, options.block_size, options.sleep_time) print("Recording...") while True: try: cache.read() except KeyboardInterrupt: cache.show_dump() sys.exit(0) if __name__ == '__main__': parser = OptionParser() parser.add_option( "-s", "--cache-slots", dest="cache_slots", type="int", help="Slots available in the cache, uwsgi cache option" ) parser.add_option( "-c", "--cache-store", dest="cache_store", default="uwsgi.cache", help="The filename of the cache store, uwsgi cache-store option. Default: uwsgi.cache" ) parser.add_option( "-b", "--block-size", dest="block_size", default=65536, type="int", help="The size of the cache block, uwsgi cache-blocksize option. Default: 65536" ) parser.add_option( "-t", "--sleep-time", dest="sleep_time", default=1, type="int", help="The time to sleep between each sample. Default: 1" ) (options, args) = parser.parse_args() if not options.cache_slots: parser.error('Option -s / --cache-slots is mandatory') main(options) uwsgi-2.0.29/contrib/uwsgi.erl000066400000000000000000000012651477626554400162740ustar00rootroot00000000000000-module(uwsgi). -export([encode/1,send/3]). encode(Vars) -> Body = lists:map(fun(X) -> Len = length(X), lists:append( binary_to_list(<>), X) end, Vars), lists:flatten(Body). response(Sock, Output) -> case gen_tcp:recv(Sock,0) of { ok, Data } -> response(Sock, lists:append(Output, binary_to_list(Data))); { error, closed } -> gen_tcp:close(Sock), Output end. send(Host, Port, Message) -> { ok, Sock } = gen_tcp:connect( Host, Port, [ binary, { active, false} ]), Body = encode(Message), Len = length(Body), ok = gen_tcp:send(Sock, << 0, Len:16/little-unsigned-integer, 0>>), ok = gen_tcp:send(Sock, Body), response(Sock, []). uwsgi-2.0.29/contrib/uwsgi.java000066400000000000000000000151551477626554400164360ustar00rootroot00000000000000import java.io.*; import java.net.*; import javax.servlet.*; import javax.servlet.http.*; import java.util.Enumeration; import org.apache.catalina.util.IOTools; public class uwsgi extends HttpServlet { private String mountpoint = null; public void init(ServletConfig config) throws ServletException { super.init(config); String servletName = getServletConfig().getServletName(); if (servletName == null) servletName = ""; if (servletName.startsWith("org.apache.catalina.INVOKER.")) throw new UnavailableException ("Cannot invoke uWSGIServlet through the invoker"); if (getServletConfig().getInitParameter("mountpoint") != null) { mountpoint = getServletConfig().getInitParameter("mountpoint"); if (mountpoint.length() <= 1) { mountpoint = null; } } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { uWSGIHandler(request, response); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { uWSGIHandler(request, response); } private void uWSGIHandler(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { Socket client = new Socket("localhost",3017); ByteArrayOutputStream uwsgi_request = new ByteArrayOutputStream(); DataOutputStream wos = new DataOutputStream(uwsgi_request); DataOutputStream os = new DataOutputStream(client.getOutputStream()); DataInputStream is = new DataInputStream( client.getInputStream() ); ServletOutputStream out = response.getOutputStream(); boolean hasBody = false; wos.writeShort(swapShort( (short) 14)); wos.writeBytes("REQUEST_METHOD"); wos.writeShort(swapShort( (short) request.getMethod().length() ) ); wos.writeBytes( request.getMethod() ); wos.writeShort(swapShort( (short) 12)); wos.writeBytes("QUERY_STRING"); if (request.getQueryString() != null) { wos.writeShort(swapShort( (short) request.getQueryString().length() ) ); wos.writeBytes( request.getQueryString() ); } else { wos.writeShort(0); } wos.writeShort(swapShort( (short) 11)); wos.writeBytes("SERVER_NAME"); wos.writeShort(swapShort( (short) request.getServerName().length() ) ); wos.writeBytes( request.getServerName() ); wos.writeShort(swapShort( (short) 11)); wos.writeBytes("SERVER_PORT"); wos.writeShort(swapShort( (short) Integer.toString(request.getServerPort()).length() ) ); wos.writeBytes( Integer.toString(request.getServerPort()) ); wos.writeShort(swapShort( (short) 15)); wos.writeBytes("SERVER_PROTOCOL"); wos.writeShort(swapShort( (short) request.getProtocol().length() ) ); wos.writeBytes( request.getProtocol() ); wos.writeShort(swapShort( (short) 11)); wos.writeBytes("REQUEST_URI"); if (request.getQueryString() != null) { if (request.getQueryString().length() > 0) { wos.writeShort(swapShort( (short) (request.getRequestURI().length()+1+request.getQueryString().length()) ) ); wos.writeBytes( request.getRequestURI()+"?"+request.getQueryString() ); } else { wos.writeShort(swapShort( (short) request.getRequestURI().length() ) ); wos.writeBytes( request.getRequestURI() ); } } else { wos.writeShort(swapShort( (short) request.getRequestURI().length() ) ); wos.writeBytes( request.getRequestURI() ); } if (mountpoint != null) { wos.writeShort(swapShort( (short) 11)); wos.writeBytes("SCRIPT_NAME"); wos.writeShort(swapShort( (short) mountpoint.length() ) ); wos.writeBytes( mountpoint ); } wos.writeShort(swapShort( (short) 9)); wos.writeBytes("PATH_INFO"); if (mountpoint != null) { wos.writeShort(swapShort( (short) (request.getRequestURI().length() - mountpoint.length()) ) ); wos.writeBytes( request.getRequestURI().substring(mountpoint.length()) ); } else { wos.writeShort(swapShort( (short) request.getRequestURI().length() ) ); wos.writeBytes( request.getRequestURI() ); } wos.writeShort(swapShort( (short) 11)); wos.writeBytes("REMOTE_ADDR"); wos.writeShort(swapShort( (short) request.getRemoteAddr().length() ) ); wos.writeBytes( request.getRemoteAddr() ); if (request.getRemoteUser() != null) { wos.writeShort(swapShort( (short) 11)); wos.writeBytes("REMOTE_USER"); wos.writeShort(swapShort( (short) request.getRemoteUser().length() ) ); wos.writeBytes( request.getRemoteUser() ); } if (request.getContentType() != null) { wos.writeShort(swapShort( (short) 12)); wos.writeBytes("CONTENT_TYPE"); wos.writeShort(swapShort( (short) request.getContentType().length() ) ); wos.writeBytes( request.getContentType() ); } if (request.getContentLength() > 0) { wos.writeShort(swapShort( (short) 14)); wos.writeBytes("CONTENT_LENGTH"); String sContentLength = new Integer(request.getContentLength()).toString(); wos.writeShort(swapShort( (short) sContentLength.length() ) ); wos.writeBytes( sContentLength ); hasBody = true; } // taken from CGI servlet Enumeration headers = request.getHeaderNames(); String header = null; while (headers.hasMoreElements()) { header = null; header = ((String) headers.nextElement()).toUpperCase(); wos.writeShort(swapShort( (short) ("HTTP_" + header.replace('-', '_')).length() )); wos.writeBytes("HTTP_" + header.replace('-', '_')); wos.writeShort(swapShort( (short) request.getHeader(header).length() )); wos.writeBytes( request.getHeader(header) ); } os.writeByte(0); os.writeShort( swapShort( (short) wos.size() ) ); os.writeByte(0); uwsgi_request.writeTo( os ); if (hasBody) { IOTools.flow(request.getInputStream(), os); } boolean statusParsed = false; for(;;) { String line = byte_readline(is); if (line == "") { break; } if (statusParsed == false) { String[] status = line.split(" ",3); response.setStatus( Integer.parseInt(status[1]) ); statusParsed = true; } else { String[] keyval = line.split(": ",2); if (keyval.length == 2) { response.addHeader(keyval[0], keyval[1]); } else { break; } } } byte cb[] = new byte[4096]; int len = 0; for(;;) { len = is.read(cb,0,4096); if ( len > 0) { out.write(cb,0,len); } else { break; } } } private String byte_readline(DataInputStream is) throws IOException { ByteArrayOutputStream line = new ByteArrayOutputStream(); for(;;) { byte b = is.readByte(); if (b == 10) { break; } line.write(b); } return line.toString("ASCII").replaceAll("\\n","").replaceAll("\\r",""); } private short swapShort(short x) { short tmp1 = (short) (x>>8); short tmp2 = (short) (x<<8); return (short) (tmp1 | tmp2); } } uwsgi-2.0.29/contrib/uwsgi.rb000066400000000000000000000067531477626554400161240ustar00rootroot00000000000000require 'socket' require 'rack/content_length' require 'rack/rewindable_input' require 'stringio' module Rack module Handler class Uwsgi def self.run(app, options={}) if ENV['UWSGI_FD'] server = UNIXServer.for_fd(ENV['UWSGI_FD'].to_i) else server = TCPServer.new(options[:Host], options[:Port]) end while client = server.accept serve client, app end end def self.serve(client, app) head, sender = client.recvfrom(4) unless head client.close return end mod1, size, mod2 = head.unpack('CvC') if size == 0 or size.nil? client.close return end vars, sender = client.recvfrom(size) if vars.length != size client.close return end env = Hash.new i = 0 while i < size kl = vars[i, 2].unpack('v')[0] i = i + 2 key = vars[i, kl] i = i + kl vl = vars[i, 2].unpack('v')[0] i = i + 2 value = vars[i, vl] i = i + vl env[key] = value end env.delete "HTTP_CONTENT_LENGTH" env.delete "HTTP_CONTENT_TYPE" env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" env["QUERY_STRING"] ||= "" env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] env["REQUEST_PATH"] ||= "/" env.delete "PATH_INFO" if env["PATH_INFO"] == "" env.delete "CONTENT_TYPE" if env["CONTENT_TYPE"] == "" env.delete "CONTENT_LENGTH" if env["CONTENT_LENGTH"] == "" if env["CONTENT_LENGTH"].to_i > 4096 rack_input = Rack::RewindableInput::Tempfile.new('Rack_uwsgi_Input') rack_input.chmod(0000) rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding) rack_input.binmode if RUBY_PLATFORM !~ /(mswin|mingw|cygwin|java)/ rack_input.unlink end remains = env["CONTENT_LENGTH"].to_i while remains > 0 if remains >= 4096 buf, sender = client.recvfrom(4096) else buf, sender = client.recvfrom(remains) end rack_input.write( buf ) remains -= buf.length end elsif env["CONTENT_LENGTH"].to_i > 0 rack_input = StringIO.new(client.recvfrom(env["CONTENT_LENGTH"].to_i)[0]) else rack_input = StringIO.new('') end rack_input.rewind env.update({"rack.version" => [1,1], "rack.input" => rack_input, "rack.errors" => $stderr, "rack.multithread" => false, "rack.multiprocess" => true, "rack.run_once" => false, "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http" }) app = Rack::ContentLength.new(app) begin status, headers, body = app.call(env) begin send_headers client, env["HTTP_VERSION"] ,status, headers send_body client, body ensure body.close if body.respond_to? :close end rescue Errno::EPIPE, Errno::ECONNRESET ensure rack_input.close client.close end end def self.send_headers(client, protocol, status, headers) client.print "#{protocol} #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]}\r\n" headers.each { |k, vs| vs.split("\n").each { |v| client.print "#{k}: #{v}\r\n" } } client.print "\r\n" client.flush end def self.send_body(client, body) body.each { |part| client.print part client.flush } end end end end uwsgi-2.0.29/contrib/uwsgi_client.c000066400000000000000000000033641477626554400172740ustar00rootroot00000000000000/* *** uWSGI cgi client *** to compile: gcc -Wall -o uwsgi_client.cgi uwsgi_client.c */ #include #include #include #include #include #include #define UWSGI_SOCK "/tmp/uwsgi.sock" int main() { extern char **environ; char *env; struct sockaddr_un s_addr; int uwsgi_socket; int res, cnt; char *place_holder; unsigned short len; char message[4096]; char *mptr; char *content_length; memset(&s_addr, 0, sizeof(struct sockaddr_un)); s_addr.sun_family = AF_UNIX; strcpy(s_addr.sun_path, UWSGI_SOCK); uwsgi_socket = socket(AF_UNIX, SOCK_STREAM, 0); if (uwsgi_socket < 0) { perror("socket()"); exit(1); } if (connect(uwsgi_socket, (struct sockaddr *) &s_addr, strlen(UWSGI_SOCK) + ( (void *)&s_addr.sun_path - (void *)&s_addr) ) != 0) { perror("connect()"); exit(1); } memset(message, 0, 4096); mptr = message+4; if (**environ) { while( (env = *environ) ) { place_holder = strchr(env,'='); // key len = place_holder-env; memcpy(mptr, &len, 2); mptr+=2; memcpy(mptr, env, len); mptr+=len; // value len = (unsigned short) (env+strlen(env) - (place_holder+1)); memcpy(mptr, &len, 2); mptr+=2; memcpy(mptr, place_holder+1, len); mptr+= len; *environ++; } } message[0] = 0; len = (mptr-message)-4; memcpy(message+1, &len, 2); message[3] = 0; res = send(uwsgi_socket, message, mptr-message, 0); if ( (content_length = getenv("CONTENT_LENGTH")) != NULL) { if (atoi(content_length) > 0) { while( (cnt = read(0, message, 4096)) ) { send(uwsgi_socket, message, cnt, 0); } } } if (res == mptr-message) { while( (res = recv(uwsgi_socket, message, 4096,0)) ) { write(1, message, res); } } return 0; } uwsgi-2.0.29/contrib/uwsgi_dynamic_client.c000066400000000000000000000033631477626554400207770ustar00rootroot00000000000000/* *** uWSGI cgi client *** to compile: gcc -Wall -o uwsgi_client.cgi uwsgi_dynamic_client.c */ #include #include #include #include #include #include #define UWSGI_SOCK "/tmp/uwsgi.sock" #define UWSGI_SCRIPT "myapp_wsgi" int main() { extern char **environ; char *env; struct sockaddr_un s_addr; int uwsgi_socket; int res, cnt; char *place_holder; unsigned short len; char message[4096]; char *mptr; memset(&s_addr, 0, sizeof(struct sockaddr_un)); s_addr.sun_family = AF_UNIX; strcpy(s_addr.sun_path, UWSGI_SOCK); uwsgi_socket = socket(AF_UNIX, SOCK_STREAM, 0); if (uwsgi_socket < 0) { perror("socket()"); exit(1); } if (connect(uwsgi_socket, (struct sockaddr *) &s_addr, strlen(UWSGI_SOCK) + ( (void *)&s_addr.sun_path - (void *)&s_addr) ) != 0) { perror("connect()"); exit(1); } memset(message, 0, 4096); mptr = message+4; if (setenv("UWSGI_SCRIPT", UWSGI_SCRIPT, 1) != 0) { perror("setenv()"); exit(1); } if (**environ) { while( (env = *environ) ) { place_holder = strchr(env,'='); // key len = place_holder-env; memcpy(mptr, &len, 2); mptr+=2; memcpy(mptr, env, len); mptr+=len; // value len = (unsigned short) (env+strlen(env) - (place_holder+1)); memcpy(mptr, &len, 2); mptr+=2; memcpy(mptr, place_holder+1, len); mptr+= len; *environ++; } } message[0] = 0; len = (mptr-message)-4; memcpy(message+1, &len, 2); message[3] = 0; res = send(uwsgi_socket, message, mptr-message, 0); while( (cnt = read(0, message, 4096)) ) { send(uwsgi_socket, message, cnt, 0); } if (res == mptr-message) { while( (res = recv(uwsgi_socket, message, 4096,0)) ) { write(1, message, res); } } return 0; } uwsgi-2.0.29/contrib/uwsgisubscribers.ru000066400000000000000000000053431477626554400204100ustar00rootroot00000000000000require 'sinatra' require 'socket' require 'json' module USubscribers def self.uwsgi_get_stats(server) parts = server.split(':') if parts.length > 1 s = TCPSocket.open(parts[0], parts[1]) else s = UNIXSocket.open(server) end return JSON.parse(s.read()) end end template = < <%=@title%> <% for server in @servers.keys %>

SubscriptionServer: <%=server%>


<% for pool in @servers[server] %>

<%=pool['key']%> (<%=pool['hits']%> hits)

<% for node in pool['nodes'] %> <% end %>
nodeloadrequests last check fail count
<%=node['name']%><%=node['load']%><%=node['requests']%> <%=Time.at(node['last_check']).strftime("%d-%m-%Y %H:%M:%S")%> <%=node['failcnt']%>
<% end %>
<% end %> eof get '/' do @servers = {} for server in ENV['U_SERVERS'].split(',') stats = USubscribers::uwsgi_get_stats(server) if stats @servers[server] = stats['subscriptions'] end end @title = 'uWSGI subscriptions viewer' erb template end run Sinatra::Application uwsgi-2.0.29/contrib/xinetd_uwsgi000066400000000000000000000006331477626554400170640ustar00rootroot00000000000000service uwsgi { disable = no id = uwsgi-000 type = UNLISTED socket_type = stream server = /root/uwsgi/uwsgi server_args = --chdir /root/uwsgi/ --module welcome --logto /tmp/uwsgi.log port = 3031 bind = 127.0.0.1 user = root wait = yes } uwsgi-2.0.29/core/000077500000000000000000000000001477626554400137165ustar00rootroot00000000000000uwsgi-2.0.29/core/alarm.c000066400000000000000000000265361477626554400151720ustar00rootroot00000000000000#include "../uwsgi.h" extern struct uwsgi_server uwsgi; // generate a uwsgi signal on alarm void uwsgi_alarm_init_signal(struct uwsgi_alarm_instance *uai) { uai->data8 = atoi(uai->arg); } void uwsgi_alarm_func_signal(struct uwsgi_alarm_instance *uai, char *msg, size_t len) { uwsgi_route_signal(uai->data8); } // simply log an alarm void uwsgi_alarm_init_log(struct uwsgi_alarm_instance *uai) { } void uwsgi_alarm_func_log(struct uwsgi_alarm_instance *uai, char *msg, size_t len) { if (msg[len-1] != '\n') { if (uai->arg && strlen(uai->arg) > 0) { uwsgi_log_verbose("ALARM: %s %.*s\n", uai->arg, len, msg); } else { uwsgi_log_verbose("ALARM: %.*s\n", len, msg); } } else { if (uai->arg && strlen(uai->arg) > 0) { uwsgi_log_verbose("ALARM: %s %.*s", uai->arg, len, msg); } else { uwsgi_log_verbose("ALARM: %.*s", len, msg); } } } // run a command on alarm void uwsgi_alarm_init_cmd(struct uwsgi_alarm_instance *uai) { uai->data_ptr = uai->arg; } void uwsgi_alarm_func_cmd(struct uwsgi_alarm_instance *uai, char *msg, size_t len) { int pipe[2]; if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe)) { return; } uwsgi_socket_nb(pipe[0]); uwsgi_socket_nb(pipe[1]); if (write(pipe[1], msg, len) != (ssize_t) len) { close(pipe[0]); close(pipe[1]); return; } uwsgi_run_command(uai->data_ptr, pipe, -1); close(pipe[0]); close(pipe[1]); } // pass the log line to a mule void uwsgi_alarm_init_mule(struct uwsgi_alarm_instance *uai) { uai->data32 = atoi(uai->arg); if (uai->data32 > (uint32_t) uwsgi.mules_cnt) { uwsgi_log_alarm("] invalid mule_id (%d mules available), fallback to 0\n", uwsgi.mules_cnt); uai->data32 = 0; } } void uwsgi_alarm_func_mule(struct uwsgi_alarm_instance *uai, char *msg, size_t len) { // skip if mules are not available if (uwsgi.mules_cnt == 0) return; int fd = uwsgi.shared->mule_queue_pipe[0]; if (uai->data32 > 0) { int mule_id = uai->data32 - 1; fd = uwsgi.mules[mule_id].queue_pipe[0]; } mule_send_msg(fd, msg, len); } // register a new alarm void uwsgi_register_alarm(char *name, void (*init) (struct uwsgi_alarm_instance *), void (*func) (struct uwsgi_alarm_instance *, char *, size_t)) { struct uwsgi_alarm *old_ua = NULL, *ua = uwsgi.alarms; while (ua) { // skip already initialized alarms if (!strcmp(ua->name, name)) { return; } old_ua = ua; ua = ua->next; } ua = uwsgi_calloc(sizeof(struct uwsgi_alarm)); ua->name = name; ua->init = init; ua->func = func; if (old_ua) { old_ua->next = ua; } else { uwsgi.alarms = ua; } } // register embedded alarms void uwsgi_register_embedded_alarms() { uwsgi_register_alarm("signal", uwsgi_alarm_init_signal, uwsgi_alarm_func_signal); uwsgi_register_alarm("cmd", uwsgi_alarm_init_cmd, uwsgi_alarm_func_cmd); uwsgi_register_alarm("mule", uwsgi_alarm_init_mule, uwsgi_alarm_func_mule); uwsgi_register_alarm("log", uwsgi_alarm_init_log, uwsgi_alarm_func_log); } static int uwsgi_alarm_add(char *name, char *plugin, char *arg) { struct uwsgi_alarm *ua = uwsgi.alarms; while (ua) { if (!strcmp(ua->name, plugin)) { break; } ua = ua->next; } if (!ua) return -1; struct uwsgi_alarm_instance *old_uai = NULL, *uai = uwsgi.alarm_instances; while (uai) { old_uai = uai; uai = uai->next; } uai = uwsgi_calloc(sizeof(struct uwsgi_alarm_instance)); uai->name = name; uai->alarm = ua; uai->arg = arg; uai->last_msg = uwsgi_malloc(uwsgi.log_master_bufsize); if (old_uai) { old_uai->next = uai; } else { uwsgi.alarm_instances = uai; } ua->init(uai); return 0; } // get an alarm instance by its name static struct uwsgi_alarm_instance *uwsgi_alarm_get_instance(char *name) { struct uwsgi_alarm_instance *uai = uwsgi.alarm_instances; while (uai) { if (!strcmp(name, uai->name)) { return uai; } uai = uai->next; } return NULL; } #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) static int uwsgi_alarm_log_add(char *alarms, char *regexp, int negate) { struct uwsgi_alarm_log *old_ual = NULL, *ual = uwsgi.alarm_logs; while (ual) { old_ual = ual; ual = ual->next; } ual = uwsgi_calloc(sizeof(struct uwsgi_alarm_log)); if (uwsgi_regexp_build(regexp, &ual->pattern)) { free(ual); return -1; } ual->negate = negate; if (old_ual) { old_ual->next = ual; } else { uwsgi.alarm_logs = ual; } // map instances to the log char *list = uwsgi_str(alarms); char *p, *ctx = NULL; uwsgi_foreach_token(list, ",", p, ctx) { struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(p); if (!uai) { free(list); return -1; } struct uwsgi_alarm_ll *old_uall = NULL, *uall = ual->alarms; while (uall) { old_uall = uall; uall = uall->next; } uall = uwsgi_calloc(sizeof(struct uwsgi_alarm_ll)); uall->alarm = uai; if (old_uall) { old_uall->next = uall; } else { ual->alarms = uall; } } free(list); return 0; } #endif static void uwsgi_alarm_thread_loop(struct uwsgi_thread *ut) { // add uwsgi_alarm_fd; struct uwsgi_alarm_fd *uafd = uwsgi.alarm_fds; while(uafd) { event_queue_add_fd_read(ut->queue, uafd->fd); uafd = uafd->next; } char *buf = uwsgi_malloc(uwsgi.alarm_msg_size + sizeof(long)); for (;;) { int interesting_fd = -1; int ret = event_queue_wait(ut->queue, -1, &interesting_fd); if (ret > 0) { if (interesting_fd == ut->pipe[1]) { ssize_t len = read(ut->pipe[1], buf, uwsgi.alarm_msg_size + sizeof(long)); if (len > (ssize_t)(sizeof(long) + 1)) { size_t msg_size = len - sizeof(long); char *msg = buf + sizeof(long); long ptr = 0; memcpy(&ptr, buf, sizeof(long)); struct uwsgi_alarm_instance *uai = (struct uwsgi_alarm_instance *) ptr; if (!uai) break; uwsgi_alarm_run(uai, msg, msg_size); } } // check for alarm_fd else { uafd = uwsgi.alarm_fds; int fd_read = 0; while(uafd) { if (interesting_fd == uafd->fd) { if (fd_read) goto raise; size_t remains = uafd->buf_len; while(remains) { ssize_t len = read(uafd->fd, uafd->buf + (uafd->buf_len-remains), remains); if (len <= 0) { uwsgi_error("[uwsgi-alarm-fd]/read()"); uwsgi_log("[uwsgi-alarm-fd] i will stop monitoring fd %d\n", uafd->fd); event_queue_del_fd(ut->queue, uafd->fd, event_queue_read()); break; } remains-=len; } fd_read = 1; raise: uwsgi_alarm_run(uafd->alarm, uafd->msg, uafd->msg_len); } uafd = uafd->next; } } } } free(buf); } // initialize alarms, instances and log regexps void uwsgi_alarms_init() { if (!uwsgi.master_process) return; // first of all, create instance of alarms struct uwsgi_string_list *usl = uwsgi.alarm_list; while (usl) { char *line = uwsgi_str(usl->value); char *space = strchr(line, ' '); if (!space) { uwsgi_log("invalid alarm syntax: %s\n", usl->value); exit(1); } *space = 0; char *plugin = space + 1; char *colon = strchr(plugin, ':'); if (!colon) { uwsgi_log("invalid alarm syntax: %s\n", usl->value); exit(1); } *colon = 0; char *arg = colon + 1; // here the alarm is mapped to a name and initialized if (uwsgi_alarm_add(line, plugin, arg)) { uwsgi_log("invalid alarm: %s\n", usl->value); exit(1); } usl = usl->next; } if (!uwsgi.alarm_instances) return; // map alarm file descriptors usl = uwsgi.alarm_fd_list; while(usl) { char *space0 = strchr(usl->value, ' '); if (!space0) { uwsgi_log("invalid alarm-fd syntax: %s\n", usl->value); exit(1); } *space0 = 0; size_t buf_len = 1; char *space1 = strchr(space0+1, ' '); if (!space1) { uwsgi_log("invalid alarm-fd syntax: %s\n", usl->value); exit(1); } char *colon = strchr(space0+1, ':'); if (colon) { buf_len = strtoul(colon+1, NULL, 10); *colon = 0; } int fd = atoi(space0+1); uwsgi_add_alarm_fd(fd, usl->value, buf_len, space1+1, strlen(space1+1)); *space0 = ' '; *space1 = ' '; if (colon) { *colon = ':'; } usl = usl->next; } #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) // then map log-alarm usl = uwsgi.alarm_logs_list; while (usl) { char *line = uwsgi_str(usl->value); char *space = strchr(line, ' '); if (!space) { uwsgi_log("invalid log-alarm syntax: %s\n", usl->value); exit(1); } *space = 0; char *regexp = space + 1; // here the log-alarm is created if (uwsgi_alarm_log_add(line, regexp, usl->custom)) { uwsgi_log("invalid log-alarm: %s\n", usl->value); exit(1); } usl = usl->next; } #endif } void uwsgi_alarm_thread_start() { if (!uwsgi.alarm_instances) return; // start the alarm_thread uwsgi.alarm_thread = uwsgi_thread_new(uwsgi_alarm_thread_loop); if (!uwsgi.alarm_thread) { uwsgi_log("unable to spawn alarm thread\n"); exit(1); } } void uwsgi_alarm_trigger_uai(struct uwsgi_alarm_instance *uai, char *msg, size_t len) { struct iovec iov[2]; iov[0].iov_base = &uai; iov[0].iov_len = sizeof(long); iov[1].iov_base = msg; iov[1].iov_len = len; // now send the message to the alarm thread if (writev(uwsgi.alarm_thread->pipe[0], iov, 2) != (ssize_t) (len+sizeof(long))) { uwsgi_error("[uwsgi-alarm-error] uwsgi_alarm_trigger()/writev()"); } } #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) // check if a log should raise an alarm void uwsgi_alarm_log_check(char *msg, size_t len) { if (!uwsgi_strncmp(msg, len, "[uwsgi-alarm", 12)) return; struct uwsgi_alarm_log *ual = uwsgi.alarm_logs; while (ual) { if (uwsgi_regexp_match(ual->pattern, msg, len) >= 0) { if (!ual->negate) { struct uwsgi_alarm_ll *uall = ual->alarms; while (uall) { if (uwsgi.alarm_cheap) uwsgi_alarm_trigger_uai(uall->alarm, msg, len); else uwsgi_alarm_run(uall->alarm, msg, len); uall = uall->next; } } else { break; } } ual = ual->next; } } #endif // call the alarm func void uwsgi_alarm_run(struct uwsgi_alarm_instance *uai, char *msg, size_t len) { time_t now = uwsgi_now(); // avoid alarm storming/loop if last message is the same if (!uwsgi_strncmp(msg, len, uai->last_msg, uai->last_msg_size)) { if (now - uai->last_run < uwsgi.alarm_freq) return; } uai->alarm->func(uai, msg, len); uai->last_run = uwsgi_now(); memcpy(uai->last_msg, msg, len); uai->last_msg_size = len; } // this is the api function workers,mules and whatever you want can call from code void uwsgi_alarm_trigger(char *alarm_instance_name, char *msg, size_t len) { if (!uwsgi.alarm_thread) return; if (len > uwsgi.alarm_msg_size) return; struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(alarm_instance_name); if (!uai) return; uwsgi_alarm_trigger_uai(uai, msg, len); } struct uwsgi_alarm_fd *uwsgi_add_alarm_fd(int fd, char *alarm, size_t buf_len, char *msg, size_t msg_len) { struct uwsgi_alarm_fd *old_uafd = NULL, *uafd = uwsgi.alarm_fds; struct uwsgi_alarm_instance *uai = uwsgi_alarm_get_instance(alarm); if (!uai) { uwsgi_log("unable to find alarm \"%s\"\n", alarm); exit(1); } if (!buf_len) buf_len = 1; while(uafd) { // check if an equal alarm has been added if (uafd->fd == fd && uafd->alarm == uai) { return uafd; } old_uafd = uafd; uafd = uafd->next; } uafd = uwsgi_calloc(sizeof(struct uwsgi_alarm_fd)); uafd->fd = fd; uafd->buf = uwsgi_malloc(buf_len); uafd->buf_len = buf_len; uafd->msg = msg; uafd->msg_len = msg_len; uafd->alarm = uai; if (!old_uafd) { uwsgi.alarm_fds = uafd; } else { old_uafd->next = uafd; } // avoid the fd to be closed uwsgi_add_safe_fd(fd); uwsgi_log("[uwsgi-alarm] added fd %d\n", fd); return uafd; } uwsgi-2.0.29/core/async.c000066400000000000000000000357431477626554400152130ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; /* This is a general-purpose async loop engine (it expects a coroutine-based approach) You can see it as an hub holding the following structures: 1) the runqueue, cores ready to be run are appended to this list 2) the fd list, this is a list of monitored file descriptors, a core can wait for all the file descriptors it needs 3) the timeout value, if set, the current core will timeout after the specified number of seconds (unless an event cancels it) IMPORTANT: this is not a callback-based engine !!! */ // this is called whenever a new connection is ready, but there are no cores to handle it void uwsgi_async_queue_is_full(time_t now) { if (now > uwsgi.async_queue_is_full) { uwsgi_log_verbose("[DANGER] async queue is full !!!\n"); uwsgi.async_queue_is_full = now; } } void uwsgi_async_init() { uwsgi.async_queue = event_queue_init(); if (uwsgi.async_queue < 0) { exit(1); } uwsgi_add_sockets_to_queue(uwsgi.async_queue, -1); uwsgi.rb_async_timeouts = uwsgi_init_rb_timer(); // optimization, this array maps file descriptor to requests uwsgi.async_waiting_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd); uwsgi.async_proto_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd); } struct wsgi_request *find_wsgi_req_proto_by_fd(int fd) { return uwsgi.async_proto_fd_table[fd]; } struct wsgi_request *find_wsgi_req_by_fd(int fd) { return uwsgi.async_waiting_fd_table[fd]; } static void runqueue_remove(struct uwsgi_async_request *u_request) { struct uwsgi_async_request *parent = u_request->prev; struct uwsgi_async_request *child = u_request->next; if (parent) { parent->next = child; } if (child) { child->prev = parent; } if (u_request == uwsgi.async_runqueue) { uwsgi.async_runqueue = child; } if (u_request == uwsgi.async_runqueue_last) { uwsgi.async_runqueue_last = parent; } free(u_request); } static void runqueue_push(struct wsgi_request *wsgi_req) { // do not push the same request in the runqueue struct uwsgi_async_request *uar = uwsgi.async_runqueue; while(uar) { if (uar->wsgi_req == wsgi_req) return; uar = uar->next; } uar = uwsgi_malloc(sizeof(struct uwsgi_async_request)); uar->prev = NULL; uar->next = NULL; uar->wsgi_req = wsgi_req; if (uwsgi.async_runqueue == NULL) { uwsgi.async_runqueue = uar; } else { uar->prev = uwsgi.async_runqueue_last; } if (uwsgi.async_runqueue_last) { uwsgi.async_runqueue_last->next = uar; } uwsgi.async_runqueue_last = uar; } struct wsgi_request *find_first_available_wsgi_req() { struct wsgi_request *wsgi_req; if (uwsgi.async_queue_unused_ptr < 0) { return NULL; } wsgi_req = uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr]; uwsgi.async_queue_unused_ptr--; return wsgi_req; } void async_reset_request(struct wsgi_request *wsgi_req) { if (wsgi_req->async_timeout) { uwsgi_del_rb_timer(uwsgi.rb_async_timeouts, wsgi_req->async_timeout); free(wsgi_req->async_timeout); wsgi_req->async_timeout = NULL; } struct uwsgi_async_fd *uaf = wsgi_req->waiting_fds; while (uaf) { event_queue_del_fd(uwsgi.async_queue, uaf->fd, uaf->event); uwsgi.async_waiting_fd_table[uaf->fd] = NULL; struct uwsgi_async_fd *current_uaf = uaf; uaf = current_uaf->next; free(current_uaf); } wsgi_req->waiting_fds = NULL; } static void async_expire_timeouts(uint64_t now) { struct wsgi_request *wsgi_req; struct uwsgi_rb_timer *urbt; for (;;) { urbt = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts, NULL); if (urbt == NULL) return; if (urbt->value <= now) { wsgi_req = (struct wsgi_request *) urbt->data; // timeout expired wsgi_req->async_timed_out = 1; // reset the request async_reset_request(wsgi_req); // push it in the runqueue runqueue_push(wsgi_req); continue; } break; } } int async_add_fd_read(struct wsgi_request *wsgi_req, int fd, int timeout) { if (uwsgi.async < 2 || !uwsgi.async_waiting_fd_table){ uwsgi_log_verbose("ASYNC call without async mode !!!\n"); return -1; } struct uwsgi_async_fd *last_uad = NULL, *uad = wsgi_req->waiting_fds; if (fd < 0) return -1; // find last slot while (uad) { last_uad = uad; uad = uad->next; } uad = uwsgi_malloc(sizeof(struct uwsgi_async_fd)); uad->fd = fd; uad->event = event_queue_read(); uad->prev = last_uad; uad->next = NULL; if (last_uad) { last_uad->next = uad; } else { wsgi_req->waiting_fds = uad; } if (timeout > 0) { async_add_timeout(wsgi_req, timeout); } uwsgi.async_waiting_fd_table[fd] = wsgi_req; wsgi_req->async_force_again = 1; return event_queue_add_fd_read(uwsgi.async_queue, fd); } static int async_wait_fd_read(int fd, int timeout) { struct wsgi_request *wsgi_req = current_wsgi_req(); wsgi_req->async_ready_fd = 0; if (async_add_fd_read(wsgi_req, fd, timeout)) { return -1; } if (uwsgi.schedule_to_main) { uwsgi.schedule_to_main(wsgi_req); } if (wsgi_req->async_timed_out) { wsgi_req->async_timed_out = 0; return 0; } return 1; } static int async_wait_fd_read2(int fd0, int fd1, int timeout, int *fd) { struct wsgi_request *wsgi_req = current_wsgi_req(); wsgi_req->async_ready_fd = 0; if (async_add_fd_read(wsgi_req, fd0, timeout)) { return -1; } if (async_add_fd_read(wsgi_req, fd1, timeout)) { // reset already registered fd async_reset_request(wsgi_req); return -1; } if (uwsgi.schedule_to_main) { uwsgi.schedule_to_main(wsgi_req); } if (wsgi_req->async_timed_out) { wsgi_req->async_timed_out = 0; return 0; } if (wsgi_req->async_ready_fd) { *fd = wsgi_req->async_last_ready_fd; return 1; } return -1; } void async_add_timeout(struct wsgi_request *wsgi_req, int timeout) { if (uwsgi.async < 2 || !uwsgi.rb_async_timeouts) { uwsgi_log_verbose("ASYNC call without async mode !!!\n"); return; } wsgi_req->async_ready_fd = 0; if (timeout > 0 && wsgi_req->async_timeout == NULL) { wsgi_req->async_timeout = uwsgi_add_rb_timer(uwsgi.rb_async_timeouts, uwsgi_now() + timeout, wsgi_req); } } int async_add_fd_write(struct wsgi_request *wsgi_req, int fd, int timeout) { if (uwsgi.async < 2 || !uwsgi.async_waiting_fd_table) { uwsgi_log_verbose("ASYNC call without async mode !!!\n"); return -1; } struct uwsgi_async_fd *last_uad = NULL, *uad = wsgi_req->waiting_fds; if (fd < 0) return -1; // find last slot while (uad) { last_uad = uad; uad = uad->next; } uad = uwsgi_malloc(sizeof(struct uwsgi_async_fd)); uad->fd = fd; uad->event = event_queue_write(); uad->prev = last_uad; uad->next = NULL; if (last_uad) { last_uad->next = uad; } else { wsgi_req->waiting_fds = uad; } if (timeout > 0) { async_add_timeout(wsgi_req, timeout); } uwsgi.async_waiting_fd_table[fd] = wsgi_req; wsgi_req->async_force_again = 1; return event_queue_add_fd_write(uwsgi.async_queue, fd); } static int async_wait_fd_write(int fd, int timeout) { struct wsgi_request *wsgi_req = current_wsgi_req(); wsgi_req->async_ready_fd = 0; if (async_add_fd_write(wsgi_req, fd, timeout)) { return -1; } if (uwsgi.schedule_to_main) { uwsgi.schedule_to_main(wsgi_req); } if (wsgi_req->async_timed_out) { wsgi_req->async_timed_out = 0; return 0; } return 1; } void async_schedule_to_req(void) { #ifdef UWSGI_ROUTING if (uwsgi_apply_routes(uwsgi.wsgi_req) == UWSGI_ROUTE_BREAK) { goto end; } // a trick to avoid calling routes again uwsgi.wsgi_req->is_routing = 1; #endif uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req); if (uwsgi.wsgi_req->async_status <= UWSGI_OK) goto end; if (uwsgi.schedule_to_main) { uwsgi.schedule_to_main(uwsgi.wsgi_req); } return; end: async_reset_request(uwsgi.wsgi_req); uwsgi_close_request(uwsgi.wsgi_req); uwsgi.wsgi_req->async_status = UWSGI_OK; uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req; } void async_schedule_to_req_green(void) { struct wsgi_request *wsgi_req = uwsgi.wsgi_req; #ifdef UWSGI_ROUTING if (uwsgi_apply_routes(wsgi_req) == UWSGI_ROUTE_BREAK) { goto end; } #endif for(;;) { wsgi_req->async_status = uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req); if (wsgi_req->async_status <= UWSGI_OK) { break; } wsgi_req->switches++; if (uwsgi.schedule_fix) { uwsgi.schedule_fix(wsgi_req); } // switch after each yield if (uwsgi.schedule_to_main) uwsgi.schedule_to_main(wsgi_req); } #ifdef UWSGI_ROUTING end: #endif // re-set the global state uwsgi.wsgi_req = wsgi_req; async_reset_request(wsgi_req); uwsgi_close_request(wsgi_req); // re-set the global state (routing could have changed it) uwsgi.wsgi_req = wsgi_req; wsgi_req->async_status = UWSGI_OK; uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = wsgi_req; } static int uwsgi_async_wait_milliseconds_hook(int timeout) { struct wsgi_request *wsgi_req = current_wsgi_req(); timeout = timeout / 1000; if (!timeout) timeout = 1; async_add_timeout(wsgi_req, timeout); wsgi_req->async_force_again = 1; if (uwsgi.schedule_to_main) { uwsgi.schedule_to_main(wsgi_req); } if (wsgi_req->async_timed_out) { wsgi_req->async_timed_out = 0; return 0; } return -1; } void async_loop() { if (uwsgi.async < 2) { uwsgi_log("the async loop engine requires async mode (--async )\n"); exit(1); } int interesting_fd, i; struct uwsgi_rb_timer *min_timeout; int timeout; int is_a_new_connection; int proto_parser_status; uint64_t now; struct uwsgi_async_request *current_request = NULL; void *events = event_queue_alloc(64); struct uwsgi_socket *uwsgi_sock; uwsgi_async_init(); uwsgi.async_runqueue = NULL; uwsgi.wait_write_hook = async_wait_fd_write; uwsgi.wait_read_hook = async_wait_fd_read; uwsgi.wait_read2_hook = async_wait_fd_read2; uwsgi.wait_milliseconds_hook = uwsgi_async_wait_milliseconds_hook; if (uwsgi.signal_socket > -1) { event_queue_add_fd_read(uwsgi.async_queue, uwsgi.signal_socket); event_queue_add_fd_read(uwsgi.async_queue, uwsgi.my_signal_socket); } // set a default request manager if (!uwsgi.schedule_to_req) uwsgi.schedule_to_req = async_schedule_to_req; if (!uwsgi.schedule_to_main) { uwsgi_log("*** DANGER *** async mode without coroutine/greenthread engine loaded !!!\n"); } while (uwsgi.workers[uwsgi.mywid].manage_next_request) { now = (uint64_t) uwsgi_now(); if (uwsgi.async_runqueue) { timeout = 0; } else { min_timeout = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts, NULL); if (min_timeout) { timeout = min_timeout->value - now; if (timeout <= 0) { async_expire_timeouts(now); timeout = 0; } } else { timeout = -1; } } uwsgi.async_nevents = event_queue_wait_multi(uwsgi.async_queue, timeout, events, 64); now = (uint64_t) uwsgi_now(); // timeout ??? if (uwsgi.async_nevents == 0) { async_expire_timeouts(now); } for (i = 0; i < uwsgi.async_nevents; i++) { // manage events interesting_fd = event_queue_interesting_fd(events, i); // signals are executed in the main stack... in the future we could have dedicated stacks for them if (uwsgi.signal_socket > -1 && (interesting_fd == uwsgi.signal_socket || interesting_fd == uwsgi.my_signal_socket)) { uwsgi_receive_signal(interesting_fd, "worker", uwsgi.mywid); continue; } is_a_new_connection = 0; // new request coming in ? uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (interesting_fd == uwsgi_sock->fd) { is_a_new_connection = 1; uwsgi.wsgi_req = find_first_available_wsgi_req(); if (uwsgi.wsgi_req == NULL) { uwsgi_async_queue_is_full((time_t)now); break; } // on error re-insert the request in the queue wsgi_req_setup(uwsgi.wsgi_req, uwsgi.wsgi_req->async_id, uwsgi_sock); if (wsgi_req_simple_accept(uwsgi.wsgi_req, interesting_fd)) { uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req; break; } if (wsgi_req_async_recv(uwsgi.wsgi_req)) { uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req; break; } // by default the core is in UWSGI_AGAIN mode uwsgi.wsgi_req->async_status = UWSGI_AGAIN; // some protocol (like zeromq) do not need additional parsing, just push it in the runqueue if (uwsgi.wsgi_req->do_not_add_to_async_queue) { runqueue_push(uwsgi.wsgi_req); } break; } uwsgi_sock = uwsgi_sock->next; } if (!is_a_new_connection) { // proto event uwsgi.wsgi_req = find_wsgi_req_proto_by_fd(interesting_fd); if (uwsgi.wsgi_req) { proto_parser_status = uwsgi.wsgi_req->socket->proto(uwsgi.wsgi_req); // reset timeout async_reset_request(uwsgi.wsgi_req); // parsing complete if (!proto_parser_status) { // remove fd from event poll and fd proto table uwsgi.async_proto_fd_table[interesting_fd] = NULL; event_queue_del_fd(uwsgi.async_queue, interesting_fd, event_queue_read()); // put request in the runqueue (set it as UWSGI_OK to signal the first run) uwsgi.wsgi_req->async_status = UWSGI_OK; runqueue_push(uwsgi.wsgi_req); continue; } else if (proto_parser_status < 0) { uwsgi.async_proto_fd_table[interesting_fd] = NULL; close(interesting_fd); uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req; continue; } // re-add timer async_add_timeout(uwsgi.wsgi_req, uwsgi.socket_timeout); continue; } // app-registered event uwsgi.wsgi_req = find_wsgi_req_by_fd(interesting_fd); // unknown fd, remove it (for safety) if (uwsgi.wsgi_req == NULL) { close(interesting_fd); continue; } // remove all the fd monitors and timeout async_reset_request(uwsgi.wsgi_req); uwsgi.wsgi_req->async_ready_fd = 1; uwsgi.wsgi_req->async_last_ready_fd = interesting_fd; // put the request in the runqueue again runqueue_push(uwsgi.wsgi_req); } } // event queue managed, give cpu to runqueue current_request = uwsgi.async_runqueue; while(current_request) { // current_request could be nulled on error/end of request struct uwsgi_async_request *next_request = current_request->next; uwsgi.wsgi_req = current_request->wsgi_req; uwsgi.schedule_to_req(); uwsgi.wsgi_req->switches++; // request ended ? if (uwsgi.wsgi_req->async_status <= UWSGI_OK || uwsgi.wsgi_req->waiting_fds || uwsgi.wsgi_req->async_timeout) { // remove from the runqueue runqueue_remove(current_request); } current_request = next_request; } } } uwsgi-2.0.29/core/buffer.c000066400000000000000000000276211477626554400153430ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; struct uwsgi_buffer *uwsgi_buffer_new(size_t len) { #ifdef UWSGI_DEBUG_BUFFER uwsgi_log("[uwsgi-buffer] allocating a new buffer of %llu\n", (unsigned long long) len); #endif struct uwsgi_buffer *ub = uwsgi_calloc(sizeof(struct uwsgi_buffer)); if (len) { ub->buf = uwsgi_malloc(len); ub->len = len; } return ub; } int uwsgi_buffer_fix(struct uwsgi_buffer *ub, size_t len) { if (ub->limit > 0 && len > ub->limit) return -1; if (ub->len < len) { char *new_buf = realloc(ub->buf, len); if (!new_buf) { uwsgi_error("uwsgi_buffer_fix()"); return -1; } ub->buf = new_buf; ub->len = len; } return 0; } int uwsgi_buffer_ensure(struct uwsgi_buffer *ub, size_t len) { size_t remains = ub->len - ub->pos; if (remains < len) { size_t new_len = ub->len + (len - remains); if (ub->limit > 0 && new_len > ub->limit) { new_len = ub->limit; if (new_len == ub->len) return -1; } char *new_buf = realloc(ub->buf, new_len); if (!new_buf) { uwsgi_error("uwsgi_buffer_ensure()"); return -1; } ub->buf = new_buf; ub->len = new_len; } return 0; } int uwsgi_buffer_insert(struct uwsgi_buffer *ub, size_t pos, char *buf, size_t len) { size_t to_move = (ub->pos-pos); if (uwsgi_buffer_ensure(ub, len)) return -1; memmove(ub->buf+pos+len, ub->buf+pos, to_move); memcpy(ub->buf+pos, buf, len); ub->pos += len; return 0; } int uwsgi_buffer_insert_chunked(struct uwsgi_buffer *ub, size_t pos, size_t len) { // 0xFFFFFFFFFFFFFFFF\r\n\0 char chunked[19]; int ret = snprintf(chunked, 19, "%X\r\n", (unsigned int) len); if (ret <= 0 || ret >= 19) { return -1; } return uwsgi_buffer_insert(ub, pos, chunked, ret); } int uwsgi_buffer_append_chunked(struct uwsgi_buffer *ub, size_t len) { // 0xFFFFFFFFFFFFFFFF\r\n\0 char chunked[19]; int ret = snprintf(chunked, 19, "%X\r\n", (unsigned int) len); if (ret <= 0 || ret >= 19) { return -1; } return uwsgi_buffer_append(ub, chunked, ret); } int uwsgi_buffer_decapitate(struct uwsgi_buffer *ub, size_t len) { if (len > ub->pos) return -1; memmove(ub->buf, ub->buf + len, ub->pos-len); ub->pos = ub->pos-len; return 0; } int uwsgi_buffer_byte(struct uwsgi_buffer *ub, char byte) { return uwsgi_buffer_append(ub, &byte, 1); } int uwsgi_buffer_u8(struct uwsgi_buffer *ub, uint8_t u8) { return uwsgi_buffer_append(ub, (char *) &u8, 1); } int uwsgi_buffer_append(struct uwsgi_buffer *ub, char *buf, size_t len) { size_t remains = ub->len - ub->pos; if (len > remains) { size_t chunk_size = UMAX(len, (size_t) uwsgi.page_size); if (ub->limit > 0 && ub->len + chunk_size > ub->limit) { // retry with another minimal size if (len < (size_t) uwsgi.page_size) { chunk_size = len; } if (ub->len + chunk_size > ub->limit) return -1; } char *new_buf = realloc(ub->buf, ub->len + chunk_size); if (!new_buf) { uwsgi_error("uwsgi_buffer_append()"); return -1; } ub->buf = new_buf; ub->len += chunk_size; } memcpy(ub->buf + ub->pos, buf, len); ub->pos += len; return 0; } int uwsgi_buffer_append_json(struct uwsgi_buffer *ub, char *buf, size_t len) { // need to escape \ and " size_t i; for(i=0;i> 8) & 0xff); return uwsgi_buffer_append(ub, (char *) buf, 2); } int uwsgi_buffer_u16be(struct uwsgi_buffer *ub, uint16_t num) { uint8_t buf[2]; buf[1] = (uint8_t) (num & 0xff); buf[0] = (uint8_t) ((num >> 8) & 0xff); return uwsgi_buffer_append(ub, (char *) buf, 2); } int uwsgi_buffer_u24be(struct uwsgi_buffer *ub, uint32_t num) { uint8_t buf[3]; buf[2] = (uint8_t) (num & 0xff); buf[1] = (uint8_t) ((num >> 8) & 0xff); buf[0] = (uint8_t) ((num >> 16) & 0xff); return uwsgi_buffer_append(ub, (char *) buf, 3); } int uwsgi_buffer_u32be(struct uwsgi_buffer *ub, uint32_t num) { uint8_t buf[4]; buf[3] = (uint8_t) (num & 0xff); buf[2] = (uint8_t) ((num >> 8) & 0xff); buf[1] = (uint8_t) ((num >> 16) & 0xff); buf[0] = (uint8_t) ((num >> 24) & 0xff); return uwsgi_buffer_append(ub, (char *) buf, 4); } int uwsgi_buffer_f32be(struct uwsgi_buffer *ub, float num) { uint8_t buf[4]; uint32_t *pnum = (uint32_t *) # buf[3] = (uint8_t) (*pnum & 0xff); buf[2] = (uint8_t) ((*pnum >> 8) & 0xff); buf[1] = (uint8_t) ((*pnum >> 16) & 0xff); buf[0] = (uint8_t) ((*pnum >> 24) & 0xff); return uwsgi_buffer_append(ub, (char *) buf, 4); } int uwsgi_buffer_u32le(struct uwsgi_buffer *ub, uint32_t num) { uint8_t buf[4]; buf[0] = (uint8_t) (num & 0xff); buf[1] = (uint8_t) ((num >> 8) & 0xff); buf[2] = (uint8_t) ((num >> 16) & 0xff); buf[3] = (uint8_t) ((num >> 24) & 0xff); return uwsgi_buffer_append(ub, (char *) buf, 4); } int uwsgi_buffer_u64be(struct uwsgi_buffer *ub, uint64_t num) { uint8_t buf[8]; buf[7] = (uint8_t) (num & 0xff); buf[6] = (uint8_t) ((num >> 8) & 0xff); buf[5] = (uint8_t) ((num >> 16) & 0xff); buf[4] = (uint8_t) ((num >> 24) & 0xff); buf[3] = (uint8_t) ((num >> 32) & 0xff); buf[2] = (uint8_t) ((num >> 40) & 0xff); buf[1] = (uint8_t) ((num >> 48) & 0xff); buf[0] = (uint8_t) ((num >> 56) & 0xff); return uwsgi_buffer_append(ub, (char *) buf, 8); } int uwsgi_buffer_u64le(struct uwsgi_buffer *ub, uint64_t num) { uint8_t buf[8]; buf[0] = (uint8_t) (num & 0xff); buf[1] = (uint8_t) ((num >> 8) & 0xff); buf[2] = (uint8_t) ((num >> 16) & 0xff); buf[3] = (uint8_t) ((num >> 24) & 0xff); buf[4] = (uint8_t) ((num >> 32) & 0xff); buf[5] = (uint8_t) ((num >> 40) & 0xff); buf[6] = (uint8_t) ((num >> 48) & 0xff); buf[7] = (uint8_t) ((num >> 56) & 0xff); return uwsgi_buffer_append(ub, (char *) buf, 8); } int uwsgi_buffer_f64be(struct uwsgi_buffer *ub, double num) { uint8_t buf[8]; uint64_t *pnum = (uint64_t *) # buf[7] = (uint8_t) (*pnum & 0xff); buf[6] = (uint8_t) ((*pnum >> 8) & 0xff); buf[5] = (uint8_t) ((*pnum >> 16) & 0xff); buf[4] = (uint8_t) ((*pnum >> 24) & 0xff); buf[3] = (uint8_t) ((*pnum >> 32) & 0xff); buf[2] = (uint8_t) ((*pnum >> 40) & 0xff); buf[1] = (uint8_t) ((*pnum >> 48) & 0xff); buf[0] = (uint8_t) ((*pnum >> 56) & 0xff); return uwsgi_buffer_append(ub, (char *) buf, 8); } int uwsgi_buffer_append_ipv4(struct uwsgi_buffer *ub, void *addr) { char ip[INET_ADDRSTRLEN]; if (!inet_ntop(AF_INET, addr, ip, INET_ADDRSTRLEN)) { uwsgi_error("uwsgi_buffer_append_ipv4() -> inet_ntop()"); return -1; } return uwsgi_buffer_append(ub, ip, strlen(ip)); } int uwsgi_buffer_num64(struct uwsgi_buffer *ub, int64_t num) { char buf[sizeof(UMAX64_STR)+1]; int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%lld", (long long) num); if (ret <= 0 || ret >= (int) (sizeof(UMAX64_STR)+1)) { return -1; } return uwsgi_buffer_append(ub, buf, ret); } int uwsgi_buffer_append_keyval(struct uwsgi_buffer *ub, char *key, uint16_t keylen, char *val, uint16_t vallen) { if (uwsgi_buffer_u16le(ub, keylen)) return -1; if (uwsgi_buffer_append(ub, key, keylen)) return -1; if (uwsgi_buffer_u16le(ub, vallen)) return -1; return uwsgi_buffer_append(ub, val, vallen); } int uwsgi_buffer_append_keyval32(struct uwsgi_buffer *ub, char *key, uint32_t keylen, char *val, uint32_t vallen) { if (uwsgi_buffer_u32be(ub, keylen)) return -1; if (uwsgi_buffer_append(ub, key, keylen)) return -1; if (uwsgi_buffer_u32be(ub, vallen)) return -1; return uwsgi_buffer_append(ub, val, vallen); } int uwsgi_buffer_append_keynum(struct uwsgi_buffer *ub, char *key, uint16_t keylen, int64_t num) { char buf[sizeof(UMAX64_STR)+1]; int ret = snprintf(buf, (sizeof(UMAX64_STR)+1), "%lld", (long long) num); if (ret <= 0 || ret >= (int) (sizeof(UMAX64_STR)+1)) { return -1; } if (uwsgi_buffer_u16le(ub, keylen)) return -1; if (uwsgi_buffer_append(ub, key, keylen)) return -1; if (uwsgi_buffer_u16le(ub, ret)) return -1; return uwsgi_buffer_append(ub, buf, ret); } int uwsgi_buffer_append_valnum(struct uwsgi_buffer *ub, int64_t num) { char buf[sizeof(UMAX64_STR)+1]; int ret = snprintf(buf, (sizeof(UMAX64_STR)+1), "%lld", (long long) num); if (ret <= 0 || ret >= (int) (sizeof(UMAX64_STR)+1)) { return -1; } if (uwsgi_buffer_u16le(ub, ret)) return -1; return uwsgi_buffer_append(ub, buf, ret); } int uwsgi_buffer_append_keyipv4(struct uwsgi_buffer *ub, char *key, uint16_t keylen, void *addr) { if (uwsgi_buffer_u16le(ub, keylen)) return -1; if (uwsgi_buffer_append(ub, key, keylen)) return -1; if (uwsgi_buffer_u16le(ub, 15)) return -1; char *ptr = ub->buf + (ub->pos - 2); if (uwsgi_buffer_append_ipv4(ub, addr)) return -1; // fix the size *ptr = ((ub->buf+ub->pos) - (ptr+2)); return 0; } int uwsgi_buffer_append_base64(struct uwsgi_buffer *ub, char *s, size_t len) { size_t b64_len = 0; char *b64 = uwsgi_base64_encode(s, len, &b64_len); if (!b64) return -1; int ret = uwsgi_buffer_append(ub, b64, b64_len); free(b64); return ret; } void uwsgi_buffer_destroy(struct uwsgi_buffer *ub) { #ifdef UWSGI_DEBUG_BUFFER uwsgi_log("[uwsgi-buffer] destroying buffer of %llu bytes\n", (unsigned long long) ub->len); if (ub->freed) { uwsgi_log("[uwsgi-buffer][BUG] buffer at %p already destroyed !!!\n", ub); } ub->freed = 1; #endif if (ub->buf) free(ub->buf); free(ub); } ssize_t uwsgi_buffer_write_simple(struct wsgi_request *wsgi_req, struct uwsgi_buffer *ub) { size_t remains = ub->pos; while(remains) { ssize_t len = write(wsgi_req->fd, ub->buf + (ub->pos - remains), remains); if (len <= 0) { return len; } remains -= len; } return ub->pos; } int uwsgi_buffer_send(struct uwsgi_buffer *ub, int fd) { size_t remains = ub->pos; char *ptr = ub->buf; while (remains > 0) { int ret = uwsgi_waitfd_write(fd, uwsgi.socket_timeout); if (ret > 0) { ssize_t len = write(fd, ptr, remains); if (len > 0) { ptr += len; remains -= len; } else if (len == 0) { return -1; } else { uwsgi_error("uwsgi_buffer_send()"); return -1; } } else if (ret == 0) { uwsgi_log("timeout while sending buffer !!!\n"); return -1; } else { return -1; } } return 0; } int uwsgi_buffer_set_uh(struct uwsgi_buffer *ub, uint8_t modifier1, uint8_t modifier2) { if (ub->pos < 4) return -1; ub->buf[0] = modifier1; ub->buf[1] = (uint8_t) ((ub->pos - 4) & 0xff); ub->buf[2] = (uint8_t) (((ub->pos - 4) >> 8) & 0xff); ub->buf[3] = modifier2; return 0; } struct uwsgi_buffer *uwsgi_buffer_from_file(char *filename) { struct stat st; int fd = open(filename, O_RDONLY); if (fd < 0) { return NULL; } if (fstat(fd, &st)) { close(fd); return NULL; } struct uwsgi_buffer *ub = uwsgi_buffer_new(st.st_size); ssize_t len = read(fd, ub->buf, st.st_size); close(fd); if (len != st.st_size) { uwsgi_buffer_destroy(ub); return NULL; } ub->pos = len; return ub; } void uwsgi_buffer_map(struct uwsgi_buffer *ub, char *buf, size_t len) { if (ub->buf) { free(ub->buf); } ub->buf = buf; ub->pos = len; ub->len = len; } uwsgi-2.0.29/core/cache.c000066400000000000000000001763271477626554400151450ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; #define cache_item(x) (struct uwsgi_cache_item *) (((char *)uc->items) + ((sizeof(struct uwsgi_cache_item)+uc->keysize) * x)) // block bitmap manager /* how the cache bitmap works: a bitmap is a shared memory area allocated when requested by the user with --cache2 Each block maps to a bit in the bitmap. If the corresponding bit is cleared the block is usable otherwise the block scanner will search for the next one. Object can be placed only on consecutive blocks, fragmentation is not allowed. To increase the scan performance, a 64bit pointer to the last used bit + 1 is hold To search for free blocks you run uint64_t uwsgi_cache_find_free_block(struct uwsgi_cache *uc, size_t need) where need is the size of the object */ static void cache_full(struct uwsgi_cache *uc) { uint64_t i; int clear_cache = uc->clear_on_full; if (!uc->ignore_full) { if (uc->purge_lru) uwsgi_log("LRU item will be purged from cache \"%s\"\n", uc->name); else uwsgi_log("*** DANGER cache \"%s\" is FULL !!! ***\n", uc->name); } uc->full++; if (uc->purge_lru && uc->lru_head) uwsgi_cache_del2(uc, NULL, 0, uc->lru_head, UWSGI_CACHE_FLAG_LOCAL); // we do not need locking here ! if (uc->sweep_on_full) { uint64_t removed = 0; uint64_t now = (uint64_t) uwsgi_now(); if (uc->next_scan <= now) { uc->next_scan = now + uc->sweep_on_full; for (i = 1; i < uc->max_items; i++) { struct uwsgi_cache_item *uci = cache_item(i); if (uci->expires > 0 && uci->expires <= now) { if (!uwsgi_cache_del2(uc, NULL, 0, i, 0)) { removed++; } } } } if (removed) { clear_cache = 0; } } if (clear_cache) { for (i = 1; i < uc->max_items; i++) { uwsgi_cache_del2(uc, NULL, 0, i, 0); } } } static uint64_t uwsgi_cache_find_free_blocks(struct uwsgi_cache *uc, uint64_t need) { // how many blocks we need ? uint64_t needed_blocks = need/uc->blocksize; if (need % uc->blocksize > 0) needed_blocks++; // which is the first free bit? uint64_t bitmap_byte = 0; uint8_t bitmap_bit = 0; if (uc->blocks_bitmap_pos > 0) { bitmap_byte = uc->blocks_bitmap_pos/8; bitmap_bit = uc->blocks_bitmap_pos % 8; } // ok we now have the start position, let's search for contiguous blocks uint8_t *bitmap = uc->blocks_bitmap; uint64_t base = 0xffffffffffffffffLLU; uint8_t base_bit = 0; uint64_t j; uint64_t found = 0; uint64_t need_to_scan = uc->blocks_bitmap_size; // we make an addition round for the corner case of a single byte map not starting from 0 if (bitmap_bit > 0) need_to_scan++; j = bitmap_byte; //uwsgi_log("start scanning %llu bytes starting from %llu need: %llu\n", (unsigned long long) need_to_scan, (unsigned long long) bitmap_byte, (unsigned long long) needed_blocks); while(need_to_scan) { uint8_t num = bitmap[j]; uint8_t i; uint8_t bit_pos = 0; if (j == bitmap_byte) { i = 1 << (7-bitmap_bit); bit_pos = bitmap_bit; } else { i = 1 <<7; } while(i > 0) { // used block if (num & i) { found = 0; base = 0xffffffffffffffffLLU; base_bit = 0; } // free block else { if (base == 0xffffffffffffffffLLU ) { base = j; base_bit = bit_pos; } found++; if (found == needed_blocks) { #ifdef UWSGI_DEBUG printf("found %llu consecutive bit starting from byte %llu\n", (unsigned long long) found, (unsigned long long) base); #endif return ((base*8) + base_bit); } } i >>= 1; bit_pos++; } j++; need_to_scan--; // check for overlap (that is not supported) if (j >= uc->blocks_bitmap_size) { j = 0; found = 0; base = 0xffffffffffffffffLLU; base_bit = 0; // we use bitmap_bit only at the first round bitmap_bit = 0; } } // no more free blocks return 0xffffffffffffffffLLU; } static uint64_t cache_mark_blocks(struct uwsgi_cache *uc, uint64_t index, uint64_t len) { uint64_t needed_blocks = len/uc->blocksize; if (len % uc->blocksize > 0) needed_blocks++; uint64_t first_byte = index/8; uint8_t first_byte_bit = index % 8; // offset starts with 0, so actual last bit is index + needed_blocks - 1 uint64_t last_byte = (index + needed_blocks - 1) / 8; uint8_t last_byte_bit = (index + needed_blocks - 1) % 8; uint64_t needed_bytes = (last_byte - first_byte) + 1; //uwsgi_log("%llu %u %llu %u\n", first_byte, first_byte_bit, last_byte, last_byte_bit); uint8_t mask = 0xff >> first_byte_bit; if (needed_bytes == 1) { // kinda hacky, but it does the job mask >>= (7 - last_byte_bit); mask <<= (7 - last_byte_bit); } uc->blocks_bitmap[first_byte] |= mask; if (needed_bytes > 1) { mask = 0xff << (7 - last_byte_bit); uc->blocks_bitmap[last_byte] |= mask; } if (needed_bytes > 2) { uint8_t *ptr = &uc->blocks_bitmap[first_byte+1]; memset(ptr, 0xff, needed_bytes-2); } return needed_blocks; } static void cache_unmark_blocks(struct uwsgi_cache *uc, uint64_t index, uint64_t len) { uint64_t needed_blocks = len/uc->blocksize; if (len % uc->blocksize > 0) needed_blocks++; uint64_t first_byte = index/8; uint8_t first_byte_bit = index % 8; // offset starts with 0, so actual last bit is index + needed_blocks - 1 uint64_t last_byte = (index + needed_blocks - 1)/8; uint8_t last_byte_bit = (index + needed_blocks - 1) % 8; uint64_t needed_bytes = (last_byte - first_byte) + 1; uint8_t mask = 0xff >> first_byte_bit; if (needed_bytes == 1) { // kinda hacky, but it does the job mask >>= (7 - last_byte_bit); mask <<= (7 - last_byte_bit); } // here we use AND (0+0 = 0 | 1+0 = 0 | 0+1 = 0| 1+1 = 1) // 0 in mask means "unmark", 1 in mask means "do not change" // so we need to invert the mask uc->blocks_bitmap[first_byte] &= ~mask; if (needed_bytes > 1) { mask = 0xff << (7 - last_byte_bit); uc->blocks_bitmap[last_byte] &= ~mask; } if (needed_bytes > 2) { uint8_t *ptr = &uc->blocks_bitmap[first_byte+1]; memset(ptr, 0, needed_bytes-2); } } static void cache_send_udp_command(struct uwsgi_cache *, char *, uint16_t, char *, uint16_t, uint64_t, uint8_t); static void cache_sync_hook(char *k, uint16_t kl, char *v, uint16_t vl, void *data) { struct uwsgi_cache *uc = (struct uwsgi_cache *) data; if (!uwsgi_strncmp(k, kl, "items", 5)) { size_t num = uwsgi_str_num(v, vl); if (num != uc->max_items) { uwsgi_log("[cache-sync] invalid cache size, expected %llu received %llu\n", (unsigned long long) uc->max_items, (unsigned long long) num); exit(1); } } if (!uwsgi_strncmp(k, kl, "blocksize", 9)) { size_t num = uwsgi_str_num(v, vl); if (num != uc->blocksize) { uwsgi_log("[cache-sync] invalid cache block size, expected %llu received %llu\n", (unsigned long long) uc->blocksize, (unsigned long long) num); exit(1); } } } static void uwsgi_cache_add_items(struct uwsgi_cache *uc) { struct uwsgi_string_list *usl = uwsgi.add_cache_item; while(usl) { char *space = strchr(usl->value, ' '); char *key = usl->value; uint16_t key_len; if (space) { // need to skip ? if (uwsgi_strncmp(uc->name, uc->name_len, usl->value, space-usl->value)) { goto next; } key = space+1; } char *value = strchr(key, '='); if (!value) { uwsgi_log("[cache] unable to store item %s\n", usl->value); goto next; } key_len = value - key; value++; uint64_t len = (usl->value + usl->len) - value; uwsgi_wlock(uc->lock); if (!uwsgi_cache_set2(uc, key, key_len, value, len, 0, 0)) { uwsgi_log("[cache] stored \"%.*s\" in \"%s\"\n", key_len, key, uc->name); } else { uwsgi_log("[cache-error] unable to store \"%.*s\" in \"%s\"\n", key_len, key, uc->name); } uwsgi_rwunlock(uc->lock); next: usl = usl->next; } } static void uwsgi_cache_load_files(struct uwsgi_cache *uc) { struct uwsgi_string_list *usl = uwsgi.load_file_in_cache; while(usl) { size_t len = 0; char *value = NULL; char *key = usl->value; uint16_t key_len = usl->len; char *space = strchr(usl->value, ' '); if (space) { // need to skip ? if (uwsgi_strncmp(uc->name, uc->name_len, usl->value, space-usl->value)) { goto next; } key = space+1; key_len = usl->len - ((space-usl->value)+1); } value = uwsgi_open_and_read(key, &len, 0, NULL); if (value) { uwsgi_wlock(uc->lock); if (!uwsgi_cache_set2(uc, key, key_len, value, len, 0, 0)) { uwsgi_log("[cache] stored \"%.*s\" in \"%s\"\n", key_len, key, uc->name); } else { uwsgi_log("[cache-error] unable to store \"%.*s\" in \"%s\"\n", key_len, key, uc->name); } uwsgi_rwunlock(uc->lock); free(value); } else { uwsgi_log("[cache-error] unable to read file \"%.*s\"\n", key_len, key); } next: usl = usl->next; } #ifdef UWSGI_ZLIB usl = uwsgi.load_file_in_cache_gzip; while(usl) { size_t len = 0; char *value = NULL; char *key = usl->value; uint16_t key_len = usl->len; char *space = strchr(usl->value, ' '); if (space) { // need to skip ? if (uwsgi_strncmp(uc->name, uc->name_len, usl->value, space-usl->value)) { goto next2; } key = space+1; key_len = usl->len - ((space-usl->value)+1); } value = uwsgi_open_and_read(key, &len, 0, NULL); if (value) { struct uwsgi_buffer *gzipped = uwsgi_gzip(value, len); if (gzipped) { uwsgi_wlock(uc->lock); if (!uwsgi_cache_set2(uc, key, key_len, gzipped->buf, gzipped->len, 0, 0)) { uwsgi_log("[cache-gzip] stored \"%.*s\" in \"%s\"\n", key_len, key, uc->name); } uwsgi_rwunlock(uc->lock); uwsgi_buffer_destroy(gzipped); } free(value); } next2: usl = usl->next; } #endif } void uwsgi_cache_init(struct uwsgi_cache *uc) { uc->hashtable = uwsgi_calloc_shared(sizeof(uint64_t) * uc->hashsize); uc->unused_blocks_stack = uwsgi_calloc_shared(sizeof(uint64_t) * uc->max_items); uc->unused_blocks_stack_ptr = 0; uc->filesize = ( (sizeof(struct uwsgi_cache_item)+uc->keysize) * uc->max_items) + (uc->blocksize * uc->blocks); uint64_t i; for (i = 1; i < uc->max_items; i++) { uc->unused_blocks_stack_ptr++; uc->unused_blocks_stack[uc->unused_blocks_stack_ptr] = i; } if (uc->use_blocks_bitmap) { uc->blocks_bitmap_size = uc->blocks/8; uint8_t m = uc->blocks % 8; if (m > 0) uc->blocks_bitmap_size++; uc->blocks_bitmap = uwsgi_calloc_shared(uc->blocks_bitmap_size); if (m > 0) { uc->blocks_bitmap[uc->blocks_bitmap_size-1] = 0xff >> m; } } //uwsgi.cache_items = (struct uwsgi_cache_item *) mmap(NULL, sizeof(struct uwsgi_cache_item) * uwsgi.cache_max_items, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); if (uc->store) { int cache_fd; struct stat cst; if (uc->store_delete && !stat(uc->store, &cst) && ((size_t) cst.st_size != uc->filesize || !S_ISREG(cst.st_mode))) { uwsgi_log("Removing invalid cache store file: %s\n", uc->store); if (unlink(uc->store) != 0) { uwsgi_log("Cannot remove invalid cache store file: %s\n", uc->store); exit(1); } } if (stat(uc->store, &cst)) { uwsgi_log("creating a new cache store file: %s\n", uc->store); cache_fd = open(uc->store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); if (cache_fd >= 0) { // fill the caching store if (ftruncate(cache_fd, uc->filesize)) { uwsgi_log("ftruncate()"); exit(1); } } } else { if ((size_t) cst.st_size != uc->filesize || !S_ISREG(cst.st_mode)) { uwsgi_log("invalid cache store file. Please remove it or fix cache blocksize/items to match its size\n"); exit(1); } cache_fd = open(uc->store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); uwsgi_log("recovered cache from backing store file: %s\n", uc->store); } if (cache_fd < 0) { uwsgi_error_open(uc->store); exit(1); } uc->items = (struct uwsgi_cache_item *) mmap(NULL, uc->filesize, PROT_READ | PROT_WRITE, MAP_SHARED, cache_fd, 0); if (uc->items == MAP_FAILED) { uwsgi_error("uwsgi_cache_init()/mmap() [with store]"); exit(1); } uwsgi_cache_fix(uc); close(cache_fd); } else { uc->items = (struct uwsgi_cache_item *) mmap(NULL, uc->filesize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); if (uc->items == MAP_FAILED) { uwsgi_error("uwsgi_cache_init()/mmap()"); exit(1); } uint64_t i; for (i = 0; i < uc->max_items; i++) { // here we only need to clear the item header memset(cache_item(i), 0, sizeof(struct uwsgi_cache_item)); } } uc->data = ((char *)uc->items) + ((sizeof(struct uwsgi_cache_item)+uc->keysize) * uc->max_items); if (uc->name) { // can't free that until shutdown char *lock_name = uwsgi_concat2("cache_", uc->name); uc->lock = uwsgi_rwlock_init(lock_name); } else { uc->lock = uwsgi_rwlock_init("cache"); } uwsgi_log("*** Cache \"%s\" initialized: %lluMB (key: %llu bytes, keys: %llu bytes, data: %llu bytes, bitmap: %llu bytes) preallocated ***\n", uc->name, (unsigned long long) uc->filesize / (1024 * 1024), (unsigned long long) sizeof(struct uwsgi_cache_item)+uc->keysize, (unsigned long long) ((sizeof(struct uwsgi_cache_item)+uc->keysize) * uc->max_items), (unsigned long long) (uc->blocksize * uc->blocks), (unsigned long long) uc->blocks_bitmap_size); uwsgi_cache_setup_nodes(uc); uc->udp_node_socket = socket(AF_INET, SOCK_DGRAM, 0); if (uc->udp_node_socket < 0) { uwsgi_error("[cache-udp-node] socket()"); exit(1); } uwsgi_socket_nb(uc->udp_node_socket); uwsgi_cache_sync_from_nodes(uc); uwsgi_cache_load_files(uc); uwsgi_cache_add_items(uc); } static uint64_t check_lazy(struct uwsgi_cache *uc, struct uwsgi_cache_item *uci, uint64_t slot) { if (!uci->expires || !uc->lazy_expire) return slot; uint64_t now = (uint64_t) uwsgi_now(); // expired ? if (uci->expires <= now) { uwsgi_cache_del2(uc, NULL, 0, slot, UWSGI_CACHE_FLAG_LOCAL); return 0; } return slot; } static uint64_t uwsgi_cache_get_index(struct uwsgi_cache *uc, char *key, uint16_t keylen) { uint32_t hash = uc->hash->func(key, keylen); uint32_t hash_key = hash % uc->hashsize; uint64_t slot = uc->hashtable[hash_key]; // optimization if (slot == 0) return 0; //uwsgi_log("hash_key = %lu slot = %llu\n", hash_key, (unsigned long long) slot); struct uwsgi_cache_item *uci = cache_item(slot); uint64_t rounds = 0; // first round if (uci->hash % uc->hashsize != hash_key) return 0; if (uci->hash != hash) goto cycle; if (uci->keysize != keylen) goto cycle; if (memcmp(uci->key, key, keylen)) goto cycle; return check_lazy(uc, uci, slot); cycle: while (uci->next) { slot = uci->next; uci = cache_item(slot); rounds++; if (rounds > uc->max_items) { uwsgi_log("ALARM !!! cache-loop (and potential deadlock) detected slot = %lu prev = %lu next = %lu\n", slot, uci->prev, uci->next); // terrible case: the whole uWSGI stack can deadlock, leaving only the master alive // if the master is avalable, trigger a brutal reload if (uwsgi.master_process) { kill(uwsgi.workers[0].pid, SIGTERM); } // otherwise kill the current worker (could be pretty useless...) else { exit(1); } } if (uci->hash != hash) continue; if (uci->keysize != keylen) continue; if (!memcmp(uci->key, key, keylen)) { return check_lazy(uc, uci, slot); } } return 0; } uint32_t uwsgi_cache_exists2(struct uwsgi_cache *uc, char *key, uint16_t keylen) { return uwsgi_cache_get_index(uc, key, keylen); } static void lru_remove_item(struct uwsgi_cache *uc, uint64_t index) { struct uwsgi_cache_item *prev, *next, *curr = cache_item(index); if (curr->lru_next) { next = cache_item(curr->lru_next); next->lru_prev = curr->lru_prev; } else uc->lru_tail = curr->lru_prev; if (curr->lru_prev) { prev = cache_item(curr->lru_prev); prev->lru_next = curr->lru_next; } else uc->lru_head = curr->lru_next; } static void lru_add_item(struct uwsgi_cache *uc, uint64_t index) { struct uwsgi_cache_item *prev, *curr = cache_item(index); if (uc->lru_tail) { prev = cache_item(uc->lru_tail); prev->lru_next = index; } else uc->lru_head = index; curr->lru_next = 0; curr->lru_prev = uc->lru_tail; uc->lru_tail = index; } char *uwsgi_cache_get2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_t * valsize) { uint64_t index = uwsgi_cache_get_index(uc, key, keylen); if (index) { struct uwsgi_cache_item *uci = cache_item(index); if (uci->flags & UWSGI_CACHE_FLAG_UNGETTABLE) return NULL; *valsize = uci->valsize; if (uc->purge_lru) { lru_remove_item(uc, index); lru_add_item(uc, index); } uci->hits++; uc->hits++; return uc->data + (uci->first_block * uc->blocksize); } uc->miss++; return NULL; } int64_t uwsgi_cache_num2(struct uwsgi_cache *uc, char *key, uint16_t keylen) { uint64_t index = uwsgi_cache_get_index(uc, key, keylen); if (index) { struct uwsgi_cache_item *uci = cache_item(index); if (uci->flags & UWSGI_CACHE_FLAG_UNGETTABLE) return 0; uci->hits++; uc->hits++; int64_t *num = (int64_t *) (uc->data + (uci->first_block * uc->blocksize)); return *num; } uc->miss++; return 0; } char *uwsgi_cache_get3(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_t * valsize, uint64_t *expires) { uint64_t index = uwsgi_cache_get_index(uc, key, keylen); if (index) { struct uwsgi_cache_item *uci = cache_item(index); if (uci->flags & UWSGI_CACHE_FLAG_UNGETTABLE) return NULL; *valsize = uci->valsize; if (expires) *expires = uci->expires; if (uc->purge_lru) { lru_remove_item(uc, index); lru_add_item(uc, index); } uci->hits++; uc->hits++; return uc->data + (uci->first_block * uc->blocksize); } uc->miss++; return NULL; } char *uwsgi_cache_get4(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_t * valsize, uint64_t *hits) { uint64_t index = uwsgi_cache_get_index(uc, key, keylen); if (index) { struct uwsgi_cache_item *uci = cache_item(index); if (uci->flags & UWSGI_CACHE_FLAG_UNGETTABLE) return NULL; *valsize = uci->valsize; if (hits) *hits = uci->hits; uci->hits++; uc->hits++; return uc->data + (uci->first_block * uc->blocksize); } uc->miss++; return NULL; } int uwsgi_cache_del2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_t index, uint16_t flags) { struct uwsgi_cache_item *uci; int ret = -1; if (!index) index = uwsgi_cache_get_index(uc, key, keylen); if (index) { uci = cache_item(index); if (uci->keysize > 0) { // unmark blocks if (uc->blocks_bitmap) cache_unmark_blocks(uc, uci->first_block, uci->valsize); // put back the block in unused stack uc->unused_blocks_stack_ptr++; uc->unused_blocks_stack[uc->unused_blocks_stack_ptr] = index; // unlink prev and next (if any) if (uci->prev) { struct uwsgi_cache_item *ucii = cache_item(uci->prev); ucii->next = uci->next; } else { // set next as the new entry point (could be 0) uc->hashtable[uci->hash % uc->hashsize] = uci->next; } if (uci->next) { struct uwsgi_cache_item *ucii = cache_item(uci->next); ucii->prev = uci->prev; } if (!uci->prev && !uci->next) { // reset hashtable entry uc->hashtable[uci->hash % uc->hashsize] = 0; } if (uc->purge_lru) lru_remove_item(uc, index); uc->n_items--; } ret = 0; uci->keysize = 0; uci->valsize = 0; uci->hash = 0; uci->prev = 0; uci->next = 0; uci->expires = 0; if (uc->use_last_modified) { uc->last_modified_at = uwsgi_now(); } } if (uc->nodes && ret == 0 && !(flags & UWSGI_CACHE_FLAG_LOCAL)) { cache_send_udp_command(uc, key, keylen, NULL, 0, 0, 11); } return ret; } void uwsgi_cache_fix(struct uwsgi_cache *uc) { uint64_t i; unsigned long long restored = 0; uint64_t next_scan = 0; // reset unused blocks uc->unused_blocks_stack_ptr = 0; for (i = 1; i < uc->max_items; i++) { // valid record ? struct uwsgi_cache_item *uci = cache_item(i); if (uci->keysize) { if (!uci->prev) { // put value in hash_table uc->hashtable[uci->hash % uc->hashsize] = i; } if (uci->expires && (!next_scan || next_scan > uci->expires)) { next_scan = uci->expires; } if (!uc->lru_head && !uci->lru_prev) { uc->lru_head = i; } if (!uc->lru_tail && !uci->lru_next) { uc->lru_tail = i; } restored++; } else { // put this record in unused stack uc->unused_blocks_stack_ptr++; uc->unused_blocks_stack[uc->unused_blocks_stack_ptr] = i; } } uc->next_scan = next_scan; uc->n_items = restored; uwsgi_log("[uwsgi-cache] restored %llu items\n", uc->n_items); } int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *val, uint64_t vallen, uint64_t expires, uint64_t flags) { uint64_t index = 0, last_index = 0; struct uwsgi_cache_item *uci, *ucii; // used to reset key allocation in bitmap mode int ret = -1; time_t now = 0; if (!keylen || !vallen) return -1; if (keylen > uc->keysize) return -1; if (vallen > uc->max_item_size) return -1; if ((flags & UWSGI_CACHE_FLAG_MATH) && vallen != 8) return -1; //uwsgi_log("putting cache data in key %.*s %d\n", keylen, key, vallen); index = uwsgi_cache_get_index(uc, key, keylen); if (!index) { if (!uc->unused_blocks_stack_ptr) { cache_full(uc); if (!uc->unused_blocks_stack_ptr) goto end; } index = uc->unused_blocks_stack[uc->unused_blocks_stack_ptr]; uc->unused_blocks_stack_ptr--; uci = cache_item(index); if (!uc->blocks_bitmap) { uci->first_block = index; } else { uci->first_block = uwsgi_cache_find_free_blocks(uc, vallen); if (uci->first_block == 0xffffffffffffffffLLU) { uc->unused_blocks_stack_ptr++; cache_full(uc); goto end; } // mark used blocks; uint64_t needed_blocks = cache_mark_blocks(uc, uci->first_block, vallen); // optimize the scan if (uci->first_block + needed_blocks >= uc->blocks) { uc->blocks_bitmap_pos = 0; } else { uc->blocks_bitmap_pos = uci->first_block + needed_blocks; } } if (uc->purge_lru) lru_add_item(uc, index); else if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) { now = uwsgi_now(); expires += now; if (!uc->next_scan || uc->next_scan > expires) uc->next_scan = expires; } uci->expires = expires; uci->hash = uc->hash->func(key, keylen); uci->hits = 0; uci->flags = flags; memcpy(uci->key, key, keylen); if ( !(flags & UWSGI_CACHE_FLAG_MATH)) { memcpy(((char *) uc->data) + (uci->first_block * uc->blocksize), val, vallen); } // ok math operations here else { int64_t *num = (int64_t *)(((char *) uc->data) + (uci->first_block * uc->blocksize)); *num = uc->math_initial; int64_t *delta = (int64_t *) val; if (flags & UWSGI_CACHE_FLAG_INC) { *num += *delta; } else if (flags & UWSGI_CACHE_FLAG_DEC) { *num -= *delta; } else if (flags & UWSGI_CACHE_FLAG_MUL) { *num *= *delta; } else if (flags & UWSGI_CACHE_FLAG_DIV) { if (*delta == 0) { *num = 0; } else { *num /= *delta; } } } // set this as late as possibile (to reduce races risk) uci->valsize = vallen; uci->keysize = keylen; ret = 0; // now put the value in the hashtable uint32_t slot = uci->hash % uc->hashsize; // reset values uci->prev = 0; uci->next = 0; last_index = uc->hashtable[slot]; if (last_index == 0) { uc->hashtable[slot] = index; } else { // append to first available next ucii = cache_item(last_index); while (ucii->next) { last_index = ucii->next; ucii = cache_item(last_index); } ucii->next = index; uci->prev = last_index; } uc->n_items++ ; } else if (flags & UWSGI_CACHE_FLAG_UPDATE) { uci = cache_item(index); if (!(flags & UWSGI_CACHE_FLAG_FIXEXPIRE)) { if (uc->purge_lru) { lru_remove_item(uc, index); lru_add_item(uc, index); } else if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) { now = uwsgi_now(); expires += now; if (!uc->next_scan || uc->next_scan > expires) uc->next_scan = expires; } uci->expires = expires; } if (uc->blocks_bitmap) { // we have a special case here, as we need to find a new series of free blocks uint64_t old_first_block = uci->first_block; uci->first_block = uwsgi_cache_find_free_blocks(uc, vallen); if (uci->first_block == 0xffffffffffffffffLLU) { uci->first_block = old_first_block; cache_full(uc); goto end; } // mark used blocks; uint64_t needed_blocks = cache_mark_blocks(uc, uci->first_block, vallen); // optimize the scan if (uci->first_block + needed_blocks >= uc->blocks) { uc->blocks_bitmap_pos = 0; } else { uc->blocks_bitmap_pos = uci->first_block + needed_blocks; } // unmark the old blocks cache_unmark_blocks(uc, old_first_block, uci->valsize); } if ( !(flags & UWSGI_CACHE_FLAG_MATH)) { memcpy(((char *) uc->data) + (uci->first_block * uc->blocksize), val, vallen); } else { int64_t *num = (int64_t *)(((char *) uc->data) + (uci->first_block * uc->blocksize)); int64_t *delta = (int64_t *) val; if (flags & UWSGI_CACHE_FLAG_INC) { *num += *delta; } else if (flags & UWSGI_CACHE_FLAG_DEC) { *num -= *delta; } else if (flags & UWSGI_CACHE_FLAG_MUL) { *num *= *delta; } else if (flags & UWSGI_CACHE_FLAG_DIV) { if (*delta == 0) { *num = 0; } else { *num /= *delta; } } } uci->valsize = vallen; ret = 0; } if (uc->use_last_modified) { uc->last_modified_at = (now ? now : uwsgi_now()); } if (uc->nodes && ret == 0 && !(flags & UWSGI_CACHE_FLAG_LOCAL)) { cache_send_udp_command(uc, key, keylen, val, vallen, expires, 10); } end: return ret; } static void cache_send_udp_command(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *val, uint16_t vallen, uint64_t expires, uint8_t cmd) { struct uwsgi_header uh; uint8_t u_k[2]; uint8_t u_v[2]; uint8_t u_e[2]; uint16_t vallen16 = vallen; struct iovec iov[7]; struct msghdr mh; memset(&mh, 0, sizeof(struct msghdr)); mh.msg_iov = iov; mh.msg_iovlen = 3; if (cmd == 10) { mh.msg_iovlen = 7; } iov[0].iov_base = &uh; iov[0].iov_len = 4; u_k[0] = (uint8_t) (keylen & 0xff); u_k[1] = (uint8_t) ((keylen >> 8) & 0xff); iov[1].iov_base = u_k; iov[1].iov_len = 2; iov[2].iov_base = key; iov[2].iov_len = keylen; uh.pktsize = 2 + keylen; if (cmd == 10) { u_v[0] = (uint8_t) (vallen16 & 0xff); u_v[1] = (uint8_t) ((vallen16 >> 8) & 0xff); iov[3].iov_base = u_v; iov[3].iov_len = 2; iov[4].iov_base = val; iov[4].iov_len = vallen16; char es[sizeof(UMAX64_STR) + 1]; uint16_t es_size = uwsgi_long2str2n(expires, es, sizeof(UMAX64_STR)); u_e[0] = (uint8_t) (es_size & 0xff); u_e[1] = (uint8_t) ((es_size >> 8) & 0xff); iov[5].iov_base = u_e; iov[5].iov_len = 2; iov[6].iov_base = es; iov[6].iov_len = es_size; uh.pktsize += 2 + vallen16 + 2 + es_size; } uh.modifier1 = 111; uh.modifier2 = cmd; struct uwsgi_string_list *usl = uc->nodes; while(usl) { mh.msg_name = usl->custom_ptr; mh.msg_namelen = usl->custom; if (sendmsg(uc->udp_node_socket, &mh, 0) <= 0) { uwsgi_error("[cache-udp-node] sendmsg()"); } usl = usl->next; } } void *cache_udp_server_loop(void *ucache) { // block all signals sigset_t smask; sigfillset(&smask); pthread_sigmask(SIG_BLOCK, &smask, NULL); struct uwsgi_cache *uc = (struct uwsgi_cache *) ucache; int queue = event_queue_init(); struct uwsgi_string_list *usl = uc->udp_servers; while(usl) { if (strchr(usl->value, ':')) { int fd = bind_to_udp(usl->value, 0, 0); if (fd < 0) { uwsgi_log("[cache-udp-server] cannot bind to %s\n", usl->value); exit(1); } uwsgi_socket_nb(fd); event_queue_add_fd_read(queue, fd); uwsgi_log("*** udp server for cache \"%s\" running on %s ***\n", uc->name, usl->value); } usl = usl->next; } // allocate 64k chunk to receive messages char *buf = uwsgi_malloc(UMAX16); for(;;) { uint16_t pktsize = 0, ss = 0; int interesting_fd = -1; int rlen = event_queue_wait(queue, -1, &interesting_fd); if (rlen <= 0) continue; if (interesting_fd < 0) continue; ssize_t len = read(interesting_fd, buf, UMAX16); if (len <= 7) { uwsgi_error("[cache-udp-server] read()"); } if (buf[0] != 111) continue; memcpy(&pktsize, buf+1, 2); if (pktsize != len-4) continue; memcpy(&ss, buf + 4, 2); if (4+ss > pktsize) continue; uint16_t keylen = ss; char *key = buf + 6; // cache set/update if (buf[3] == 10) { if (keylen + 2 + 2 > pktsize) continue; memcpy(&ss, buf + 6 + keylen, 2); if (4+keylen+ss > pktsize) continue; uint16_t vallen = ss; char *val = buf + 8 + keylen; uint64_t expires = 0; if (2 + keylen + 2 + vallen + 2 < pktsize) { memcpy(&ss, buf + 8 + keylen + vallen , 2); if (6+keylen+vallen+ss > pktsize) continue; expires = uwsgi_str_num(buf + 10 + keylen+vallen, ss); } uwsgi_wlock(uc->lock); if (uwsgi_cache_set2(uc, key, keylen, val, vallen, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_LOCAL|UWSGI_CACHE_FLAG_ABSEXPIRE)) { uwsgi_log("[cache-udp-server] unable to update cache\n"); } uwsgi_rwunlock(uc->lock); } // cache del else if (buf[3] == 11) { uwsgi_wlock(uc->lock); if (uwsgi_cache_del2(uc, key, keylen, 0, UWSGI_CACHE_FLAG_LOCAL)) { uwsgi_log("[cache-udp-server] unable to update cache\n"); } uwsgi_rwunlock(uc->lock); } } return NULL; } static uint64_t cache_sweeper_free_items(struct uwsgi_cache *uc) { uint64_t i; uint64_t freed_items = 0; if (uc->no_expire || uc->purge_lru || uc->lazy_expire) return 0; uwsgi_rlock(uc->lock); if (!uc->next_scan || uc->next_scan > (uint64_t)uwsgi.current_time) { uwsgi_rwunlock(uc->lock); return 0; } uwsgi_rwunlock(uc->lock); // skip the first slot for (i = 1; i < uc->max_items; i++) { struct uwsgi_cache_item *uci = cache_item(i); uwsgi_wlock(uc->lock); // we reset next scan time first, then we find the least // expiration time from those that are NOT expired yet. if (i == 1) uc->next_scan = 0; if (uci->expires) { if (uci->expires <= (uint64_t)uwsgi.current_time) { uwsgi_cache_del2(uc, NULL, 0, i, UWSGI_CACHE_FLAG_LOCAL); freed_items++; } else if (!uc->next_scan || uc->next_scan > uci->expires) { uc->next_scan = uci->expires; } } uwsgi_rwunlock(uc->lock); } return freed_items; } static void *cache_sweeper_loop(void *ucache) { // block all signals sigset_t smask; sigfillset(&smask); pthread_sigmask(SIG_BLOCK, &smask, NULL); if (!uwsgi.cache_expire_freq) uwsgi.cache_expire_freq = 3; // remove expired cache items TODO use rb_tree timeouts for (;;) { struct uwsgi_cache *uc; for (uc = (struct uwsgi_cache *)ucache; uc; uc = uc->next) { uint64_t freed_items = cache_sweeper_free_items(uc); if (uwsgi.cache_report_freed_items && freed_items) uwsgi_log("freed %llu items for cache \"%s\"\n", (unsigned long long)freed_items, uc->name); } sleep(uwsgi.cache_expire_freq); } return NULL; } void uwsgi_cache_sync_all() { struct uwsgi_cache *uc = uwsgi.caches; while(uc) { if (uc->store && (uwsgi.master_cycles == 0 || (uc->store_sync > 0 && (uwsgi.master_cycles % uc->store_sync) == 0))) { if (msync(uc->items, uc->filesize, MS_ASYNC)) { uwsgi_error("uwsgi_cache_sync_all()/msync()"); } } uc = uc->next; } } void uwsgi_cache_start_sweepers() { struct uwsgi_cache *uc = uwsgi.caches; if (uwsgi.cache_no_expire) return; int need_to_run = 0; while(uc) { if (!uc->no_expire && !uc->purge_lru && !uc->lazy_expire) { need_to_run = 1; break; } uc = uc->next; } if (!need_to_run) return; pthread_t cache_sweeper; if (pthread_create(&cache_sweeper, NULL, cache_sweeper_loop, uwsgi.caches)) { uwsgi_error("uwsgi_cache_start_sweepers()/pthread_create()"); uwsgi_log("unable to run the cache sweeper!!!\n"); return; } uwsgi_log("cache sweeper thread enabled\n"); } void uwsgi_cache_start_sync_servers() { struct uwsgi_cache *uc = uwsgi.caches; while(uc) { if (!uc->udp_servers) goto next; pthread_t cache_udp_server; if (pthread_create(&cache_udp_server, NULL, cache_udp_server_loop, (void *) uc)) { uwsgi_error("pthread_create()"); uwsgi_log("unable to run the cache udp server !!!\n"); } else { uwsgi_log("udp server thread enabled for cache \"%s\"\n", uc->name); } next: uc = uc->next; } } struct uwsgi_cache *uwsgi_cache_create(char *arg) { struct uwsgi_cache *old_uc = NULL, *uc = uwsgi.caches; while(uc) { old_uc = uc; uc = uc->next; } uc = uwsgi_calloc_shared(sizeof(struct uwsgi_cache)); if (old_uc) { old_uc->next = uc; } else { uwsgi.caches = uc; } // default (old-stye) cache ? if (!arg) { uc->name = "default"; uc->name_len = strlen(uc->name); uc->blocksize = uwsgi.cache_blocksize; if (!uc->blocksize) uc->blocksize = UMAX16; uc->max_item_size = uc->blocksize; uc->max_items = uwsgi.cache_max_items; uc->blocks = uwsgi.cache_max_items; uc->keysize = 2048; uc->hashsize = UMAX16; uc->hash = uwsgi_hash_algo_get("djb33x"); uc->store = uwsgi.cache_store; uc->nodes = uwsgi.cache_udp_node; uc->udp_servers = uwsgi.cache_udp_server; uc->store_sync = uwsgi.cache_store_sync; uc->use_last_modified = (uint8_t) uwsgi.cache_use_last_modified; if (uwsgi.cache_sync) { uwsgi_string_new_list(&uc->sync_nodes, uwsgi.cache_sync); } } else { char *c_name = NULL; char *c_max_items = NULL; char *c_blocksize = NULL; char *c_blocks = NULL; char *c_hash = NULL; char *c_hashsize = NULL; char *c_keysize = NULL; char *c_store = NULL; char *c_store_sync = NULL; char *c_store_delete = NULL; char *c_nodes = NULL; char *c_sync = NULL; char *c_udp_servers = NULL; char *c_bitmap = NULL; char *c_use_last_modified = NULL; char *c_math_initial = NULL; char *c_ignore_full = NULL; char *c_purge_lru = NULL; char *c_lazy_expire = NULL; char *c_sweep_on_full = NULL; char *c_clear_on_full = NULL; char *c_no_expire = NULL; if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=', "name", &c_name, "max_items", &c_max_items, "maxitems", &c_max_items, "items", &c_max_items, "blocksize", &c_blocksize, "blocks", &c_blocks, "hash", &c_hash, "hashsize", &c_hashsize, "hash_size", &c_hashsize, "keysize", &c_keysize, "key_size", &c_keysize, "store", &c_store, "store_sync", &c_store_sync, "storesync", &c_store_sync, "store_delete", &c_store_delete, "storedelete", &c_store_delete, "node", &c_nodes, "nodes", &c_nodes, "sync", &c_sync, "udp", &c_udp_servers, "udp_servers", &c_udp_servers, "udp_server", &c_udp_servers, "udpservers", &c_udp_servers, "udpserver", &c_udp_servers, "bitmap", &c_bitmap, "lastmod", &c_use_last_modified, "math_initial", &c_math_initial, "ignore_full", &c_ignore_full, "purge_lru", &c_purge_lru, "lru", &c_purge_lru, "lazy_expire", &c_lazy_expire, "lazy", &c_lazy_expire, "sweep_on_full", &c_sweep_on_full, "clear_on_full", &c_clear_on_full, "no_expire", &c_no_expire, NULL)) { uwsgi_log("unable to parse cache definition\n"); exit(1); } if (!c_name) { uwsgi_log("you have to specify a cache name\n"); exit(1); } if (!c_max_items) { uwsgi_log("you have to specify the maximum number of cache items\n"); exit(1); } uc->name = c_name; uc->name_len = strlen(c_name); uc->max_items = uwsgi_n64(c_max_items); if (!uc->max_items) { uwsgi_log("you have to specify the maximum number of cache items\n"); exit(1); } // defaults uc->blocks = uc->max_items; uc->blocksize = UMAX16; uc->keysize = 2048; uc->hashsize = UMAX16; uc->hash = uwsgi_hash_algo_get("djb33x"); // customize if (c_blocksize) uc->blocksize = uwsgi_n64(c_blocksize); if (!uc->blocksize) { uwsgi_log("invalid cache blocksize for \"%s\"\n", uc->name); exit(1); } // set the true max size of an item uc->max_item_size = uc->blocksize; if (c_blocks) uc->blocks = uwsgi_n64(c_blocks); if (!uc->blocks) { uwsgi_log("invalid cache blocks for \"%s\"\n", uc->name); exit(1); } if (c_hash) uc->hash = uwsgi_hash_algo_get(c_hash); if (!uc->hash) { uwsgi_log("invalid cache hash for \"%s\"\n", uc->name); exit(1); } if (c_hashsize) uc->hashsize = uwsgi_n64(c_hashsize); if (!uc->hashsize) { uwsgi_log("invalid cache hashsize for \"%s\"\n", uc->name); exit(1); } if (c_keysize) uc->keysize = uwsgi_n64(c_keysize); if (!uc->keysize || uc->keysize >= UMAX16) { uwsgi_log("invalid cache keysize for \"%s\"\n", uc->name); exit(1); } if (c_bitmap) { uc->use_blocks_bitmap = 1; uc->max_item_size = uc->blocksize * uc->blocks; } if (c_use_last_modified) uc->use_last_modified = 1; if (c_ignore_full) uc->ignore_full = 1; if (c_store_delete) uc->store_delete = 1; if (c_math_initial) uc->math_initial = strtol(c_math_initial, NULL, 10); if (c_lazy_expire) uc->lazy_expire = 1; if (c_sweep_on_full) { uc->sweep_on_full = uwsgi_n64(c_sweep_on_full); } if (c_clear_on_full) uc->clear_on_full = 1; if (c_no_expire) uc->no_expire = 1; uc->store_sync = uwsgi.cache_store_sync; if (c_store_sync) { uc->store_sync = uwsgi_n64(c_store_sync); } if (uc->blocks < uc->max_items) { uwsgi_log("invalid number of cache blocks for \"%s\", must be higher than max_items (%llu)\n", uc->name, uc->max_items); exit(1); } uc->store = c_store; if (c_nodes) { char *p, *ctx = NULL; uwsgi_foreach_token(c_nodes, ";", p, ctx) { uwsgi_string_new_list(&uc->nodes, p); } } if (c_sync) { char *p, *ctx = NULL; uwsgi_foreach_token(c_sync, ";", p, ctx) { uwsgi_string_new_list(&uc->sync_nodes, p); } } if (c_udp_servers) { char *p, *ctx = NULL; uwsgi_foreach_token(c_udp_servers, ";", p, ctx) { uwsgi_string_new_list(&uc->udp_servers, p); } } if (c_purge_lru) uc->purge_lru = 1; } uwsgi_cache_init(uc); return uc; } struct uwsgi_cache *uwsgi_cache_by_name(char *name) { struct uwsgi_cache *uc = uwsgi.caches; if (!name || *name == 0) { return uwsgi.caches; } while(uc) { if (uc->name && !strcmp(uc->name, name)) { return uc; } uc = uc->next; } return NULL; } struct uwsgi_cache *uwsgi_cache_by_namelen(char *name, uint16_t len) { struct uwsgi_cache *uc = uwsgi.caches; if (!name || *name == 0) { return uwsgi.caches; } while(uc) { if (uc->name && !uwsgi_strncmp(uc->name, uc->name_len, name, len)) { return uc; } uc = uc->next; } return NULL; } void uwsgi_cache_create_all() { if (uwsgi.cache_setup) return; // register embedded hash algorithms uwsgi_hash_algo_register_all(); // setup default cache if (uwsgi.cache_max_items > 0) { uwsgi_cache_create(NULL); } // setup new generation caches struct uwsgi_string_list *usl = uwsgi.cache2; while(usl) { uwsgi_cache_create(usl->value); usl = usl->next; } uwsgi.cache_setup = 1; } /* * uWSGI cache magic functions. They can be used by plugin to easily access local and remote caches * * they generate (when needed) a new memory buffer. Locking is automatically managed * * You have to free the returned memory !!! * */ void uwsgi_cache_magic_context_hook(char *key, uint16_t key_len, char *value, uint16_t vallen, void *data) { struct uwsgi_cache_magic_context *ucmc = (struct uwsgi_cache_magic_context *) data; if (!uwsgi_strncmp(key, key_len, "cmd", 3)) { ucmc->cmd = value; ucmc->cmd_len = vallen; return; } if (!uwsgi_strncmp(key, key_len, "key", 3)) { ucmc->key = value; ucmc->key_len = vallen; return; } if (!uwsgi_strncmp(key, key_len, "expires", 7)) { ucmc->expires = uwsgi_str_num(value, vallen); return; } if (!uwsgi_strncmp(key, key_len, "size", 4)) { ucmc->size = uwsgi_str_num(value, vallen); return; } if (!uwsgi_strncmp(key, key_len, "cache", 5)) { ucmc->cache = value; ucmc->cache_len = vallen; return; } if (!uwsgi_strncmp(key, key_len, "status", 6)) { ucmc->status = value; ucmc->status_len = vallen; return; } } static struct uwsgi_buffer *uwsgi_cache_prepare_magic_get(char *cache_name, uint16_t cache_name_len, char *key, uint16_t key_len) { struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); ub->pos = 4; if (uwsgi_buffer_append_keyval(ub, "cmd", 3, "get", 3)) goto error; if (uwsgi_buffer_append_keyval(ub, "key", 3, key, key_len)) goto error; if (cache_name) { if (uwsgi_buffer_append_keyval(ub, "cache", 5, cache_name, cache_name_len)) goto error; } return ub; error: uwsgi_buffer_destroy(ub); return NULL; } struct uwsgi_buffer *uwsgi_cache_prepare_magic_exists(char *cache_name, uint16_t cache_name_len, char *key, uint16_t key_len) { struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); ub->pos = 4; if (uwsgi_buffer_append_keyval(ub, "cmd", 3, "exists", 6)) goto error; if (uwsgi_buffer_append_keyval(ub, "key", 3, key, key_len)) goto error; if (cache_name) { if (uwsgi_buffer_append_keyval(ub, "cache", 5, cache_name, cache_name_len)) goto error; } return ub; error: uwsgi_buffer_destroy(ub); return NULL; } struct uwsgi_buffer *uwsgi_cache_prepare_magic_del(char *cache_name, uint16_t cache_name_len, char *key, uint16_t key_len) { struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); ub->pos = 4; if (uwsgi_buffer_append_keyval(ub, "cmd", 3, "del", 3)) goto error; if (uwsgi_buffer_append_keyval(ub, "key", 3, key, key_len)) goto error; if (cache_name) { if (uwsgi_buffer_append_keyval(ub, "cache", 5, cache_name, cache_name_len)) goto error; } return ub; error: uwsgi_buffer_destroy(ub); return NULL; } struct uwsgi_buffer *uwsgi_cache_prepare_magic_clear(char *cache_name, uint16_t cache_name_len) { struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); ub->pos = 4; if (uwsgi_buffer_append_keyval(ub, "cmd", 3, "clear", 5)) goto error; if (cache_name) { if (uwsgi_buffer_append_keyval(ub, "cache", 5, cache_name, cache_name_len)) goto error; } return ub; error: uwsgi_buffer_destroy(ub); return NULL; } struct uwsgi_buffer *uwsgi_cache_prepare_magic_set(char *cache_name, uint16_t cache_name_len, char *key, uint16_t key_len, uint64_t len, uint64_t expires) { struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); ub->pos = 4; if (uwsgi_buffer_append_keyval(ub, "cmd", 3, "set", 3)) goto error; if (uwsgi_buffer_append_keyval(ub, "key", 3, key, key_len)) goto error; if (uwsgi_buffer_append_keynum(ub, "size", 4, len)) goto error; if (expires > 0) { if (uwsgi_buffer_append_keynum(ub, "expires", 7, expires)) goto error; } if (uwsgi_buffer_append_keynum(ub, "size", 4, len)) goto error; if (cache_name) { if (uwsgi_buffer_append_keyval(ub, "cache", 5, cache_name, cache_name_len)) goto error; } return ub; error: uwsgi_buffer_destroy(ub); return NULL; } struct uwsgi_buffer *uwsgi_cache_prepare_magic_update(char *cache_name, uint16_t cache_name_len, char *key, uint16_t key_len, uint64_t len, uint64_t expires) { struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); ub->pos = 4; if (uwsgi_buffer_append_keyval(ub, "cmd", 3, "update", 6)) goto error; if (uwsgi_buffer_append_keyval(ub, "key", 3, key, key_len)) goto error; if (uwsgi_buffer_append_keynum(ub, "size", 4, len)) goto error; if (expires > 0) { if (uwsgi_buffer_append_keynum(ub, "expires", 7, expires)) goto error; } if (uwsgi_buffer_append_keynum(ub, "size", 4, len)) goto error; if (cache_name) { if (uwsgi_buffer_append_keyval(ub, "cache", 5, cache_name, cache_name_len)) goto error; } return ub; error: uwsgi_buffer_destroy(ub); return NULL; } static int cache_magic_send_and_manage(int fd, struct uwsgi_buffer *ub, char *stream, uint64_t stream_len, int timeout, struct uwsgi_cache_magic_context *ucmc) { if (uwsgi_buffer_set_uh(ub, 111, 17)) return -1; if (stream) { if (uwsgi_buffer_append(ub, stream, stream_len)) return -1; } if (uwsgi_write_true_nb(fd, ub->buf, ub->pos, timeout)) return -1; // ok now wait for the response, using the same buffer of the request // NOTE: after using a uwsgi_buffer in that way we basically destroy (even if we can safely free it) size_t rlen = ub->pos; if (uwsgi_read_with_realloc(fd, &ub->buf, &rlen, timeout, NULL, NULL)) return -1; // try to fix the buffer to maintain size info ub->pos = rlen; // now we have a uwsgi dictionary with all of the options needed, let's parse it memset(ucmc, 0, sizeof(struct uwsgi_cache_magic_context)); if (uwsgi_hooked_parse(ub->buf, rlen, uwsgi_cache_magic_context_hook, ucmc)) return -1; return 0; } char *uwsgi_cache_magic_get(char *key, uint16_t keylen, uint64_t *vallen, uint64_t *expires, char *cache) { struct uwsgi_cache_magic_context ucmc; struct uwsgi_cache *uc = NULL; char *cache_server = NULL; char *cache_name = NULL; uint16_t cache_name_len = 0; if (cache) { char *at = strchr(cache, '@'); if (!at) { uc = uwsgi_cache_by_name(cache); } else { cache_server = at + 1; cache_name = cache; cache_name_len = at - cache; } } // use default (local) cache else { uc = uwsgi.caches; } // we have a local cache !!! if (uc) { if (uc->purge_lru) uwsgi_wlock(uc->lock); else uwsgi_rlock(uc->lock); char *value = uwsgi_cache_get3(uc, key, keylen, vallen, expires); if (!value) { uwsgi_rwunlock(uc->lock); return NULL; } char *buf = uwsgi_malloc(*vallen); memcpy(buf, value, *vallen); uwsgi_rwunlock(uc->lock); return buf; } // we have a remote one if (cache_server) { int fd = uwsgi_connect(cache_server, 0, 1); if (fd < 0) return NULL; int ret = uwsgi.wait_write_hook(fd, uwsgi.socket_timeout); if (ret <= 0) { close(fd); return NULL; } struct uwsgi_buffer *ub = uwsgi_cache_prepare_magic_get(cache_name, cache_name_len, key, keylen); if (!ub) { close(fd); return NULL; } if (cache_magic_send_and_manage(fd, ub, NULL, 0, uwsgi.socket_timeout, &ucmc)) { close(fd); uwsgi_buffer_destroy(ub); return NULL; } if (uwsgi_strncmp(ucmc.status, ucmc.status_len, "ok", 2)) { close(fd); uwsgi_buffer_destroy(ub); return NULL; } if (ucmc.size == 0) { close(fd); uwsgi_buffer_destroy(ub); return NULL; } // ok we now need to fix our buffer (if needed) if (ucmc.size > ub->pos) { char *tmp_buf = realloc(ub->buf, ucmc.size); if (!tmp_buf) { uwsgi_error("uwsgi_cache_magic_get()/realloc()"); close(fd); uwsgi_buffer_destroy(ub); return NULL; } ub->buf = tmp_buf; } // read the raw value from the socket if (uwsgi_read_whole_true_nb(fd, ub->buf, ucmc.size, uwsgi.socket_timeout)) { close(fd); uwsgi_buffer_destroy(ub); return NULL; } // now the magic, we dereference the internal buffer and return it to the caller close(fd); char *value = ub->buf; ub->buf = NULL; uwsgi_buffer_destroy(ub); *vallen = ucmc.size; if (expires) { *expires = ucmc.expires; } return value; } return NULL; } int uwsgi_cache_magic_exists(char *key, uint16_t keylen, char *cache) { struct uwsgi_cache_magic_context ucmc; struct uwsgi_cache *uc = NULL; char *cache_server = NULL; char *cache_name = NULL; uint16_t cache_name_len = 0; if (cache) { char *at = strchr(cache, '@'); if (!at) { uc = uwsgi_cache_by_name(cache); } else { cache_server = at + 1; cache_name = cache; cache_name_len = at - cache; } } // use default (local) cache else { uc = uwsgi.caches; } // we have a local cache !!! if (uc) { uwsgi_rlock(uc->lock); if (!uwsgi_cache_exists2(uc, key, keylen)) { uwsgi_rwunlock(uc->lock); return 0; } uwsgi_rwunlock(uc->lock); return 1; } // we have a remote one if (cache_server) { int fd = uwsgi_connect(cache_server, 0, 1); if (fd < 0) return 0; int ret = uwsgi.wait_write_hook(fd, uwsgi.socket_timeout); if (ret <= 0) { close(fd); return 0; } struct uwsgi_buffer *ub = uwsgi_cache_prepare_magic_exists(cache_name, cache_name_len, key, keylen); if (!ub) { close(fd); return 0; } if (cache_magic_send_and_manage(fd, ub, NULL, 0, uwsgi.socket_timeout, &ucmc)) { close(fd); uwsgi_buffer_destroy(ub); return 0; } if (uwsgi_strncmp(ucmc.status, ucmc.status_len, "ok", 2)) { close(fd); uwsgi_buffer_destroy(ub); return 0; } close(fd); uwsgi_buffer_destroy(ub); return 1; } return 0; } int uwsgi_cache_magic_set(char *key, uint16_t keylen, char *value, uint64_t vallen, uint64_t expires, uint64_t flags, char *cache) { struct uwsgi_cache_magic_context ucmc; struct uwsgi_cache *uc = NULL; char *cache_server = NULL; char *cache_name = NULL; uint16_t cache_name_len = 0; if (cache) { char *at = strchr(cache, '@'); if (!at) { uc = uwsgi_cache_by_name(cache); } else { cache_server = at + 1; cache_name = cache; cache_name_len = at - cache; } } // use default (local) cache else { uc = uwsgi.caches; } // we have a local cache !!! if (uc) { uwsgi_wlock(uc->lock); int ret = uwsgi_cache_set2(uc, key, keylen, value, vallen, expires, flags); uwsgi_rwunlock(uc->lock); return ret; } // we have a remote one if (cache_server) { int fd = uwsgi_connect(cache_server, 0, 1); if (fd < 0) return -1; int ret = uwsgi.wait_write_hook(fd, uwsgi.socket_timeout); if (ret <= 0) { close(fd); return -1; } struct uwsgi_buffer *ub = NULL; if (flags & UWSGI_CACHE_FLAG_UPDATE) { ub = uwsgi_cache_prepare_magic_update(cache_name, cache_name_len, key, keylen, vallen, expires); } else { ub = uwsgi_cache_prepare_magic_set(cache_name, cache_name_len, key, keylen, vallen, expires); } if (!ub) { close(fd); return -1; } if (cache_magic_send_and_manage(fd, ub, value, vallen, uwsgi.socket_timeout, &ucmc)) { close(fd); uwsgi_buffer_destroy(ub); return -1; } if (uwsgi_strncmp(ucmc.status, ucmc.status_len, "ok", 2)) { close(fd); uwsgi_buffer_destroy(ub); return -1; } close(fd); uwsgi_buffer_destroy(ub); return 0; } return -1; } int uwsgi_cache_magic_del(char *key, uint16_t keylen, char *cache) { struct uwsgi_cache_magic_context ucmc; struct uwsgi_cache *uc = NULL; char *cache_server = NULL; char *cache_name = NULL; uint16_t cache_name_len = 0; if (cache) { char *at = strchr(cache, '@'); if (!at) { uc = uwsgi_cache_by_name(cache); } else { cache_server = at + 1; cache_name = cache; cache_name_len = at - cache; } } // use default (local) cache else { uc = uwsgi.caches; } // we have a local cache !!! if (uc) { uwsgi_wlock(uc->lock); if (uwsgi_cache_del2(uc, key, keylen, 0, 0)) { uwsgi_rwunlock(uc->lock); return -1; } uwsgi_rwunlock(uc->lock); return 0; } // we have a remote one if (cache_server) { int fd = uwsgi_connect(cache_server, 0, 1); if (fd < 0) return -1; int ret = uwsgi.wait_write_hook(fd, uwsgi.socket_timeout); if (ret <= 0) { close(fd); return -1; } struct uwsgi_buffer *ub = uwsgi_cache_prepare_magic_del(cache_name, cache_name_len, key, keylen); if (!ub) { close(fd); return -1; } if (cache_magic_send_and_manage(fd, ub, NULL, 0, uwsgi.socket_timeout, &ucmc)) { close(fd); uwsgi_buffer_destroy(ub); return -1; } if (uwsgi_strncmp(ucmc.status, ucmc.status_len, "ok", 2)) { close(fd); uwsgi_buffer_destroy(ub); return -1; } close(fd); uwsgi_buffer_destroy(ub); return 0; } return -1 ; } int uwsgi_cache_magic_clear(char *cache) { struct uwsgi_cache_magic_context ucmc; struct uwsgi_cache *uc = NULL; char *cache_server = NULL; char *cache_name = NULL; uint16_t cache_name_len = 0; if (cache) { char *at = strchr(cache, '@'); if (!at) { uc = uwsgi_cache_by_name(cache); } else { cache_server = at + 1; cache_name = cache; cache_name_len = at - cache; } } // use default (local) cache else { uc = uwsgi.caches; } // we have a local cache !!! if (uc) { uint64_t i; uwsgi_wlock(uc->lock); for (i = 1; i < uc->max_items; i++) { if (uwsgi_cache_del2(uc, NULL, 0, i, 0)) { uwsgi_rwunlock(uc->lock); return -1; } } uwsgi_rwunlock(uc->lock); return 0; } // we have a remote one if (cache_server) { int fd = uwsgi_connect(cache_server, 0, 1); if (fd < 0) return -1; int ret = uwsgi.wait_write_hook(fd, uwsgi.socket_timeout); if (ret <= 0) { close(fd); return -1; } struct uwsgi_buffer *ub = uwsgi_cache_prepare_magic_clear(cache_name, cache_name_len); if (!ub) { close(fd); return -1; } if (cache_magic_send_and_manage(fd, ub, NULL, 0, uwsgi.socket_timeout, &ucmc)) { close(fd); uwsgi_buffer_destroy(ub); return -1; } if (uwsgi_strncmp(ucmc.status, ucmc.status_len, "ok", 2)) { close(fd); uwsgi_buffer_destroy(ub); return -1; } close(fd); uwsgi_buffer_destroy(ub); return 0; } return -1 ; } void uwsgi_cache_sync_from_nodes(struct uwsgi_cache *uc) { struct uwsgi_string_list *usl = uc->sync_nodes; while(usl) { uwsgi_log("[cache-sync] getting cache dump from %s ...\n", usl->value); int fd = uwsgi_connect(usl->value, 0, 0); if (fd < 0) { uwsgi_log("[cache-sync] unable to connect to the cache server\n"); goto next; } struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size + uc->filesize); ub->pos = 4; if (uc->name && uwsgi_buffer_append(ub, uc->name, uc->name_len)) { uwsgi_buffer_destroy(ub); close(fd); goto next; } if (uwsgi_buffer_set_uh(ub, 111, 6)) { uwsgi_buffer_destroy(ub); close(fd); goto next; } if (uwsgi_write_nb(fd, ub->buf, ub->pos, uwsgi.socket_timeout)) { uwsgi_buffer_destroy(ub); uwsgi_log("[cache-sync] unable to write to the cache server\n"); close(fd); goto next; } size_t rlen = ub->pos; if (uwsgi_read_with_realloc(fd, &ub->buf, &rlen, uwsgi.socket_timeout, NULL, NULL)) { uwsgi_buffer_destroy(ub); uwsgi_log("[cache-sync] unable to read from the cache server\n"); close(fd); goto next; } uwsgi_hooked_parse(ub->buf, rlen, cache_sync_hook, uc); if (uwsgi_read_nb(fd, (char *) uc->items, uc->filesize, uwsgi.socket_timeout)) { uwsgi_buffer_destroy(ub); close(fd); uwsgi_log("[cache-sync] unable to read from the cache server\n"); goto next; } // reset the hashtable memset(uc->hashtable, 0, sizeof(uint64_t) * UMAX16); // re-fill the hashtable uwsgi_cache_fix(uc); uwsgi_buffer_destroy(ub); close(fd); break; next: if (!usl->next) { exit(1); } uwsgi_log("[cache-sync] trying with the next sync node...\n"); usl = usl->next; } } void uwsgi_cache_setup_nodes(struct uwsgi_cache *uc) { struct uwsgi_string_list *usl = uc->nodes; while(usl) { char *port = strchr(usl->value, ':'); if (!port) { uwsgi_log("[cache-udp-node] invalid udp address: %s\n", usl->value); exit(1); } // no need to zero the memory, socket_to_in_addr will do that struct sockaddr_in *sin = uwsgi_malloc(sizeof(struct sockaddr_in)); usl->custom = socket_to_in_addr(usl->value, port, 0, sin); usl->custom_ptr = sin; uwsgi_log("added udp node %s for cache \"%s\"\n", usl->value, uc->name); usl = usl->next; } } struct uwsgi_cache_item *uwsgi_cache_keys(struct uwsgi_cache *uc, uint64_t *pos, struct uwsgi_cache_item **uci) { // security check if (*pos >= uc->hashsize) return NULL; // iterate hashtable uint64_t orig_pos = *pos; for(;*poshashsize;(*pos)++) { // get the cache slot uint64_t slot = uc->hashtable[*pos]; if (*pos == orig_pos && *uci) { slot = (*uci)->next; } if (slot == 0) continue; *uci = cache_item(slot); return *uci; } (*pos)++; return NULL; } void uwsgi_cache_rlock(struct uwsgi_cache *uc) { uwsgi_rlock(uc->lock); } void uwsgi_cache_rwunlock(struct uwsgi_cache *uc) { uwsgi_rwunlock(uc->lock); } char *uwsgi_cache_item_key(struct uwsgi_cache_item *uci) { return uci->key; } uwsgi-2.0.29/core/chunked.c000066400000000000000000000125261477626554400155110ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; /* Chunked input implementation --chunked-input-limit (default 1MB) --chunked-input-timeout (default --socket-timeout) chunk = uwsgi.chunked_read([timeout]) timeout = -1 (wait forever) timeout = 0 (default) */ static ssize_t uwsgi_chunked_input_recv(struct wsgi_request *wsgi_req, int timeout, int nb) { if (timeout == 0) timeout = uwsgi.chunked_input_timeout; if (timeout == 0) timeout = uwsgi.socket_timeout; int ret = -1; for(;;) { ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->chunked_input_buf->buf + wsgi_req->chunked_input_buf->pos, wsgi_req->chunked_input_buf->len - wsgi_req->chunked_input_buf->pos); if (rlen > 0) return rlen; if (rlen == 0) return -1; if (rlen < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) { if (nb) return -1; goto wait; } uwsgi_error("uwsgi_chunked_input_recv()"); return -1; } wait: ret = uwsgi.wait_read_hook(wsgi_req->fd, timeout); if (ret > 0) { rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->chunked_input_buf->buf + wsgi_req->chunked_input_buf->pos, wsgi_req->chunked_input_buf->len - wsgi_req->chunked_input_buf->pos); if (rlen > 0) return rlen; if (rlen <= 0) return -1; } if (ret < 0) { uwsgi_error("uwsgi_chunked_input_recv()"); } return -1; } return -1; } static ssize_t uwsgi_chunked_readline(struct wsgi_request *wsgi_req) { size_t i; int found = 0; for(i=0;ichunked_input_buf->pos;i++) { if (found) { if (wsgi_req->chunked_input_buf->buf[i] == '\n') { // strtoul will stop at \r size_t num = strtoul(wsgi_req->chunked_input_buf->buf, NULL, 16); if (uwsgi_buffer_decapitate(wsgi_req->chunked_input_buf, i+1)) return -1; return num; } return -1; } if ((wsgi_req->chunked_input_buf->buf[i] >= '0' && wsgi_req->chunked_input_buf->buf[i] <= '9') || (wsgi_req->chunked_input_buf->buf[i] >= 'a' && wsgi_req->chunked_input_buf->buf[i] <= 'z') || (wsgi_req->chunked_input_buf->buf[i] >= 'A' && wsgi_req->chunked_input_buf->buf[i] <= 'Z')) continue; if (wsgi_req->chunked_input_buf->buf[i] == '\r') { found = 1; continue; } return -1; } return -2; } /* 0 -> waiting for \r\n 1 -> waiting for whole body */ char *uwsgi_chunked_read(struct wsgi_request *wsgi_req, size_t *len, int timeout, int nb) { if (!wsgi_req->chunked_input_buf) { wsgi_req->chunked_input_buf = uwsgi_buffer_new(uwsgi.page_size); wsgi_req->chunked_input_buf->limit = uwsgi.chunked_input_limit; } // the whole chunk stream has been consumed if (wsgi_req->chunked_input_complete) { *len = 0; return wsgi_req->chunked_input_buf->buf; } if (wsgi_req->chunked_input_decapitate > 0) { if (uwsgi_buffer_decapitate(wsgi_req->chunked_input_buf, wsgi_req->chunked_input_decapitate)) return NULL; wsgi_req->chunked_input_decapitate = 0; } for(;;) { if (wsgi_req->chunked_input_need > 0 || wsgi_req->chunked_input_buf->pos == 0) { if (uwsgi_buffer_ensure(wsgi_req->chunked_input_buf, UMAX((uint64_t)uwsgi.page_size, wsgi_req->chunked_input_need))) return NULL; ssize_t rlen = uwsgi_chunked_input_recv(wsgi_req, timeout, nb); if (rlen <= 0) return NULL; // update buffer position wsgi_req->chunked_input_buf->pos += rlen; if (wsgi_req->chunked_input_need > 0) { if ((size_t)rlen > wsgi_req->chunked_input_need) { wsgi_req->chunked_input_need = 0; } else { wsgi_req->chunked_input_need -= rlen; } } } if (wsgi_req->chunked_input_need > 0) continue; // ok we have a frame, let's parse it if (wsgi_req->chunked_input_buf->pos > 0) { switch(wsgi_req->chunked_input_parser_status) { case 0: wsgi_req->chunked_input_chunk_len = uwsgi_chunked_readline(wsgi_req); if (wsgi_req->chunked_input_chunk_len == -2) { wsgi_req->chunked_input_need++; break; } else if (wsgi_req->chunked_input_chunk_len < 0) { return NULL; } else if (wsgi_req->chunked_input_chunk_len == 0) { *len = 0; wsgi_req->chunked_input_complete = 1; return wsgi_req->chunked_input_buf->buf; } // if here the buffer has been already decapitated if ((size_t)(wsgi_req->chunked_input_chunk_len+2) > wsgi_req->chunked_input_buf->pos) { wsgi_req->chunked_input_need = (wsgi_req->chunked_input_chunk_len+2) - wsgi_req->chunked_input_buf->pos; wsgi_req->chunked_input_parser_status = 1; break; } *len = wsgi_req->chunked_input_chunk_len; wsgi_req->chunked_input_decapitate = wsgi_req->chunked_input_chunk_len+2; return wsgi_req->chunked_input_buf->buf; case 1: if ((size_t)(wsgi_req->chunked_input_chunk_len+2) > wsgi_req->chunked_input_buf->pos) { wsgi_req->chunked_input_need = (wsgi_req->chunked_input_chunk_len+2) - wsgi_req->chunked_input_buf->pos; break; } *len = wsgi_req->chunked_input_chunk_len; wsgi_req->chunked_input_decapitate = wsgi_req->chunked_input_chunk_len+2; wsgi_req->chunked_input_parser_status = 0; return wsgi_req->chunked_input_buf->buf; } } } } uwsgi-2.0.29/core/clang_fake.c000066400000000000000000000000161477626554400161310ustar00rootroot00000000000000int main() {} uwsgi-2.0.29/core/clock.c000066400000000000000000000017241477626554400151610ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; int uwsgi_simple_wait_milliseconds_hook(int timeout) { return poll(NULL, 0, timeout); } // in the future we will need to use the best clock source for each os/system time_t uwsgi_now() { return uwsgi.clock->seconds(); } uint64_t uwsgi_micros() { return uwsgi.clock->microseconds(); } uint64_t uwsgi_millis() { return uwsgi.clock->microseconds() / 1000; } void uwsgi_register_clock(struct uwsgi_clock *clock) { struct uwsgi_clock *clocks = uwsgi.clocks; clock->next = NULL; if (!clocks) { uwsgi.clocks = clock; return; } while (clocks) { if (!clocks->next) { clocks->next = clock; return; } clocks = clocks->next; } } void uwsgi_set_clock(char *name) { struct uwsgi_clock *clocks = uwsgi.clocks; while (clocks) { if (!strcmp(name, clocks->name)) { uwsgi.clock = clocks; return; } clocks = clocks->next; } uwsgi_log("unable to set \"%s\" clock\n", name); exit(1); } uwsgi-2.0.29/core/config.c000066400000000000000000000536531477626554400153430ustar00rootroot00000000000000#include "uwsgi.h" /* pluggable configuration system */ extern struct uwsgi_server uwsgi; struct uwsgi_configurator *uwsgi_register_configurator(char *name, void (*func)(char *, char **)) { struct uwsgi_configurator *old_uc = NULL,*uc = uwsgi.configurators; while(uc) { if (!strcmp(uc->name, name)) { return uc; } old_uc = uc; uc = uc->next; } uc = uwsgi_calloc(sizeof(struct uwsgi_configurator)); uc->name = name; uc->func = func; if (old_uc) { old_uc->next = uc; } else { uwsgi.configurators = uc; } return uc; } int uwsgi_logic_opt_if_exists(char *key, char *value) { if (uwsgi_file_exists(uwsgi.logic_opt_data)) { add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0); return 1; } return 0; } int uwsgi_logic_opt_if_not_exists(char *key, char *value) { if (!uwsgi_file_exists(uwsgi.logic_opt_data)) { add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0); return 1; } return 0; } int uwsgi_logic_opt_for(char *key, char *value) { char *p, *ctx = NULL; uwsgi_foreach_token(uwsgi.logic_opt_data, " ", p, ctx) { add_exported_option(key, uwsgi_substitute(value, "%(_)", p), 0); } return 1; } int uwsgi_logic_opt_for_glob(char *key, char *value) { glob_t g; int i; if (glob(uwsgi.logic_opt_data, GLOB_MARK | GLOB_NOCHECK, NULL, &g)) { uwsgi_error("uwsgi_logic_opt_for_glob()"); return 0; } for (i = 0; i < (int) g.gl_pathc; i++) { add_exported_option(key, uwsgi_substitute(value, "%(_)", g.gl_pathv[i]), 0); } globfree(&g); return 1; } int uwsgi_logic_opt_for_readline(char *key, char *value) { char line[1024]; FILE *fh = fopen(uwsgi.logic_opt_data, "r"); if (fh) { while (fgets(line, 1024, fh)) { add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi_chomp(uwsgi_str(line))), 0); } fclose(fh); return 1; } uwsgi_error_open(uwsgi.logic_opt_data); return 0; } int uwsgi_logic_opt_for_times(char *key, char *value) { int num = atoi(uwsgi.logic_opt_data); int i; char str_num[11]; for (i = 1; i <= num; i++) { int ret = uwsgi_num2str2(i, str_num); // security check if (ret < 0 || ret > 11) { exit(1); } add_exported_option(key, uwsgi_substitute(value, "%(_)", str_num), 0); } return 1; } int uwsgi_logic_opt_if_opt(char *key, char *value) { // check for env-value syntax char *equal = strchr(uwsgi.logic_opt_data, '='); if (equal) *equal = 0; char *p = uwsgi_get_exported_opt(uwsgi.logic_opt_data); if (equal) *equal = '='; if (p) { if (equal) { if (strcmp(equal + 1, p)) return 0; } add_exported_option(key, uwsgi_substitute(value, "%(_)", p), 0); return 1; } return 0; } int uwsgi_logic_opt_if_not_opt(char *key, char *value) { // check for env-value syntax char *equal = strchr(uwsgi.logic_opt_data, '='); if (equal) *equal = 0; char *p = uwsgi_get_exported_opt(uwsgi.logic_opt_data); if (equal) *equal = '='; if (p) { if (equal) { if (!strcmp(equal + 1, p)) return 0; } else { return 0; } } add_exported_option(key, uwsgi_substitute(value, "%(_)", p), 0); return 1; } int uwsgi_logic_opt_if_env(char *key, char *value) { // check for env-value syntax char *equal = strchr(uwsgi.logic_opt_data, '='); if (equal) *equal = 0; char *p = getenv(uwsgi.logic_opt_data); if (equal) *equal = '='; if (p) { if (equal) { if (strcmp(equal + 1, p)) return 0; } add_exported_option(key, uwsgi_substitute(value, "%(_)", p), 0); return 1; } return 0; } int uwsgi_logic_opt_if_not_env(char *key, char *value) { // check for env-value syntax char *equal = strchr(uwsgi.logic_opt_data, '='); if (equal) *equal = 0; char *p = getenv(uwsgi.logic_opt_data); if (equal) *equal = '='; if (p) { if (equal) { if (!strcmp(equal + 1, p)) return 0; } else { return 0; } } add_exported_option(key, uwsgi_substitute(value, "%(_)", p), 0); return 1; } int uwsgi_logic_opt_if_reload(char *key, char *value) { if (uwsgi.is_a_reload) { add_exported_option(key, value, 0); return 1; } return 0; } int uwsgi_logic_opt_if_not_reload(char *key, char *value) { if (!uwsgi.is_a_reload) { add_exported_option(key, value, 0); return 1; } return 0; } int uwsgi_logic_opt_if_file(char *key, char *value) { if (uwsgi_is_file(uwsgi.logic_opt_data)) { add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0); return 1; } return 0; } int uwsgi_logic_opt_if_not_file(char *key, char *value) { if (!uwsgi_is_file(uwsgi.logic_opt_data)) { add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0); return 1; } return 0; } int uwsgi_logic_opt_if_dir(char *key, char *value) { if (uwsgi_is_dir(uwsgi.logic_opt_data)) { add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0); return 1; } return 0; } int uwsgi_logic_opt_if_not_dir(char *key, char *value) { if (!uwsgi_is_dir(uwsgi.logic_opt_data)) { add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0); return 1; } return 0; } int uwsgi_logic_opt_if_plugin(char *key, char *value) { if (plugin_already_loaded(uwsgi.logic_opt_data)) { add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0); return 1; } return 0; } int uwsgi_logic_opt_if_not_plugin(char *key, char *value) { if (!plugin_already_loaded(uwsgi.logic_opt_data)) { add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0); return 1; } return 0; } int uwsgi_logic_opt_if_hostname(char *key, char *value) { if (!strcmp(uwsgi.hostname, uwsgi.logic_opt_data)) { add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0); return 1; } return 0; } int uwsgi_logic_opt_if_not_hostname(char *key, char *value) { if (strcmp(uwsgi.hostname, uwsgi.logic_opt_data)) { add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0); return 1; } return 0; } #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) int uwsgi_logic_opt_if_hostname_match(char *key, char *value) { if (uwsgi_regexp_match_pattern(uwsgi.logic_opt_data, uwsgi.hostname)) { add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0); return 1; } return 0; } int uwsgi_logic_opt_if_not_hostname_match(char *key, char *value) { if (!uwsgi_regexp_match_pattern(uwsgi.logic_opt_data, uwsgi.hostname)) { add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0); return 1; } return 0; } #endif int uwsgi_count_options(struct uwsgi_option *uopt) { struct uwsgi_option *aopt; int count = 0; while ((aopt = uopt)) { if (!aopt->name) break; count++; uopt++; } return count; } int uwsgi_opt_exists(char *name) { struct uwsgi_option *op = uwsgi.options; while (op->name) { if (!strcmp(name, op->name)) return 1; op++; } return 0; } /* avoid loops here !!! */ struct uwsgi_option *uwsgi_opt_get(char *name) { struct uwsgi_option *op; int round = 0; retry: round++; if (round > 2) goto end; op = uwsgi.options; while (op->name) { if (!strcmp(name, op->name)) { return op; } op++; } if (uwsgi.autoload) { if (uwsgi_try_autoload(name)) goto retry; } end: if (uwsgi.strict) { uwsgi_log("[strict-mode] unknown config directive: %s\n", name); exit(1); } return NULL; } void add_exported_option(char *key, char *value, int configured) { add_exported_option_do(key, value, configured, 0); } void add_exported_option_do(char *key, char *value, int configured, int placeholder_only) { struct uwsgi_string_list *blacklist = uwsgi.blacklist; struct uwsgi_string_list *whitelist = uwsgi.whitelist; while (blacklist) { if (!strcmp(key, blacklist->value)) { uwsgi_log("uWSGI error: forbidden option \"%s\" (by blacklist)\n", key); exit(1); } blacklist = blacklist->next; } if (whitelist) { int allowed = 0; while (whitelist) { if (!strcmp(key, whitelist->value)) { allowed = 1; break; } whitelist = whitelist->next; } if (!allowed) { uwsgi_log("uWSGI error: forbidden option \"%s\" (by whitelist)\n", key); exit(1); } } if (uwsgi.blacklist_context) { if (uwsgi_list_has_str(uwsgi.blacklist_context, key)) { uwsgi_log("uWSGI error: forbidden option \"%s\" (by blacklist)\n", key); exit(1); } } if (uwsgi.whitelist_context) { if (!uwsgi_list_has_str(uwsgi.whitelist_context, key)) { uwsgi_log("uWSGI error: forbidden option \"%s\" (by whitelist)\n", key); exit(1); } } if (uwsgi.logic_opt_running) goto add; if (!strcmp(key, "end") || !strcmp(key, "endfor") || !strcmp(key, "endif") || !strcmp(key, "end-if") || !strcmp(key, "end-for")) { if (uwsgi.logic_opt_data) { free(uwsgi.logic_opt_data); } uwsgi.logic_opt = NULL; uwsgi.logic_opt_arg = NULL; uwsgi.logic_opt_cycles = 0; uwsgi.logic_opt_data = NULL; } if (uwsgi.logic_opt) { if (uwsgi.logic_opt_data) { free(uwsgi.logic_opt_data); } uwsgi.logic_opt_data = uwsgi_str(uwsgi.logic_opt_arg); uwsgi.logic_opt_cycles++; uwsgi.logic_opt_running = 1; uwsgi.logic_opt(key, value); uwsgi.logic_opt_running = 0; return; } add: if (!uwsgi.exported_opts) { uwsgi.exported_opts = uwsgi_malloc(sizeof(struct uwsgi_opt *)); } else { uwsgi.exported_opts = realloc(uwsgi.exported_opts, sizeof(struct uwsgi_opt *) * (uwsgi.exported_opts_cnt + 1)); if (!uwsgi.exported_opts) { uwsgi_error("realloc()"); exit(1); } } int id = uwsgi.exported_opts_cnt; uwsgi.exported_opts[id] = uwsgi_malloc(sizeof(struct uwsgi_opt)); uwsgi.exported_opts[id]->key = key; uwsgi.exported_opts[id]->value = value; uwsgi.exported_opts[id]->configured = configured; uwsgi.exported_opts_cnt++; uwsgi.dirty_config = 1; if (placeholder_only) { if (uwsgi_opt_exists(key)) { uwsgi_log("you cannot use %s as a placeholder, it is already available as an option\n"); exit(1); } uwsgi.exported_opts[id]->configured = 1; return; } struct uwsgi_option *op = uwsgi_opt_get(key); if (op) { // requires master ? if (op->flags & UWSGI_OPT_MASTER) { uwsgi.master_process = 1; } // requires log_master ? if (op->flags & UWSGI_OPT_LOG_MASTER) { uwsgi.master_process = 1; uwsgi.log_master = 1; } if (op->flags & UWSGI_OPT_REQ_LOG_MASTER) { uwsgi.master_process = 1; uwsgi.log_master = 1; uwsgi.req_log_master = 1; } // requires threads ? if (op->flags & UWSGI_OPT_THREADS) { uwsgi.has_threads = 1; } // requires cheaper mode ? if (op->flags & UWSGI_OPT_CHEAPER) { uwsgi.cheaper = 1; } // requires virtualhosting ? if (op->flags & UWSGI_OPT_VHOST) { uwsgi.vhost = 1; } // requires memusage ? if (op->flags & UWSGI_OPT_MEMORY) { uwsgi.force_get_memusage = 1; } // requires auto procname ? if (op->flags & UWSGI_OPT_PROCNAME) { uwsgi.auto_procname = 1; } // requires lazy ? if (op->flags & UWSGI_OPT_LAZY) { uwsgi.lazy = 1; } // requires no_initial ? if (op->flags & UWSGI_OPT_NO_INITIAL) { uwsgi.no_initial_output = 1; } // requires no_server ? if (op->flags & UWSGI_OPT_NO_SERVER) { uwsgi.no_server = 1; } // requires post_buffering ? if (op->flags & UWSGI_OPT_POST_BUFFERING) { if (!uwsgi.post_buffering) uwsgi.post_buffering = 4096; } // requires building mime dict ? if (op->flags & UWSGI_OPT_MIME) { uwsgi.build_mime_dict = 1; } // enable metrics ? if (op->flags & UWSGI_OPT_METRICS) { uwsgi.has_metrics = 1; } // immediate ? if (op->flags & UWSGI_OPT_IMMEDIATE) { op->func(key, value, op->data); uwsgi.exported_opts[id]->configured = 1; } } } void uwsgi_fallback_config() { if (uwsgi.fallback_config && uwsgi.last_exit_code == 1) { uwsgi_log_verbose("!!! %s (pid: %d) exited with status %d !!!\n", uwsgi.binary_path, (int) getpid(), uwsgi.last_exit_code); uwsgi_log_verbose("!!! Fallback config to %s !!!\n", uwsgi.fallback_config); char *argv[3]; argv[0] = uwsgi.binary_path; argv[1] = uwsgi.fallback_config; argv[2] = NULL; execvp(uwsgi.binary_path, argv); uwsgi_error("execvp()"); // never here } } int uwsgi_manage_opt(char *key, char *value) { struct uwsgi_option *op = uwsgi_opt_get(key); if (op) { op->func(key, value, op->data); return 1; } return 0; } void uwsgi_configure() { int i; // and now apply the remaining configs restart: for (i = 0; i < uwsgi.exported_opts_cnt; i++) { if (uwsgi.exported_opts[i]->configured) continue; uwsgi.dirty_config = 0; uwsgi.exported_opts[i]->configured = uwsgi_manage_opt(uwsgi.exported_opts[i]->key, uwsgi.exported_opts[i]->value); // some option could cause a dirty config tree if (uwsgi.dirty_config) goto restart; } } void uwsgi_opt_custom(char *key, char *value, void *data ) { struct uwsgi_custom_option *uco = (struct uwsgi_custom_option *)data; size_t i, count = 1; size_t value_len = 0; if (value) value_len = strlen(value); off_t pos = 0; char **opt_argv; char *tmp_val = NULL, *p = NULL; // now count the number of args for (i = 0; i < value_len; i++) { if (value[i] == ' ') { count++; } } // allocate a tmp array opt_argv = uwsgi_calloc(sizeof(char *) * count); //make a copy of the value; if (value_len > 0) { tmp_val = uwsgi_str(value); // fill the array of options char *p, *ctx = NULL; uwsgi_foreach_token(tmp_val, " ", p, ctx) { opt_argv[pos] = p; pos++; } } else { // no argument specified opt_argv[0] = ""; } #ifdef UWSGI_DEBUG uwsgi_log("found custom option %s with %d args\n", key, count); #endif // now make a copy of the option template char *tmp_opt = uwsgi_str(uco->value); // split it char *ctx = NULL; uwsgi_foreach_token(tmp_opt, ";", p, ctx) { char *equal = strchr(p, '='); if (!equal) goto clear; *equal = '\0'; // build the key char *new_key = uwsgi_str(p); for (i = 0; i < count; i++) { char *old_key = new_key; char *tmp_num = uwsgi_num2str(i + 1); char *placeholder = uwsgi_concat2((char *) "$", tmp_num); free(tmp_num); new_key = uwsgi_substitute(old_key, placeholder, opt_argv[i]); if (new_key != old_key) free(old_key); free(placeholder); } // build the value char *new_value = uwsgi_str(equal + 1); for (i = 0; i < count; i++) { char *old_value = new_value; char *tmp_num = uwsgi_num2str(i + 1); char *placeholder = uwsgi_concat2((char *) "$", tmp_num); free(tmp_num); new_value = uwsgi_substitute(old_value, placeholder, opt_argv[i]); if (new_value != old_value) free(old_value); free(placeholder); } // ignore return value here uwsgi_manage_opt(new_key, new_value); } clear: free(tmp_val); free(tmp_opt); free(opt_argv); } char *uwsgi_get_exported_opt(char *key) { int i; for (i = 0; i < uwsgi.exported_opts_cnt; i++) { if (!strcmp(uwsgi.exported_opts[i]->key, key)) { return uwsgi.exported_opts[i]->value; } } return NULL; } char *uwsgi_get_optname_by_index(int index) { struct uwsgi_option *op = uwsgi.options; while (op->name) { if (op->shortcut == index) { return op->name; } op++; } return NULL; } /* this works as a pipeline processes = 2 cpu_cores = 8 foobar = %(processes cpu_cores + 2) translate as: step1 = proceses cpu_cores = 2 8 = 28 (string concatenation) step1 + = step1_apply_func_plus (func token) step1_apply_func_plus 2 = 28 + 2 = 30 (math) */ char *uwsgi_manage_placeholder(char *key) { enum { concat = 0, sum, sub, mul, div, } state; state = concat; char *current_value = NULL; char *space = strchr(key, ' '); if (!space) { return uwsgi_get_exported_opt(key); } // let's start the heavy metal here char *tmp_value = uwsgi_str(key); char *p, *ctx = NULL; uwsgi_foreach_token(tmp_value, " ", p, ctx) { char *value = NULL; if (is_a_number(p)) { value = uwsgi_str(p); } else if (!strcmp(p, "+")) { state = sum; continue; } else if (!strcmp(p, "-")) { state = sub; continue; } else if (!strcmp(p, "*")) { state = mul; continue; } else if (!strcmp(p, "/")) { state = div; continue; } else if (!strcmp(p, "++")) { if (current_value) { int64_t tmp_num = strtoll(current_value, NULL, 10); free(current_value); current_value = uwsgi_64bit2str(tmp_num+1); } state = concat; continue; } else if (!strcmp(p, "--")) { if (current_value) { int64_t tmp_num = strtoll(current_value, NULL, 10); free(current_value); current_value = uwsgi_64bit2str(tmp_num-1); } state = concat; continue; } // find the option else { char *ov = uwsgi_get_exported_opt(p); if (!ov) ov = ""; value = uwsgi_str(ov); } int64_t arg1n = 0, arg2n = 0; char *arg1 = "", *arg2 = ""; switch(state) { case concat: if (current_value) arg1 = current_value; if (value) arg2 = value; char *ret = uwsgi_concat2(arg1, arg2); if (current_value) free(current_value); current_value = ret; break; case sum: if (current_value) arg1n = strtoll(current_value, NULL, 10); if (value) arg2n = strtoll(value, NULL, 10); if (current_value) free(current_value); current_value = uwsgi_64bit2str(arg1n + arg2n); break; case sub: if (current_value) arg1n = strtoll(current_value, NULL, 10); if (value) arg2n = strtoll(value, NULL, 10); if (current_value) free(current_value); current_value = uwsgi_64bit2str(arg1n - arg2n); break; case mul: if (current_value) arg1n = strtoll(current_value, NULL, 10); if (value) arg2n = strtoll(value, NULL, 10); if (current_value) free(current_value); current_value = uwsgi_64bit2str(arg1n * arg2n); break; case div: if (current_value) arg1n = strtoll(current_value, NULL, 10); if (value) arg2n = strtoll(value, NULL, 10); if (current_value) free(current_value); // avoid division by zero if (arg2n == 0) { current_value = uwsgi_64bit2str(0); } else { current_value = uwsgi_64bit2str(arg1n / arg2n); } break; default: break; } // over engineering if (value) free(value); // reset state to concat state = concat; } free(tmp_value); return current_value; } void uwsgi_opt_resolve(char *opt, char *value, void *foo) { char *equal = strchr(value, '='); if (!equal) { uwsgi_log("invalid resolve syntax, must be placeholder=domain\n"); exit(1); } char *ip = uwsgi_resolve_ip(equal+1); if (!ip) { uwsgi_log("unable to resolve name %s\n", equal+1); uwsgi_error("uwsgi_resolve_ip()"); exit(1); } char *new_opt = uwsgi_concat2n(value, (equal-value)+1, ip, strlen(ip)); uwsgi_opt_set_placeholder(opt, new_opt, (void *) 1); } uwsgi-2.0.29/core/cookie.c000066400000000000000000000031011477626554400153260ustar00rootroot00000000000000#include "uwsgi.h" /* cookie management functions (mainly used by the internal routing subsystem) */ static char *check_cookie(char *cookie, uint16_t cookie_len, char *key, uint16_t keylen, uint16_t *vallen) { uint16_t orig_cookie_len = cookie_len-1; // first lstrip white spaces char *ptr = cookie; uint16_t i; for(i=0;i0;i--) { if (isspace((int)ptr[i])) { cookie_len--; } else { break; } } // now search for the first equal sign char *equal = memchr(cookie, '=', cookie_len); if (!equal) return NULL; if (uwsgi_strncmp(key, keylen, cookie, equal-cookie)) { return NULL; } cookie_len -= (equal-cookie)+1; if (cookie_len == 0) return NULL; *vallen = cookie_len; return equal+1; } char *uwsgi_get_cookie(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) { uint16_t i; char *cookie = wsgi_req->cookie; uint16_t cookie_len = 0; char *ptr = wsgi_req->cookie; //start splitting by ; for(i=0;icookie_len;i++) { if (!cookie) { cookie = ptr + i; } if (ptr[i] == ';') { char *value = check_cookie(cookie, cookie_len, key, keylen, vallen); if (value) { return value; } cookie_len = 0; cookie = NULL; } else { cookie_len++; } } if (cookie_len > 0) { char *value = check_cookie(cookie, cookie_len, key, keylen, vallen); if (value) { return value; } } return NULL; } uwsgi-2.0.29/core/cron.c000066400000000000000000000205611477626554400150270ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; struct uwsgi_cron *uwsgi_cron_add(char *crontab) { int i; struct uwsgi_cron *old_uc, *uc = uwsgi.crons; if (!uc) { uc = uwsgi_malloc(sizeof(struct uwsgi_cron)); uwsgi.crons = uc; } else { old_uc = uc; while (uc->next) { uc = uc->next; old_uc = uc; } old_uc->next = uwsgi_malloc(sizeof(struct uwsgi_cron)); uc = old_uc->next; } memset(uc, 0, sizeof(struct uwsgi_cron)); if (sscanf(crontab, "%d %d %d %d %d %n", &uc->minute, &uc->hour, &uc->day, &uc->month, &uc->week, &i) != 5) { uwsgi_log("invalid cron syntax\n"); exit(1); } uc->command = crontab + i; uc->pid = -1; return uc; } void uwsgi_opt_add_cron(char *opt, char *value, void *foobar) { uwsgi_cron_add(value); } void uwsgi_opt_add_unique_cron(char *opt, char *value, void *foobar) { struct uwsgi_cron *uc = uwsgi_cron_add(value); uc->unique = 1; } #ifdef UWSGI_SSL void uwsgi_opt_add_legion_cron(char *opt, char *value, void *foobar) { char *space = strchr(value, ' '); if (!space) { uwsgi_log("invalid %s syntax, must be prefixed with a legion name\n", opt); exit(1); } char *legion = uwsgi_concat2n(value, space-value, "", 0); struct uwsgi_cron *uc = uwsgi_cron_add(space+1); uc->legion = legion; } void uwsgi_opt_add_unique_legion_cron(char *opt, char *value, void *foobar) { char *space = strchr(value, ' '); if (!space) { uwsgi_log("invalid %s syntax, must be prefixed with a legion name\n", opt); exit(1); } char *legion = uwsgi_concat2n(value, space-value, "", 0); struct uwsgi_cron *uc = uwsgi_cron_add(space+1); uc->legion = legion; uc->unique = 1; } #endif void uwsgi_opt_add_cron2(char *opt, char *value, void *foobar) { char *c_minute = NULL; char *c_hour = NULL; char *c_day = NULL; char *c_month = NULL; char *c_week = NULL; char *c_unique = NULL; char *c_harakiri = NULL; char *c_legion = NULL; char *c_command = value; char *space = strchr(value, ' '); if (space) { if (uwsgi_str_contains(value, space - value, '=')) { // --cron2 key=val command *space = 0; c_command = space + 1; } // no point in parsing key=val list if there is none if (uwsgi_kvlist_parse(value, strlen(value), ',', '=', "minute", &c_minute, "hour", &c_hour, "day", &c_day, "month", &c_month, "week", &c_week, "unique", &c_unique, "harakiri", &c_harakiri, "legion", &c_legion, NULL)) { uwsgi_log("unable to parse cron definition: %s\n", value); exit(1); } } else { if (uwsgi_str_contains(value, strlen(value), '=')) { // --cron2 key=val uwsgi_log("unable to parse cron definition: %s\n", value); exit(1); } } struct uwsgi_cron *old_uc, *uc = uwsgi.crons; if (!uc) { uc = uwsgi_malloc(sizeof(struct uwsgi_cron)); uwsgi.crons = uc; } else { old_uc = uc; while (uc->next) { uc = uc->next; old_uc = uc; } old_uc->next = uwsgi_malloc(sizeof(struct uwsgi_cron)); uc = old_uc->next; } memset(uc, 0, sizeof(struct uwsgi_cron)); uc->command = c_command; if (!uc->command) { uwsgi_log("[uwsgi-cron] invalid command in cron definition: %s\n", value); exit(1); } // defaults uc->minute = -1; uc->hour = -1; uc->day = -1; uc->month = -1; uc->week = -1; uc->unique = 0; uc->mercy = 0; uc->harakiri = 0; uc->pid = -1; #ifdef UWSGI_SSL uc->legion = c_legion; #endif if (c_minute) uc->minute = atoi(c_minute); if (c_hour) uc->hour = atoi(c_hour); if (c_day) uc->day = atoi(c_day); if (c_month) uc->month = atoi(c_month); if (c_week) uc->week = atoi(c_week); if (c_unique) uc->unique = atoi(c_unique); if (c_harakiri) { if (atoi(c_harakiri)) { // harakiri > 0 uc->mercy = atoi(c_harakiri); } else { // harakiri == 0 uc->mercy = -1; } } else if (uwsgi.cron_harakiri) { uc->harakiri = uwsgi.cron_harakiri; } } int uwsgi_signal_add_cron(uint8_t sig, int minute, int hour, int day, int month, int week) { if (!uwsgi.master_process) return -1; uwsgi_lock(uwsgi.cron_table_lock); if (ushared->cron_cnt < MAX_CRONS) { ushared->cron[ushared->cron_cnt].sig = sig; ushared->cron[ushared->cron_cnt].minute = minute; ushared->cron[ushared->cron_cnt].hour = hour; ushared->cron[ushared->cron_cnt].day = day; ushared->cron[ushared->cron_cnt].month = month; ushared->cron[ushared->cron_cnt].week = week; ushared->cron_cnt++; } else { uwsgi_log("you can register max %d cron !!!\n", MAX_CRONS); uwsgi_unlock(uwsgi.cron_table_lock); return -1; } uwsgi_unlock(uwsgi.cron_table_lock); return 0; } void uwsgi_manage_signal_cron(time_t now) { struct tm *uwsgi_cron_delta; int i; uwsgi_cron_delta = localtime(&now); if (uwsgi_cron_delta) { // fix month uwsgi_cron_delta->tm_mon++; uwsgi_lock(uwsgi.cron_table_lock); for (i = 0; i < ushared->cron_cnt; i++) { struct uwsgi_cron *ucron = &ushared->cron[i]; int run_task = uwsgi_cron_task_needs_execution(uwsgi_cron_delta, ucron->minute, ucron->hour, ucron->day, ucron->month, ucron->week); if (run_task == 1) { // date match, signal it ? if (now - ucron->last_job >= 60) { uwsgi_log_verbose("[uwsgi-cron] routing signal %d\n", ucron->sig); uwsgi_route_signal(ucron->sig); ucron->last_job = now; } } } uwsgi_unlock(uwsgi.cron_table_lock); } else { uwsgi_error("localtime()"); } } void uwsgi_manage_command_cron(time_t now) { struct tm *uwsgi_cron_delta; struct uwsgi_cron *current_cron = uwsgi.crons; uwsgi_cron_delta = localtime(&now); if (!uwsgi_cron_delta) { uwsgi_error("uwsgi_manage_command_cron()/localtime()"); return; } // fix month uwsgi_cron_delta->tm_mon++; while (current_cron) { #ifdef UWSGI_SSL // check for legion cron if (current_cron->legion) { if (!uwsgi_legion_i_am_the_lord(current_cron->legion)) goto next; } #endif // skip unique crons that are still running if (current_cron->unique && current_cron->pid >= 0) goto next; int run_task = uwsgi_cron_task_needs_execution(uwsgi_cron_delta, current_cron->minute, current_cron->hour, current_cron->day, current_cron->month, current_cron->week); if (run_task == 1) { // date match, run command ? if (now - current_cron->last_job >= 60) { //call command if (current_cron->command) { if (current_cron->func) { current_cron->func(current_cron, now); } else { pid_t pid = uwsgi_run_command(current_cron->command, NULL, -1); if (pid >= 0) { current_cron->pid = pid; current_cron->started_at = now; uwsgi_log_verbose("[uwsgi-cron] running \"%s\" (pid %d)\n", current_cron->command, current_cron->pid); if (current_cron->mercy) { //uwsgi_cron->mercy can be negative to inform master that harakiri should be disabled for this cron if (current_cron->mercy > 0) current_cron->harakiri = now + current_cron->mercy; } else if (uwsgi.cron_harakiri) current_cron->harakiri = now + uwsgi.cron_harakiri; } } } current_cron->last_job = now; } } next: current_cron = current_cron->next; } } uwsgi-2.0.29/core/daemons.c000066400000000000000000000366461477626554400155270ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; /* External uwsgi daemons There are 3 kinds of daemons (read: external applications) that can be managed by uWSGI. 1) dumb daemons (attached with --attach-daemon) they must not daemonize() and when they exit() the master is notified (via waitpid) and the process is respawned 2) smart daemons with daemonization you specify a pidfile and a command - on startup - if the pidfile does not exist or contains a non-available pid (checked with kill(pid, 0)) the daemon is respawned - on master check - if the pidfile does not exist or if it points to a non-existent pid the daemon is respawned 3) smart daemons without daemonization same as 2, but the daemonization and pidfile creation are managed by uWSGI status: 0 -> never started 1 -> just started 2 -> started and monitored (only in pidfile based) */ void uwsgi_daemons_smart_check() { static time_t last_run = 0; time_t now = uwsgi_now(); if (now - last_run <= 0) { return; } last_run = now; struct uwsgi_daemon *ud = uwsgi.daemons; while (ud) { #ifdef UWSGI_SSL if (ud->legion) { if (uwsgi_legion_i_am_the_lord(ud->legion)) { // lord, spawn if not running if (ud->pid <= 0) { uwsgi_spawn_daemon(ud); } } else { // not lord, kill daemon if running if (ud->pid > 0) { if (!kill(ud->pid, 0)) { uwsgi_log("[uwsgi_daemons] stopping legion \"%s\" daemon: %s (pid: %d)\n", ud->legion, ud->command, ud->pid); kill(-(ud->pid), ud->stop_signal); } else { // pid already died ud->pid = -1; } } ud = ud->next; continue; } } #endif if (ud->pidfile) { int checked_pid = uwsgi_check_pidfile(ud->pidfile); if (checked_pid <= 0) { // monitored instance if (ud->status == 2) { uwsgi_spawn_daemon(ud); } else { ud->pidfile_checks++; if (ud->pidfile_checks >= (unsigned int) ud->freq) { if (!ud->has_daemonized) { uwsgi_log_verbose("[uwsgi-daemons] \"%s\" (pid: %d) did not daemonize !!!\n", ud->command, (int) ud->pid); ud->pidfile_checks = 0; } else { uwsgi_log("[uwsgi-daemons] found changed pidfile for \"%s\" (old_pid: %d new_pid: %d)\n", ud->command, (int) ud->pid, (int) checked_pid); uwsgi_spawn_daemon(ud); } } } } else if (checked_pid != ud->pid) { uwsgi_log("[uwsgi-daemons] found changed pid for \"%s\" (old_pid: %d new_pid: %d)\n", ud->command, (int) ud->pid, (int) checked_pid); ud->pid = checked_pid; } // all ok, pidfile and process found else { ud->status = 2; } } ud = ud->next; } } // this function is called when a dumb daemon dies and we do not want to respawn it int uwsgi_daemon_check_pid_death(pid_t diedpid) { struct uwsgi_daemon *ud = uwsgi.daemons; while (ud) { if (ud->pid == diedpid) { if (!ud->pidfile) { uwsgi_log("daemon \"%s\" (pid: %d) annihilated\n", ud->command, (int) diedpid); ud->pid = -1; return -1; } else { if (!ud->has_daemonized) { ud->has_daemonized = 1; } else { uwsgi_log("[uwsgi-daemons] BUG !!! daemon \"%s\" has already daemonized !!!\n", ud->command); } } } ud = ud->next; } return 0; } // this function is called when a dumb daemon dies and we want to respawn it int uwsgi_daemon_check_pid_reload(pid_t diedpid) { struct uwsgi_daemon *ud = uwsgi.daemons; while (ud) { #ifdef UWSGI_SSL if (ud->pid == diedpid && ud->legion && !uwsgi_legion_i_am_the_lord(ud->legion)) { // part of legion but not lord, don't respawn ud->pid = -1; uwsgi_log("uwsgi-daemons] legion \"%s\" daemon \"%s\" (pid: %d) annihilated\n", ud->legion, ud->command, (int) diedpid); ud = ud->next; continue; } #endif if (ud->pid == diedpid && !ud->pidfile) { if (ud->control) { gracefully_kill_them_all(0); return 0; } uwsgi_spawn_daemon(ud); return 1; } ud = ud->next; } return 0; } int uwsgi_check_pidfile(char *filename) { struct stat st; pid_t ret = -1; int fd = open(filename, O_RDONLY); if (fd < 0) { uwsgi_error_open(filename); goto end; } if (fstat(fd, &st)) { uwsgi_error("fstat()"); goto end2; } char *pidstr = uwsgi_calloc(st.st_size + 1); if (read(fd, pidstr, st.st_size) != st.st_size) { uwsgi_error("read()"); goto end3; } pid_t pid = atoi(pidstr); if (pid <= 0) goto end3; if (!kill(pid, 0)) { ret = pid; } end3: free(pidstr); end2: close(fd); end: return ret; } void uwsgi_daemons_spawn_all() { struct uwsgi_daemon *ud = uwsgi.daemons; while (ud) { if (!ud->registered) { #ifdef UWSGI_SSL if (ud->legion && !uwsgi_legion_i_am_the_lord(ud->legion)) { // part of legion, register but don't spawn it yet if (ud->pidfile) { ud->pid = uwsgi_check_pidfile(ud->pidfile); if (ud->pid > 0) uwsgi_log("[uwsgi-daemons] found valid/active pidfile for \"%s\" (pid: %d)\n", ud->command, (int) ud->pid); } ud->registered = 1; ud = ud->next; continue; } #endif ud->registered = 1; if (ud->pidfile) { int checked_pid = uwsgi_check_pidfile(ud->pidfile); if (checked_pid <= 0) { uwsgi_spawn_daemon(ud); } else { ud->pid = checked_pid; uwsgi_log("[uwsgi-daemons] found valid/active pidfile for \"%s\" (pid: %d)\n", ud->command, (int) ud->pid); } } else { uwsgi_spawn_daemon(ud); } } ud = ud->next; } } void uwsgi_detach_daemons() { struct uwsgi_daemon *ud = uwsgi.daemons; while (ud) { #ifdef UWSGI_SSL // stop any legion daemon, doesn't matter if dumb or smart if (ud->pid > 0 && (ud->legion || !ud->pidfile)) { #else // stop only dumb daemons if (ud->pid > 0 && !ud->pidfile) { #endif uwsgi_log("[uwsgi-daemons] stopping daemon (pid: %d): %s\n", (int) ud->pid, ud->command); // try to stop daemon gracefully, kill it if it won't die // if mercy is not set then wait up to 3 seconds time_t timeout = uwsgi_now() + (uwsgi.reload_mercy ? uwsgi.reload_mercy : 3); int waitpid_status; while (!kill(ud->pid, 0)) { if (uwsgi_instance_is_reloading && ud->reload_signal > 0) { kill(-(ud->pid), ud->reload_signal); } else { kill(-(ud->pid), ud->stop_signal); } sleep(1); waitpid(ud->pid, &waitpid_status, WNOHANG); if (uwsgi_now() >= timeout) { uwsgi_log("[uwsgi-daemons] daemon did not die in time, killing (pid: %d): %s\n", (int) ud->pid, ud->command); kill(-(ud->pid), SIGKILL); break; } } // unregister daemon to prevent it from being respawned ud->registered = 0; } // smart daemons that have to be notified when master is reloading or stopping if (ud->notifypid && ud->pid > 0 && ud->pidfile) { if (uwsgi_instance_is_reloading) { kill(-(ud->pid), ud->reload_signal > 0 ? ud->reload_signal : SIGHUP); } else { kill(-(ud->pid), ud->stop_signal); } } ud = ud->next; } } static int daemon_spawn(void *); void uwsgi_spawn_daemon(struct uwsgi_daemon *ud) { // skip unregistered daemons if (!ud->registered) return; ud->throttle = 0; if (uwsgi.current_time - ud->last_spawn <= 3) { ud->throttle = ud->respawns - (uwsgi.current_time - ud->last_spawn); // if ud->respawns == 0 then we can end up with throttle < 0 if (ud->throttle <= 0) ud->throttle = 1; if (ud->max_throttle > 0 ) { if (ud->throttle > ud->max_throttle) { ud->throttle = ud->max_throttle; } } // use an arbitrary value (5 minutes to avoid endless sleeps...) else if (ud->throttle > 300) { ud->throttle = 300; } } pid_t pid = uwsgi_fork("uWSGI external daemon"); if (pid < 0) { uwsgi_error("fork()"); return; } if (pid > 0) { ud->has_daemonized = 0; ud->pid = pid; ud->status = 1; ud->pidfile_checks = 0; if (ud->respawns == 0) { ud->born = uwsgi_now(); } ud->respawns++; ud->last_spawn = uwsgi_now(); } else { // close uwsgi sockets uwsgi_close_all_sockets(); uwsgi_close_all_fds(); if (ud->chdir) { if (chdir(ud->chdir)) { uwsgi_error("uwsgi_spawn_daemon()/chdir()"); exit(1); } } #if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL) && defined(CLONE_NEWPID) if (ud->ns_pid) { // we need to create a new session if (setsid() < 0) { uwsgi_error("uwsgi_spawn_daemon()/setsid()"); exit(1); } // avoid the need to set stop_signal in attach-daemon2 signal(SIGTERM, end_me); char stack[PTHREAD_STACK_MIN]; pid_t pid = clone((int (*)(void *))daemon_spawn, stack + PTHREAD_STACK_MIN, SIGCHLD | CLONE_NEWPID, (void *) ud); if (pid > 0) { #ifdef PR_SET_PDEATHSIG if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) { uwsgi_error("uwsgi_spawn_daemon()/prctl()"); } #endif // block all signals except SIGTERM sigset_t smask; sigfillset(&smask); sigdelset(&smask, SIGTERM); sigprocmask(SIG_BLOCK, &smask, NULL); int status; if (waitpid(pid, &status, 0) < 0) { uwsgi_error("uwsgi_spawn_daemon()/waitpid()"); } _exit(0); } uwsgi_error("uwsgi_spawn_daemon()/clone()"); exit(1); } #endif daemon_spawn((void *) ud); } } static int daemon_spawn(void *arg) { struct uwsgi_daemon *ud = (struct uwsgi_daemon *) arg; if (ud->gid) { if (setgid(ud->gid)) { uwsgi_error("uwsgi_spawn_daemon()/setgid()"); exit(1); } } if (ud->uid) { if (setuid(ud->uid)) { uwsgi_error("uwsgi_spawn_daemon()/setuid()"); exit(1); } } if (ud->daemonize) { /* refork... */ pid_t pid = fork(); if (pid < 0) { uwsgi_error("fork()"); exit(1); } if (pid != 0) { _exit(0); } uwsgi_write_pidfile(ud->pidfile); } if (!uwsgi.daemons_honour_stdin && !ud->honour_stdin) { // /dev/null will became stdin uwsgi_remap_fd(0, "/dev/null"); } if (setsid() < 0) { uwsgi_error("setsid()"); exit(1); } if (!ud->pidfile) { #ifdef PR_SET_PDEATHSIG if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) { uwsgi_error("prctl()"); } #endif } if (ud->throttle) { uwsgi_log("[uwsgi-daemons] throttling \"%s\" for %d seconds\n", ud->command, ud->throttle); sleep((unsigned int) ud->throttle); } uwsgi_log("[uwsgi-daemons] %sspawning \"%s\" (uid: %d gid: %d)\n", ud->respawns > 0 ? "re" : "", ud->command, (int) getuid(), (int) getgid()); uwsgi_exec_command_with_args(ud->command); uwsgi_log("[uwsgi-daemons] unable to spawn \"%s\"\n", ud->command); // never here; exit(1); } void uwsgi_opt_add_daemon(char *opt, char *value, void *none) { struct uwsgi_daemon *uwsgi_ud = uwsgi.daemons, *old_ud; char *pidfile = NULL; int daemonize = 0; int freq = 10; char *space = NULL; int stop_signal = SIGTERM; int reload_signal = 0; char *command = uwsgi_str(value); #ifdef UWSGI_SSL char *legion = NULL; if (!uwsgi_starts_with(opt, strlen(command), "legion-", 7)) { space = strchr(command, ' '); if (!space) { uwsgi_log("invalid legion daemon syntax: %s\n", command); exit(1); } *space = 0; legion = command; command = space+1; } #endif if (!strcmp(opt, "smart-attach-daemon") || !strcmp(opt, "smart-attach-daemon2") || !strcmp(opt, "legion-smart-attach-daemon") || !strcmp(opt, "legion-smart-attach-daemon2")) { space = strchr(command, ' '); if (!space) { uwsgi_log("invalid smart-attach-daemon syntax: %s\n", command); exit(1); } *space = 0; pidfile = command; // check for freq char *comma = strchr(pidfile, ','); if (comma) { *comma = 0; freq = atoi(comma + 1); } command = space + 1; if (!strcmp(opt, "smart-attach-daemon2") || !strcmp(opt, "legion-smart-attach-daemon2")) { daemonize = 1; } } if (!uwsgi_ud) { uwsgi.daemons = uwsgi_calloc(sizeof(struct uwsgi_daemon)); uwsgi_ud = uwsgi.daemons; } else { while (uwsgi_ud) { old_ud = uwsgi_ud; uwsgi_ud = uwsgi_ud->next; } uwsgi_ud = uwsgi_calloc(sizeof(struct uwsgi_daemon)); old_ud->next = uwsgi_ud; } uwsgi_ud->command = command; uwsgi_ud->pid = 0; uwsgi_ud->status = 0; uwsgi_ud->freq = freq; uwsgi_ud->registered = 0; uwsgi_ud->next = NULL; uwsgi_ud->respawns = 0; uwsgi_ud->last_spawn = 0; uwsgi_ud->daemonize = daemonize; uwsgi_ud->pidfile = pidfile; uwsgi_ud->control = 0; uwsgi_ud->stop_signal = stop_signal; uwsgi_ud->reload_signal = reload_signal; if (!strcmp(opt, "attach-control-daemon")) { uwsgi_ud->control = 1; } #ifdef UWSGI_SSL uwsgi_ud->legion = legion; #endif uwsgi.daemons_cnt++; } void uwsgi_opt_add_daemon2(char *opt, char *value, void *none) { struct uwsgi_daemon *uwsgi_ud = uwsgi.daemons, *old_ud; char *d_command = NULL; char *d_freq = NULL; char *d_pidfile = NULL; char *d_control = NULL; char *d_legion = NULL; char *d_daemonize = NULL; char *d_touch = NULL; char *d_stopsignal = NULL; char *d_reloadsignal = NULL; char *d_stdin = NULL; char *d_uid = NULL; char *d_gid = NULL; char *d_ns_pid = NULL; char *d_chdir = NULL; char *d_max_throttle = NULL; char *d_notifypid = NULL; char *arg = uwsgi_str(value); if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=', "command", &d_command, "cmd", &d_command, "exec", &d_command, "freq", &d_freq, "pidfile", &d_pidfile, "control", &d_control, "daemonize", &d_daemonize, "daemon", &d_daemonize, "touch", &d_touch, "stopsignal", &d_stopsignal, "stop_signal", &d_stopsignal, "reloadsignal", &d_reloadsignal, "reload_signal", &d_reloadsignal, "stdin", &d_stdin, "uid", &d_uid, "gid", &d_gid, "ns_pid", &d_ns_pid, "chdir", &d_chdir, "max_throttle", &d_max_throttle, "notifypid", &d_notifypid, NULL)) { uwsgi_log("invalid --%s keyval syntax\n", opt); exit(1); } if (!d_command) { uwsgi_log("--%s: you need to specify a 'command' key\n", opt); exit(1); } #ifndef UWSGI_SSL if (d_legion) { uwsgi_log("legion subsystem is not supported on this uWSGI version, rebuild with ssl support\n"); exit(1); } #endif if (!uwsgi_ud) { uwsgi.daemons = uwsgi_calloc(sizeof(struct uwsgi_daemon)); uwsgi_ud = uwsgi.daemons; } else { while (uwsgi_ud) { old_ud = uwsgi_ud; uwsgi_ud = uwsgi_ud->next; } uwsgi_ud = uwsgi_calloc(sizeof(struct uwsgi_daemon)); old_ud->next = uwsgi_ud; } uwsgi_ud->command = d_command; uwsgi_ud->freq = d_freq ? atoi(d_freq) : 10; uwsgi_ud->daemonize = d_daemonize ? 1 : 0; uwsgi_ud->pidfile = d_pidfile; uwsgi_ud->stop_signal = d_stopsignal ? atoi(d_stopsignal) : SIGTERM; uwsgi_ud->reload_signal = d_reloadsignal ? atoi(d_reloadsignal) : 0; uwsgi_ud->control = d_control ? 1 : 0; uwsgi_ud->uid = d_uid ? atoi(d_uid) : 0; uwsgi_ud->gid = d_gid ? atoi(d_gid) : 0; uwsgi_ud->honour_stdin = d_stdin ? 1 : 0; #ifdef UWSGI_SSL uwsgi_ud->legion = d_legion; #endif uwsgi_ud->ns_pid = d_ns_pid ? 1 : 0; uwsgi_ud->chdir = d_chdir; uwsgi_ud->max_throttle = d_max_throttle ? atoi(d_max_throttle) : 0; uwsgi_ud->notifypid = d_notifypid ? 1 : 0; if (d_touch) { size_t i,rlen = 0; char **argv = uwsgi_split_quoted(d_touch, strlen(d_touch), ";", &rlen); for(i=0;itouch, argv[i]); } if (argv) free(argv); } uwsgi.daemons_cnt++; free(arg); } uwsgi-2.0.29/core/emperor.c000066400000000000000000001754241477626554400155500ustar00rootroot00000000000000/* The uWSGI Emperor */ #include "uwsgi.h" extern struct uwsgi_server uwsgi; extern char **environ; void emperor_send_stats(int); time_t emperor_throttle; int emperor_throttle_level; int emperor_warming_up = 1; struct uwsgi_instance *ui; time_t on_royal_death = 0; /* blacklist subsystem failed unloyal vassals are blacklisted and throttled */ struct uwsgi_emperor_blacklist_item { char id[0xff]; struct timeval first_attempt; struct timeval last_attempt; int throttle_level; int attempt; struct uwsgi_emperor_blacklist_item *prev; struct uwsgi_emperor_blacklist_item *next; }; struct uwsgi_emperor_blacklist_item *emperor_blacklist; /* this should be placed in core/socket.c but we realized it was needed only after 2.0 so we cannot change uwsgi.h basically it is a stripped down bind_to_tcp/bind_to_unix with rollback */ static int on_demand_bind(char *socket_name) { union uwsgi_sockaddr us; socklen_t addr_len = sizeof(struct sockaddr_un); char *is_tcp = strchr(socket_name, ':'); int af_family = is_tcp ? AF_INET : AF_UNIX; int fd = socket(af_family, SOCK_STREAM, 0); if (fd < 0) return -1; memset(&us, 0, sizeof(union uwsgi_sockaddr)); if (is_tcp) { int reuse = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) { goto error; } us.sa_in.sin_family = AF_INET; us.sa_in.sin_port = htons(atoi(is_tcp + 1)); *is_tcp = 0; if (socket_name[0] != 0) { us.sa_in.sin_addr.s_addr = inet_addr(socket_name); } else { us.sa_in.sin_addr.s_addr = INADDR_ANY; } *is_tcp = ':'; addr_len = sizeof(struct sockaddr_in); } else { if (unlink(socket_name) != 0 && errno != ENOENT) { goto error; } us.sa_un.sun_family = AF_UNIX; memcpy(us.sa_un.sun_path, socket_name, UMIN(strlen(socket_name), 102)); addr_len = strlen(socket_name) + ((void *) us.sa_un.sun_path - (void *) &us.sa_un); } if (bind(fd, (struct sockaddr *) &us, addr_len) != 0) { goto error; } if (!is_tcp) { if (chmod(socket_name, 0666)) { goto error; } } if (listen(fd, uwsgi.listen_queue) != 0) { goto error; } return fd; error: close(fd); return -1; } struct uwsgi_emperor_blacklist_item *uwsgi_emperor_blacklist_check(char *id) { struct uwsgi_emperor_blacklist_item *uebi = emperor_blacklist; while (uebi) { if (!strcmp(uebi->id, id)) { return uebi; } uebi = uebi->next; } return NULL; } void uwsgi_emperor_blacklist_add(char *id) { // check if the item is already in the blacklist struct uwsgi_emperor_blacklist_item *uebi = uwsgi_emperor_blacklist_check(id); if (uebi) { gettimeofday(&uebi->last_attempt, NULL); if (uebi->throttle_level < (uwsgi.emperor_max_throttle * 1000)) { uebi->throttle_level += (uwsgi.emperor_throttle * 1000); } else { uwsgi_log_verbose("[emperor] maximum throttle level for vassal %s reached !!!\n", id); uebi->throttle_level = uebi->throttle_level / 2; } uebi->attempt++; if (uebi->attempt == 2) { uwsgi_log_verbose("[emperor] unloyal bad behaving vassal found: %s throttling it...\n", id); } return; } uebi = emperor_blacklist; if (!uebi) { uebi = uwsgi_calloc(sizeof(struct uwsgi_emperor_blacklist_item)); uebi->prev = NULL; emperor_blacklist = uebi; } else { while (uebi) { if (!uebi->next) { uebi->next = uwsgi_calloc(sizeof(struct uwsgi_emperor_blacklist_item)); uebi->next->prev = uebi; uebi = uebi->next; break; } uebi = uebi->next; } } snprintf(uebi->id, 0xff, "%s", id); gettimeofday(&uebi->first_attempt, NULL); memcpy(&uebi->last_attempt, &uebi->first_attempt, sizeof(struct timeval)); uebi->throttle_level = uwsgi.emperor_throttle; uebi->next = NULL; } void uwsgi_emperor_blacklist_remove(char *id) { struct uwsgi_emperor_blacklist_item *uebi = uwsgi_emperor_blacklist_check(id); if (!uebi) return; // ok let's remove the item //is it the first item ? if (uebi == emperor_blacklist) { emperor_blacklist = uebi->next; } struct uwsgi_emperor_blacklist_item *next = uebi->next; struct uwsgi_emperor_blacklist_item *prev = uebi->prev; if (next) next->prev = prev; if (prev) prev->next = next; free(uebi); } struct uwsgi_emperor_scanner *emperor_scanners; static int has_extra_extension(char *name) { struct uwsgi_string_list *usl = uwsgi.emperor_extra_extension; while (usl) { if (uwsgi_endswith(name, usl->value)) { return 1; } usl = usl->next; } return 0; } int uwsgi_emperor_is_valid(char *name) { if (uwsgi_endswith(name, ".xml") || uwsgi_endswith(name, ".ini") || uwsgi_endswith(name, ".yml") || uwsgi_endswith(name, ".yaml") || uwsgi_endswith(name, ".js") || uwsgi_endswith(name, ".json") || has_extra_extension(name)) { if (strlen(name) < 0xff) { return 1; } } return 0; } static char *emperor_check_on_demand_socket(char *filename) { size_t len = 0; if (uwsgi.emperor_on_demand_extension) { char *tmp = uwsgi_concat2(filename, uwsgi.emperor_on_demand_extension); int fd = open(tmp, O_RDONLY); free(tmp); if (fd < 0) return NULL; char *ret = uwsgi_read_fd(fd, &len, 1); close(fd); // change the first non printable character to 0 size_t i; for (i = 0; i < len; i++) { if (ret[i] < 32) { ret[i] = 0; break; } } if (ret[0] == 0) { free(ret); return NULL; } return ret; } else if (uwsgi.emperor_on_demand_directory) { // we need to build the socket path automagically char *start_of_vassal_name = uwsgi_get_last_char(filename, '/'); if (!start_of_vassal_name) { start_of_vassal_name = filename; } else { start_of_vassal_name++; } char *last_dot = uwsgi_get_last_char(filename, '.'); if (!last_dot) return NULL; return uwsgi_concat4n(uwsgi.emperor_on_demand_directory, strlen(uwsgi.emperor_on_demand_directory), "/", 1, start_of_vassal_name, last_dot - start_of_vassal_name, ".socket", 7); } else if (uwsgi.emperor_on_demand_exec) { int cpipe[2]; if (pipe(cpipe)) { uwsgi_error("emperor_check_on_demand_socket()pipe()"); return NULL; } char *cmd = uwsgi_concat4(uwsgi.emperor_on_demand_exec, " \"", filename, "\""); int r = uwsgi_run_command(cmd, NULL, cpipe[1]); free(cmd); if (r < 0) { close(cpipe[0]); close(cpipe[1]); return NULL; } char *ret = uwsgi_read_fd(cpipe[0], &len, 1); close(cpipe[0]); close(cpipe[1]); // change the first non prinabel character to 0 size_t i; for (i = 0; i < len; i++) { if (ret[i] < 32) { ret[i] = 0; break; } } if (ret[0] == 0) { free(ret); return NULL; } return ret; } return NULL; } // this is the monitor for non-glob directories void uwsgi_imperial_monitor_directory(struct uwsgi_emperor_scanner *ues) { struct uwsgi_instance *ui_current; struct dirent *de; struct stat st; if (chdir(ues->arg)) { uwsgi_error("chdir()"); return; } DIR *dir = opendir("."); while ((de = readdir(dir)) != NULL) { if (!uwsgi_emperor_is_valid(de->d_name)) continue; if (uwsgi.emperor_nofollow) { if (lstat(de->d_name, &st)) continue; if (!S_ISLNK(st.st_mode) && !S_ISREG(st.st_mode)) continue; } else { if (stat(de->d_name, &st)) continue; if (!S_ISREG(st.st_mode)) continue; } ui_current = emperor_get(de->d_name); uid_t t_uid = st.st_uid; gid_t t_gid = st.st_gid; if (uwsgi.emperor_tyrant && uwsgi.emperor_tyrant_nofollow) { struct stat lst; if (lstat(de->d_name, &lst)) { uwsgi_error("[emperor-tyrant]/lstat()"); if (ui_current) { uwsgi_log("!!! availability of file %s changed. stopping the instance... !!!\n", de->d_name); emperor_stop(ui_current); } continue; } t_uid = lst.st_uid; t_gid = lst.st_gid; } if (ui_current) { // check if uid or gid are changed, in such case, stop the instance if (uwsgi.emperor_tyrant) { if (t_uid != ui_current->uid || t_gid != ui_current->gid) { uwsgi_log("!!! permissions of file %s changed. stopping the instance... !!!\n", de->d_name); emperor_stop(ui_current); continue; } } // check if mtime is changed and the uWSGI instance must be reloaded if (st.st_mtime > ui_current->last_mod) { emperor_respawn(ui_current, st.st_mtime); } } else { char *socket_name = emperor_check_on_demand_socket(de->d_name); emperor_add(ues, de->d_name, st.st_mtime, NULL, 0, t_uid, t_gid, socket_name); if (socket_name) free(socket_name); } } closedir(dir); // now check for removed instances struct uwsgi_instance *c_ui = ui->ui_next; while (c_ui) { if (c_ui->scanner == ues) { if (c_ui->zerg) { char *colon = strrchr(c_ui->name, ':'); if (!colon) { emperor_stop(c_ui); } else { char *filename = uwsgi_calloc(0xff); memcpy(filename, c_ui->name, colon - c_ui->name); if (uwsgi.emperor_nofollow) { if (lstat(filename, &st)) { emperor_stop(c_ui); } } else { if (stat(filename, &st)) { emperor_stop(c_ui); } } free(filename); } } else { if (uwsgi.emperor_nofollow) { if (lstat(c_ui->name, &st)) { emperor_stop(c_ui); } } else { if (stat(c_ui->name, &st)) { emperor_stop(c_ui); } } } } c_ui = c_ui->ui_next; } } // this is the monitor for glob patterns void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *ues) { glob_t g; int i; struct stat st; struct uwsgi_instance *ui_current; if (chdir(uwsgi.cwd)) { uwsgi_error("uwsgi_imperial_monitor_glob()/chdir()"); exit(1); } if (glob(ues->arg, GLOB_MARK | GLOB_NOCHECK, NULL, &g)) { uwsgi_error("uwsgi_imperial_monitor_glob()/glob()"); return; } for (i = 0; i < (int) g.gl_pathc; i++) { if (!uwsgi_emperor_is_valid(g.gl_pathv[i])) continue; if (uwsgi.emperor_nofollow) { if (lstat(g.gl_pathv[i], &st)) continue; if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) continue; } else { if (stat(g.gl_pathv[i], &st)) continue; if (!S_ISREG(st.st_mode)) continue; } ui_current = emperor_get(g.gl_pathv[i]); uid_t t_uid = st.st_uid; gid_t t_gid = st.st_gid; if (uwsgi.emperor_tyrant && uwsgi.emperor_tyrant_nofollow) { struct stat lst; if (lstat(g.gl_pathv[i], &lst)) { uwsgi_error("[emperor-tyrant]/lstat()"); if (ui_current) { uwsgi_log("!!! availability of file %s changed. stopping the instance... !!!\n", g.gl_pathv[i]); emperor_stop(ui_current); } continue; } t_uid = lst.st_uid; t_gid = lst.st_gid; } if (ui_current) { // check if uid or gid are changed, in such case, stop the instance if (uwsgi.emperor_tyrant) { if (t_uid != ui_current->uid || t_gid != ui_current->gid) { uwsgi_log("!!! permissions of file %s changed. stopping the instance... !!!\n", g.gl_pathv[i]); emperor_stop(ui_current); continue; } } // check if mtime is changed and the uWSGI instance must be reloaded if (st.st_mtime > ui_current->last_mod) { emperor_respawn(ui_current, st.st_mtime); } } else { char *socket_name = emperor_check_on_demand_socket(g.gl_pathv[i]); emperor_add(ues, g.gl_pathv[i], st.st_mtime, NULL, 0, t_uid, t_gid, socket_name); if (socket_name) free(socket_name); } } globfree(&g); // now check for removed instances struct uwsgi_instance *c_ui = ui->ui_next; while (c_ui) { if (c_ui->scanner == ues) { if (c_ui->zerg) { char *colon = strrchr(c_ui->name, ':'); if (!colon) { emperor_stop(c_ui); } else { char *filename = uwsgi_calloc(0xff); memcpy(filename, c_ui->name, colon - c_ui->name); if (uwsgi.emperor_nofollow) { if (lstat(filename, &st)) { emperor_stop(c_ui); } } else { if (stat(filename, &st)) { emperor_stop(c_ui); } } free(filename); } } else { if (uwsgi.emperor_nofollow) { if (lstat(c_ui->name, &st)) { emperor_stop(c_ui); } } else { if (stat(c_ui->name, &st)) { emperor_stop(c_ui); } } } } c_ui = c_ui->ui_next; } } void uwsgi_register_imperial_monitor(char *name, void (*init) (struct uwsgi_emperor_scanner *), void (*func) (struct uwsgi_emperor_scanner *)) { struct uwsgi_imperial_monitor *uim = uwsgi.emperor_monitors; if (!uim) { uim = uwsgi_calloc(sizeof(struct uwsgi_imperial_monitor)); uwsgi.emperor_monitors = uim; } else { while (uim) { if (!uim->next) { uim->next = uwsgi_calloc(sizeof(struct uwsgi_imperial_monitor)); uim = uim->next; break; } uim = uim->next; } } uim->scheme = name; uim->init = init; uim->func = func; uim->next = NULL; } // the sad death of an Emperor static void royal_death(int signum) { if (on_royal_death) { uwsgi_log("[emperor] *** RAGNAROK ALREADY EVOKED (mercyless in %d seconds)***\n", uwsgi.reload_mercy - (uwsgi_now() - on_royal_death)); return; } struct uwsgi_instance *c_ui = ui->ui_next; if (uwsgi.vassals_stop_hook) { while (c_ui) { uwsgi_log("[emperor] running vassal stop-hook: %s %s\n", uwsgi.vassals_stop_hook, c_ui->name); if (uwsgi.emperor_absolute_dir) { if (setenv("UWSGI_VASSALS_DIR", uwsgi.emperor_absolute_dir, 1)) { uwsgi_error("setenv()"); } } int stop_hook_ret = uwsgi_run_command_and_wait(uwsgi.vassals_stop_hook, c_ui->name); uwsgi_log("[emperor] %s stop-hook returned %d\n", c_ui->name, stop_hook_ret); c_ui = c_ui->ui_next; } } uwsgi_log("[emperor] *** RAGNAROK EVOKED ***\n"); while (c_ui) { emperor_stop(c_ui); c_ui = c_ui->ui_next; } if (!uwsgi.reload_mercy) uwsgi.reload_mercy = 30; on_royal_death = uwsgi_now(); } // massive reload of vassals static void emperor_massive_reload(int signum) { struct uwsgi_instance *c_ui = ui->ui_next; while (c_ui) { emperor_respawn(c_ui, uwsgi_now()); c_ui = c_ui->ui_next; } } static void emperor_stats(int signum) { struct uwsgi_instance *c_ui = ui->ui_next; while (c_ui) { uwsgi_log("vassal instance %s (last modified %lld) status %d loyal %d zerg %d\n", c_ui->name, (long long) c_ui->last_mod, c_ui->status, c_ui->loyal, c_ui->zerg); c_ui = c_ui->ui_next; } } struct uwsgi_instance *emperor_get_by_fd(int fd) { struct uwsgi_instance *c_ui = ui; while (c_ui->ui_next) { c_ui = c_ui->ui_next; if (c_ui->pipe[0] == fd) { return c_ui; } } return NULL; } struct uwsgi_instance *emperor_get_by_socket_fd(int fd) { struct uwsgi_instance *c_ui = ui; while (c_ui->ui_next) { c_ui = c_ui->ui_next; // over engineering... if (c_ui->on_demand_fd > -1 && c_ui->on_demand_fd == fd) { return c_ui; } } return NULL; } struct uwsgi_instance *emperor_get(char *name) { struct uwsgi_instance *c_ui = ui; while (c_ui->ui_next) { c_ui = c_ui->ui_next; if (!strcmp(c_ui->name, name)) { return c_ui; } } return NULL; } void emperor_del(struct uwsgi_instance *c_ui) { struct uwsgi_instance *parent_ui = c_ui->ui_prev; struct uwsgi_instance *child_ui = c_ui->ui_next; parent_ui->ui_next = child_ui; if (child_ui) { child_ui->ui_prev = parent_ui; } // this will destroy the whole uWSGI instance (and workers) if (c_ui->pipe[0] != -1) close(c_ui->pipe[0]); if (c_ui->pipe[1] != -1) close(c_ui->pipe[1]); if (c_ui->use_config) { if (c_ui->pipe_config[0] != -1) close(c_ui->pipe_config[0]); if (c_ui->pipe_config[1] != -1) close(c_ui->pipe_config[1]); } if (uwsgi.vassals_stop_hook) { uwsgi_log("[emperor] running vassal stop-hook: %s %s\n", uwsgi.vassals_stop_hook, c_ui->name); if (uwsgi.emperor_absolute_dir) { if (setenv("UWSGI_VASSALS_DIR", uwsgi.emperor_absolute_dir, 1)) { uwsgi_error("setenv()"); } } int stop_hook_ret = uwsgi_run_command_and_wait(uwsgi.vassals_stop_hook, c_ui->name); uwsgi_log("[emperor] %s stop-hook returned %d\n", c_ui->name, stop_hook_ret); } uwsgi_log_verbose("[emperor] removed uwsgi instance %s\n", c_ui->name); // put the instance in the blacklist (or update its throttling value) if (!c_ui->loyal && !uwsgi.emperor_no_blacklist) { uwsgi_emperor_blacklist_add(c_ui->name); } if (c_ui->zerg) { uwsgi.emperor_broodlord_count--; } if (c_ui->socket_name) { free(c_ui->socket_name); } if (c_ui->config) free(c_ui->config); if (c_ui->on_demand_fd > -1) { close(c_ui->on_demand_fd); } free(c_ui); } void emperor_back_to_ondemand(struct uwsgi_instance *c_ui) { if (c_ui->status > 0) return; // remove uWSGI instance if (c_ui->pid != -1) { if (write(c_ui->pipe[0], uwsgi.emperor_graceful_shutdown ? "\2" : "\0", 1) != 1) { uwsgi_error("emperor_stop()/write()"); } } c_ui->status = 2; c_ui->cursed_at = uwsgi_now(); uwsgi_log_verbose("[emperor] bringing back instance %s to on-demand mode\n", c_ui->name); } void emperor_stop(struct uwsgi_instance *c_ui) { if (c_ui->status == 1) return; // remove uWSGI instance if (c_ui->pid != -1) { if (write(c_ui->pipe[0], uwsgi.emperor_graceful_shutdown ? "\2" : "\0", 1) != 1) { uwsgi_error("emperor_stop()/write()"); } } c_ui->status = 1; c_ui->cursed_at = uwsgi_now(); uwsgi_log_verbose("[emperor] stop the uwsgi instance %s\n", c_ui->name); } void emperor_curse(struct uwsgi_instance *c_ui) { if (c_ui->status == 1) return; // curse uWSGI instance // take in account on-demand mode if (c_ui->status == 0) c_ui->status = 1; c_ui->cursed_at = uwsgi_now(); uwsgi_log_verbose("[emperor] curse the uwsgi instance %s (pid: %d)\n", c_ui->name, (int) c_ui->pid); } // send configuration (if required to the vassal) static void emperor_push_config(struct uwsgi_instance *c_ui) { struct uwsgi_header uh; if (c_ui->use_config) { uh.modifier1 = 115; uh.pktsize = c_ui->config_len; uh.modifier2 = 0; if (write(c_ui->pipe_config[0], &uh, 4) != 4) { uwsgi_error("[uwsgi-emperor] write() header config"); } else { if (write(c_ui->pipe_config[0], c_ui->config, c_ui->config_len) != (long) c_ui->config_len) { uwsgi_error("[uwsgi-emperor] write() config"); } } } } void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) { // if the vassal is being destroyed, do not honour respawns if (c_ui->status > 0) return; // check if we are in on_demand mode (the respawn will be ignored) if (c_ui->pid == -1 && c_ui->on_demand_fd > -1) { c_ui->last_mod = mod; // reset readyness c_ui->ready = 0; // reset accepting c_ui->accepting = 0; uwsgi_log_verbose("[emperor] updated configuration for \"on demand\" instance %s\n", c_ui->name); return; } // reload the uWSGI instance if (write(c_ui->pipe[0], "\1", 1) != 1) { // the vassal could be already dead, better to curse it uwsgi_error("emperor_respawn/write()"); emperor_curse(c_ui); return; } // push the config to the config pipe (if needed) emperor_push_config(c_ui); c_ui->respawns++; c_ui->last_mod = mod; c_ui->last_run = uwsgi_now(); // reset readyness c_ui->ready = 0; // reset accepting c_ui->accepting = 0; uwsgi_log_verbose("[emperor] reload the uwsgi instance %s\n", c_ui->name); } void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, char *config, uint32_t config_size, uid_t uid, gid_t gid, char *socket_name) { struct uwsgi_instance *c_ui = ui; struct uwsgi_instance *n_ui = NULL; struct timeval tv; #ifdef UWSGI_DEBUG uwsgi_log("\n\nVASSAL %s %d %.*s %d %d\n", name, born, config_size, config, uid, gid); #endif if (strlen(name) > (0xff - 1)) { uwsgi_log("[emperor] invalid vassal name: %s\n", name); return; } gettimeofday(&tv, NULL); int now = tv.tv_sec; uint64_t micros = (tv.tv_sec * 1000ULL * 1000ULL) + tv.tv_usec; // blacklist check struct uwsgi_emperor_blacklist_item *uebi = uwsgi_emperor_blacklist_check(name); if (uebi) { uint64_t i_micros = (uebi->last_attempt.tv_sec * 1000ULL * 1000ULL) + uebi->last_attempt.tv_usec + uebi->throttle_level; if (i_micros > micros) { return; } } // TODO make it meaningful if (now - emperor_throttle < 1) { emperor_throttle_level = emperor_throttle_level * 2; } else { if (emperor_throttle_level > uwsgi.emperor_throttle) { emperor_throttle_level = emperor_throttle_level / 2; } if (emperor_throttle_level < uwsgi.emperor_throttle) { emperor_throttle_level = uwsgi.emperor_throttle; } } emperor_throttle = now; #ifdef UWSGI_DEBUG uwsgi_log("emperor throttle = %d\n", emperor_throttle_level); #endif /* if (emperor_warming_up) { if (emperor_throttle_level > 0) { // wait 10 milliseconds in case of fork-bombing // pretty random value, but should avoid the load average to increase usleep(10 * 1000); } } else { usleep(emperor_throttle_level * 1000); } */ if (uwsgi.emperor_tyrant) { if (uid == 0 || gid == 0) { uwsgi_log("[emperor-tyrant] invalid permissions for vassal %s\n", name); return; } } while (c_ui->ui_next) { c_ui = c_ui->ui_next; } n_ui = uwsgi_calloc(sizeof(struct uwsgi_instance)); if (config) { n_ui->use_config = 1; n_ui->config = config; n_ui->config_len = config_size; } c_ui->ui_next = n_ui; #ifdef UWSGI_DEBUG uwsgi_log("c_ui->ui_next = %p\n", c_ui->ui_next); #endif n_ui->ui_prev = c_ui; if (strchr(name, ':')) { n_ui->zerg = 1; uwsgi.emperor_broodlord_count++; } n_ui->scanner = ues; memcpy(n_ui->name, name, strlen(name)); n_ui->born = born; n_ui->uid = uid; n_ui->gid = gid; n_ui->last_mod = born; // start non-ready n_ui->last_ready = 0; n_ui->ready = 0; // start without loyalty n_ui->last_loyal = 0; n_ui->loyal = 0; n_ui->first_run = uwsgi_now(); n_ui->last_run = n_ui->first_run; n_ui->on_demand_fd = -1; if (socket_name) { n_ui->socket_name = uwsgi_str(socket_name); } n_ui->pid = -1; n_ui->pipe[0] = -1; n_ui->pipe[1] = -1; n_ui->pipe_config[0] = -1; n_ui->pipe_config[1] = -1; // ok here we check if we need to bind to the specified socket or continue with the activation if (socket_name) { n_ui->on_demand_fd = on_demand_bind(socket_name); if (n_ui->on_demand_fd < 0) { uwsgi_error("emperor_add()/bind()"); emperor_del(n_ui); return; } event_queue_add_fd_read(uwsgi.emperor_queue, n_ui->on_demand_fd); uwsgi_log("[uwsgi-emperor] %s -> \"on demand\" instance detected, waiting for connections on socket \"%s\" ...\n", name, socket_name); return; } if (uwsgi_emperor_vassal_start(n_ui)) { // clear the vassal emperor_del(n_ui); } } static int uwsgi_emperor_spawn_vassal(struct uwsgi_instance *); int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) { pid_t pid; if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe)) { uwsgi_error("socketpair()"); return -1; } uwsgi_socket_nb(n_ui->pipe[0]); event_queue_add_fd_read(uwsgi.emperor_queue, n_ui->pipe[0]); if (n_ui->use_config) { if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe_config)) { uwsgi_error("socketpair()"); return -1; } uwsgi_socket_nb(n_ui->pipe_config[0]); } if (n_ui->zerg) { uwsgi.emperor_broodlord_num++; } // TODO pre-start hook // a new uWSGI instance will start #if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL) && !defined(__ia64__) if (uwsgi.emperor_clone) { char stack[PTHREAD_STACK_MIN]; pid = clone((int (*)(void *)) uwsgi_emperor_spawn_vassal, stack + PTHREAD_STACK_MIN, SIGCHLD | uwsgi.emperor_clone, (void *) n_ui); } else { #endif pid = fork(); #if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL) && !defined(__ia64__) } #endif if (pid < 0) { uwsgi_error("uwsgi_emperor_spawn_vassal()/fork()") } else if (pid > 0) { n_ui->pid = pid; // close the right side of the pipe close(n_ui->pipe[1]); n_ui->pipe[1] = -1; /* THE ON-DEMAND file descriptor is left mapped to the emperor to allow fast-respawn // TODO add an option to force closing it // close the "on demand" socket if (n_ui->on_demand_fd > -1) { close(n_ui->on_demand_fd); n_ui->on_demand_fd = -1; } */ if (n_ui->use_config) { close(n_ui->pipe_config[1]); n_ui->pipe_config[1] = -1; emperor_push_config(n_ui); } // once the config is sent we can run hooks (they can fail) // exec hooks have access to all of the currently defined vars + UWSGI_VASSAL_PID, UWSGI_VASSAL_UID, UWSGI_VASSAL_GID, UWSGI_VASSAL_CONFIG uwsgi_hooks_run(uwsgi.hook_as_emperor, "as-emperor", 0); struct uwsgi_string_list *usl; uwsgi_foreach(usl, uwsgi.mount_as_emperor) { uwsgi_log("mounting \"%s\" (as-emperor for vassal \"%s\" pid: %d uid: %d gid: %d)...\n", usl->value, n_ui->name, n_ui->pid, n_ui->uid, n_ui->gid); if (uwsgi_mount_hook(usl->value)) { uwsgi_log("unable to mount %s\n", usl->value); } } uwsgi_foreach(usl, uwsgi.umount_as_emperor) { uwsgi_log("un-mounting \"%s\" (as-emperor for vassal \"%s\" pid: %d uid: %d gid: %d)...\n", usl->value, n_ui->name, n_ui->pid, n_ui->uid, n_ui->gid); if (uwsgi_umount_hook(usl->value)) { uwsgi_log("unable to umount %s\n", usl->value); } } uwsgi_foreach(usl, uwsgi.exec_as_emperor) { uwsgi_log("running \"%s\" (as-emperor for vassal \"%s\" pid: %d uid: %d gid: %d)...\n", usl->value, n_ui->name, n_ui->pid, n_ui->uid, n_ui->gid); char *argv[4]; argv[0] = uwsgi_concat2("UWSGI_VASSAL_CONFIG=", n_ui->name); char argv_pid[17 + 11]; snprintf(argv_pid, 17 + 11, "UWSGI_VASSAL_PID=%d", (int) n_ui->pid); argv[1] = argv_pid; char argv_uid[17 + 11]; snprintf(argv_uid, 17 + 11, "UWSGI_VASSAL_UID=%d", (int) n_ui->uid); argv[2] = argv_uid; char argv_gid[17 + 11]; snprintf(argv_gid, 17 + 11, "UWSGI_VASSAL_GID=%d", (int) n_ui->gid); argv[3] = argv_gid; int ret = uwsgi_run_command_putenv_and_wait(NULL, usl->value, argv, 4); uwsgi_log("command \"%s\" exited with code: %d\n", usl->value, ret); free(argv[0]); } // 4 call hooks // config / config + pid / config + pid + uid + gid // call uwsgi_foreach(usl, uwsgi.call_as_emperor) { void (*func) (void) = dlsym(RTLD_DEFAULT, usl->value); if (!func) { uwsgi_log("unable to call function \"%s\"\n", usl->value); } else { func(); } } uwsgi_foreach(usl, uwsgi.call_as_emperor1) { void (*func) (char *) = dlsym(RTLD_DEFAULT, usl->value); if (!func) { uwsgi_log("unable to call function \"%s\"\n", usl->value); } else { func(n_ui->name); } } uwsgi_foreach(usl, uwsgi.call_as_emperor2) { void (*func) (char *, pid_t) = dlsym(RTLD_DEFAULT, usl->value); if (!func) { uwsgi_log("unable to call function \"%s\"\n", usl->value); } else { func(n_ui->name, n_ui->pid); } } uwsgi_foreach(usl, uwsgi.call_as_emperor4) { void (*func) (char *, pid_t, uid_t, gid_t) = dlsym(RTLD_DEFAULT, usl->value); if (!func) { uwsgi_log("unable to call function \"%s\"\n", usl->value); } else { func(n_ui->name, n_ui->pid, n_ui->uid, n_ui->gid); } } return 0; } else { uwsgi_emperor_spawn_vassal(n_ui); } return -1; } static int uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) { int i; // run plugin hooks for the vassal for (i = 0; i < 256; i++) { if (uwsgi.p[i]->vassal) { uwsgi.p[i]->vassal(n_ui); } } for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->vassal) { uwsgi.gp[i]->vassal(n_ui); } } #ifdef __linux__ if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) { uwsgi_error("prctl()"); } #ifdef CLONE_NEWUSER if (uwsgi.emperor_clone & CLONE_NEWUSER) { if (setuid(0)) { uwsgi_error("uwsgi_emperor_spawn_vassal()/setuid(0)"); exit(1); } } #endif #ifdef UWSGI_CAP #if defined(CAP_LAST_CAP) && defined(PR_CAPBSET_READ) && defined(PR_CAPBSET_DROP) if (uwsgi.emperor_cap && uwsgi.emperor_cap_count > 0) { int i; for (i = 0; i <= CAP_LAST_CAP; i++) { int has_cap = prctl(PR_CAPBSET_READ, i, 0, 0, 0); if (has_cap == 1) { if (i == CAP_SETPCAP) continue; int j; int found = 0; for (j = 0; j < uwsgi.emperor_cap_count; j++) { if (uwsgi.emperor_cap[j] == (int) i) { found = 1; break; } } if (found) continue; if (prctl(PR_CAPBSET_DROP, i, 0, 0, 0)) { uwsgi_error("uwsgi_emperor_spawn_vassal()/prctl()"); uwsgi_log_verbose("unable to drop capability %lu\n", i); exit(1); } } } // just for being paranoid #ifdef SECBIT_KEEP_CAPS if (prctl(SECBIT_KEEP_CAPS, 1, 0, 0, 0) < 0) { uwsgi_error("prctl()"); exit(1); } #else if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) { uwsgi_error("prctl()"); exit(1); } #endif uwsgi_log("capabilities applied for vassal %s (pid: %d)\n", n_ui->name, (int) getpid()); } #endif #endif #endif if (uwsgi.emperor_tyrant) { uwsgi_log("[emperor-tyrant] dropping privileges to %d %d for instance %s\n", (int) n_ui->uid, (int) n_ui->gid, n_ui->name); if (setgid(n_ui->gid)) { uwsgi_error("setgid()"); exit(1); } if (setgroups(0, NULL)) { uwsgi_error("setgroups()"); exit(1); } if (setuid(n_ui->uid)) { uwsgi_error("setuid()"); exit(1); } } unsetenv("UWSGI_RELOADS"); unsetenv("NOTIFY_SOCKET"); char *uef = uwsgi_num2str(n_ui->pipe[1]); if (setenv("UWSGI_EMPEROR_FD", uef, 1)) { uwsgi_error("setenv()"); exit(1); } free(uef); // add UWSGI_BROODLORD_NUM if (n_ui->zerg) { uef = uwsgi_num2str(uwsgi.emperor_broodlord_num); if (setenv("UWSGI_BROODLORD_NUM", uef, 1)) { uwsgi_error("setenv()"); exit(1); } free(uef); } if (n_ui->use_config) { uef = uwsgi_num2str(n_ui->pipe_config[1]); if (setenv("UWSGI_EMPEROR_FD_CONFIG", uef, 1)) { uwsgi_error("setenv()"); exit(1); } free(uef); } char **uenvs = environ; while (*uenvs) { if (!strncmp(*uenvs, "UWSGI_VASSAL_", 13) && strchr(*uenvs, '=')) { char *oe = uwsgi_concat2n(*uenvs, strchr(*uenvs, '=') - *uenvs, "", 0), *ne; #ifdef UNSETENV_VOID unsetenv(oe); #else if (unsetenv(oe)) { uwsgi_error("unsetenv()"); free(oe); break; } #endif free(oe); ne = uwsgi_concat2("UWSGI_", *uenvs + 13); #ifdef UWSGI_DEBUG uwsgi_log("putenv %s\n", ne); #endif if (putenv(ne)) { uwsgi_error("putenv()"); } // do not free ne as putenv will add it to the environ uenvs = environ; continue; } uenvs++; } // close the left side of the pipe close(n_ui->pipe[0]); if (n_ui->use_config) { close(n_ui->pipe_config[0]); } int counter = 4; struct uwsgi_string_list *uct; uwsgi_foreach(uct, uwsgi.vassals_templates_before) counter += 2; uwsgi_foreach(uct, uwsgi.vassals_includes_before) counter += 2; uwsgi_foreach(uct, uwsgi.vassals_set) counter += 2; uwsgi_foreach(uct, uwsgi.vassals_templates) counter += 2; uwsgi_foreach(uct, uwsgi.vassals_includes) counter += 2; char **vassal_argv = uwsgi_malloc(sizeof(char *) * counter); // set args vassal_argv[0] = uwsgi.emperor_wrapper ? uwsgi.emperor_wrapper : uwsgi.binary_path; // reset counter counter = 1; uwsgi_foreach(uct, uwsgi.vassals_templates_before) { vassal_argv[counter] = "--inherit"; vassal_argv[counter + 1] = uct->value; counter += 2; } uwsgi_foreach(uct, uwsgi.vassals_includes_before) { vassal_argv[counter] = "--include"; vassal_argv[counter + 1] = uct->value; counter += 2; } uwsgi_foreach(uct, uwsgi.vassals_set) { vassal_argv[counter] = "--set"; vassal_argv[counter + 1] = uct->value; counter += 2; } char *colon = NULL; if (uwsgi.emperor_broodlord) { colon = strchr(n_ui->name, ':'); if (colon) { colon[0] = 0; } } // initialize to a default value vassal_argv[counter] = "--inherit"; if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".xml")) vassal_argv[counter] = "--xml"; if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".ini")) vassal_argv[counter] = "--ini"; if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".yml")) vassal_argv[counter] = "--yaml"; if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".yaml")) vassal_argv[counter] = "--yaml"; if (!strcmp(n_ui->name + (strlen(n_ui->name) - 3), ".js")) vassal_argv[counter] = "--json"; if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".json")) vassal_argv[counter] = "--json"; struct uwsgi_string_list *usl = uwsgi.emperor_extra_extension; while (usl) { if (uwsgi_endswith(n_ui->name, usl->value)) { vassal_argv[counter] = "--config"; break; } usl = usl->next; } if (colon) colon[0] = ':'; // start config filename... counter++; vassal_argv[counter] = n_ui->name; if (uwsgi.emperor_magic_exec) { if (!access(n_ui->name, R_OK | X_OK)) { vassal_argv[counter] = uwsgi_concat2("exec://", n_ui->name); } } if (n_ui->use_config) { vassal_argv[counter] = uwsgi_concat2("emperor://", n_ui->name); } // start templates,includes,inherit... counter++; uwsgi_foreach(uct, uwsgi.vassals_templates) { vassal_argv[counter] = "--inherit"; vassal_argv[counter + 1] = uct->value; counter += 2; } uwsgi_foreach(uct, uwsgi.vassals_includes) { vassal_argv[counter] = "--include"; vassal_argv[counter + 1] = uct->value; counter += 2; } vassal_argv[counter] = NULL; // disable stdin OR map it to the "on demand" socket if (n_ui->on_demand_fd > -1) { if (n_ui->on_demand_fd != 0) { if (dup2(n_ui->on_demand_fd, 0) < 0) { uwsgi_error("dup2()"); exit(1); } close(n_ui->on_demand_fd); } } else { uwsgi_remap_fd(0, "/dev/null"); } // close all of the unneded fd for (i = 3; i < (int) uwsgi.max_fd; i++) { if (uwsgi_fd_is_safe(i)) continue; if (n_ui->use_config) { if (i == n_ui->pipe_config[1]) continue; } if (i != n_ui->pipe[1]) { close(i); } } // run start hook (can fail) if (uwsgi.vassals_start_hook) { uwsgi_log("[emperor] running vassal start-hook: %s %s\n", uwsgi.vassals_start_hook, n_ui->name); if (uwsgi.emperor_absolute_dir) { if (setenv("UWSGI_VASSALS_DIR", uwsgi.emperor_absolute_dir, 1)) { uwsgi_error("setenv()"); } } int start_hook_ret = uwsgi_run_command_and_wait(uwsgi.vassals_start_hook, n_ui->name); uwsgi_log("[emperor] %s start-hook returned %d\n", n_ui->name, start_hook_ret); } uwsgi_hooks_run(uwsgi.hook_as_vassal, "as-vassal", 1); uwsgi_foreach(usl, uwsgi.mount_as_vassal) { uwsgi_log("mounting \"%s\" (as-vassal)...\n", usl->value); if (uwsgi_mount_hook(usl->value)) { exit(1); } } uwsgi_foreach(usl, uwsgi.umount_as_vassal) { uwsgi_log("un-mounting \"%s\" (as-vassal)...\n", usl->value); if (uwsgi_umount_hook(usl->value)) { exit(1); } } // run exec hooks (cannot fail) uwsgi_foreach(usl, uwsgi.exec_as_vassal) { uwsgi_log("running \"%s\" (as-vassal)...\n", usl->value); int ret = uwsgi_run_command_and_wait(NULL, usl->value); if (ret != 0) { uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret); exit(1); } } // run low-level hooks uwsgi_foreach(usl, uwsgi.call_as_vassal) { void (*func) (void) = dlsym(RTLD_DEFAULT, usl->value); if (!func) { uwsgi_log("unable to call function \"%s\"\n", usl->value); exit(1); } func(); } uwsgi_foreach(usl, uwsgi.call_as_vassal1) { void (*func) (char *) = dlsym(RTLD_DEFAULT, usl->value); if (!func) { uwsgi_log("unable to call function \"%s\"\n", usl->value); exit(1); } func(n_ui->name); } uwsgi_foreach(usl, uwsgi.call_as_vassal3) { void (*func) (char *, uid_t, gid_t) = dlsym(RTLD_DEFAULT, usl->value); if (!func) { uwsgi_log("unable to call function \"%s\"\n", usl->value); exit(1); } func(n_ui->name, n_ui->uid, n_ui->gid); } // ->vassal_before_exec for (i = 0; i < 256; i++) { if (uwsgi.p[i]->vassal_before_exec) { uwsgi.p[i]->vassal_before_exec(n_ui); } } for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->vassal) { uwsgi.gp[i]->vassal_before_exec(n_ui); } } if (uwsgi.emperor_wrapper_override) { char *orig_wrapper = vassal_argv[0]; uwsgi_foreach(usl, uwsgi.emperor_wrapper_override) { vassal_argv[0] = usl->value; uwsgi_log("[emperor] trying to use %s as binary wrapper ...\n", usl->value); execvp(vassal_argv[0], vassal_argv); // not here if the binary is found } vassal_argv[0] = orig_wrapper; } // start !!! if (execvp(vassal_argv[0], vassal_argv)) { uwsgi_error("execvp()"); } uwsgi_log("[emperor] binary path: %s\n", vassal_argv[0]); uwsgi_log("[emperor] is the uwsgi binary in your system PATH ?\n"); // trying fallback uwsgi_foreach(usl, uwsgi.emperor_wrapper_fallback) { uwsgi_log("[emperor] trying to use %s as binary fallback ...\n", usl->value); vassal_argv[0] = usl->value; execvp(vassal_argv[0], vassal_argv); // not here if the binary is found } // never here exit(UWSGI_EXILE_CODE); return 0; } void uwsgi_imperial_monitor_glob_init(struct uwsgi_emperor_scanner *ues) { if (chdir(uwsgi.cwd)) { uwsgi_error("chdir()"); exit(1); } uwsgi.emperor_absolute_dir = uwsgi.cwd; if (!uwsgi_startswith(ues->arg, "glob://", 7)) { ues->arg += 7; } } void uwsgi_imperial_monitor_directory_init(struct uwsgi_emperor_scanner *ues) { if (!uwsgi_startswith(ues->arg, "dir://", 6)) { ues->arg += 6; } if (chdir(ues->arg)) { uwsgi_error("chdir()"); exit(1); } uwsgi.emperor_absolute_dir = uwsgi_malloc(PATH_MAX + 1); if (realpath(".", uwsgi.emperor_absolute_dir) == NULL) { uwsgi_error("realpath()"); exit(1); } ues->arg = uwsgi.emperor_absolute_dir; } struct uwsgi_imperial_monitor *imperial_monitor_get_by_id(char *scheme) { struct uwsgi_imperial_monitor *uim = uwsgi.emperor_monitors; while (uim) { if (!strcmp(uim->scheme, scheme)) { return uim; } uim = uim->next; } return NULL; } struct uwsgi_imperial_monitor *imperial_monitor_get_by_scheme(char *arg) { struct uwsgi_imperial_monitor *uim = uwsgi.emperor_monitors; while (uim) { char *scheme = uwsgi_concat2(uim->scheme, "://"); if (!uwsgi_starts_with(arg, strlen(arg), scheme, strlen(scheme))) { free(scheme); return uim; } free(scheme); uim = uim->next; } return NULL; } void emperor_add_scanner(struct uwsgi_imperial_monitor *monitor, char *arg) { struct uwsgi_emperor_scanner *ues = emperor_scanners; if (!ues) { ues = uwsgi_calloc(sizeof(struct uwsgi_emperor_scanner)); emperor_scanners = ues; } else { while (ues) { if (!ues->next) { ues->next = uwsgi_calloc(sizeof(struct uwsgi_emperor_scanner)); ues = ues->next; break; } ues = ues->next; } } ues->arg = arg; ues->monitor = monitor; ues->next = NULL; ues->fd = -1; // run the init hook ues->monitor->init(ues); } void uwsgi_emperor_run_scanners(void) { struct uwsgi_emperor_scanner *ues = emperor_scanners; while (ues) { ues->monitor->func(ues); ues = ues->next; } emperor_warming_up = 0; } void emperor_build_scanners() { struct uwsgi_string_list *usl = uwsgi.emperor; glob_t g; while (usl) { struct uwsgi_imperial_monitor *uim = imperial_monitor_get_by_scheme(usl->value); if (uim) { emperor_add_scanner(uim, usl->value); } else { // check for "glob" and fallback to "dir" if (!glob(usl->value, GLOB_MARK | GLOB_NOCHECK, NULL, &g)) { if (g.gl_pathc == 1 && g.gl_pathv[0][strlen(g.gl_pathv[0]) - 1] == '/') { globfree(&g); goto dir; } globfree(&g); uim = imperial_monitor_get_by_id("glob"); emperor_add_scanner(uim, usl->value); goto next; } dir: uim = imperial_monitor_get_by_id("dir"); emperor_add_scanner(uim, usl->value); } next: usl = usl->next; } } int uwsgi_emperor_scanner_event(int fd) { struct uwsgi_emperor_scanner *ues = emperor_scanners; while (ues) { if (ues->fd > -1 && ues->fd == fd) { ues->event_func(ues); return 1; } ues = ues->next; } return 0; } static void emperor_wakeup(int sn) { } static void emperor_cleanup(int signum) { uwsgi_log_verbose("[emperor] cleaning up blacklist ...\n"); struct uwsgi_emperor_blacklist_item *uebi = emperor_blacklist; while (uebi) { struct uwsgi_emperor_blacklist_item *next = uebi->next; free(uebi); uebi = next; } emperor_blacklist = NULL; } void emperor_loop() { // monitor a directory struct uwsgi_instance ui_base; struct uwsgi_instance *ui_current; pid_t diedpid; int waitpid_status; int has_children = 0; int i_am_alone = 0; int i; void *events; int nevents; int interesting_fd; char notification_message[64]; struct rlimit rl; uwsgi.disable_nuclear_blast = 1; uwsgi.emperor_stats_fd = -1; if (uwsgi.emperor_pidfile) { uwsgi_write_pidfile(uwsgi.emperor_pidfile); } signal(SIGPIPE, SIG_IGN); signal(SIGWINCH, emperor_wakeup); uwsgi_unix_signal(SIGINT, royal_death); uwsgi_unix_signal(SIGTERM, royal_death); uwsgi_unix_signal(SIGQUIT, royal_death); uwsgi_unix_signal(SIGUSR1, emperor_stats); uwsgi_unix_signal(SIGHUP, emperor_massive_reload); uwsgi_unix_signal(SIGURG, emperor_cleanup); memset(&ui_base, 0, sizeof(struct uwsgi_instance)); if (getrlimit(RLIMIT_NOFILE, &rl)) { uwsgi_error("getrlimit()"); exit(1); } uwsgi.max_fd = rl.rlim_cur; emperor_throttle_level = uwsgi.emperor_throttle; emperor_throttle = 0; // the queue must be initialized before adding scanners uwsgi.emperor_queue = event_queue_init(); emperor_build_scanners(); events = event_queue_alloc(64); if (uwsgi.has_emperor) { uwsgi_log("*** starting uWSGI sub-Emperor ***\n"); } else { uwsgi_log("*** starting uWSGI Emperor ***\n"); } if (uwsgi.emperor_stats) { char *tcp_port = strchr(uwsgi.emperor_stats, ':'); if (tcp_port) { // disable deferred accept for this socket int current_defer_accept = uwsgi.no_defer_accept; uwsgi.no_defer_accept = 1; uwsgi.emperor_stats_fd = bind_to_tcp(uwsgi.emperor_stats, uwsgi.listen_queue, tcp_port); uwsgi.no_defer_accept = current_defer_accept; } else { uwsgi.emperor_stats_fd = bind_to_unix(uwsgi.emperor_stats, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); } event_queue_add_fd_read(uwsgi.emperor_queue, uwsgi.emperor_stats_fd); uwsgi_log("*** Emperor stats server enabled on %s fd: %d ***\n", uwsgi.emperor_stats, uwsgi.emperor_stats_fd); } ui = &ui_base; int freq = 0; uwsgi_hooks_run(uwsgi.hook_emperor_start, "emperor-start", 1); // signal parent-Emperor about my loyalty if (uwsgi.has_emperor && !uwsgi.loyal) { uwsgi_log("announcing my loyalty to the Emperor...\n"); char byte = 17; if (write(uwsgi.emperor_fd, &byte, 1) != 1) { uwsgi_error("write()"); } uwsgi.loyal = 1; } for (;;) { if (on_royal_death) { if (!ui->ui_next) break; if (uwsgi_now() - on_royal_death >= uwsgi.reload_mercy) { ui_current = ui->ui_next; while (ui_current) { uwsgi_log_verbose("[emperor] NO MERCY for vassal %s !!!\n", ui_current->name); if (kill(ui_current->pid, SIGKILL) < 0) { uwsgi_error("[emperor] kill()"); emperor_del(ui_current); break; } ui_current = ui_current->ui_next; } break; } ui_current = ui->ui_next; while (ui_current) { struct uwsgi_instance *dead_vassal = ui_current; ui_current = ui_current->ui_next; pid_t dead_pid = waitpid(dead_vassal->pid, &waitpid_status, WNOHANG); if (dead_pid > 0 || dead_pid < 0) { emperor_del(dead_vassal); } } sleep(1); continue; } if (!i_am_alone) { diedpid = waitpid(uwsgi.emperor_pid, &waitpid_status, WNOHANG); if (diedpid < 0 || diedpid > 0) { i_am_alone = 1; } } nevents = event_queue_wait_multi(uwsgi.emperor_queue, freq, events, 64); freq = uwsgi.emperor_freq; for (i = 0; i < nevents; i++) { interesting_fd = event_queue_interesting_fd(events, i); if (uwsgi.emperor_stats && uwsgi.emperor_stats_fd > -1 && interesting_fd == uwsgi.emperor_stats_fd) { emperor_send_stats(uwsgi.emperor_stats_fd); continue; } // check if a monitor is mapped to that file descriptor if (uwsgi_emperor_scanner_event(interesting_fd)) { continue; } ui_current = emperor_get_by_fd(interesting_fd); if (ui_current) { char byte; ssize_t rlen = read(interesting_fd, &byte, 1); // retry if needed if (rlen < 0 && uwsgi_is_again()) continue; if (rlen <= 0) { // SAFE event_queue_del_fd(uwsgi.emperor_queue, interesting_fd, event_queue_read()); if (ui_current->status > 0) { // temporarily set frequency to a low value , so we can eventually fast-restart the instance freq = ui_current->status; } emperor_curse(ui_current); } else { if (byte == 17) { ui_current->loyal = 1; ui_current->last_loyal = uwsgi_now(); uwsgi_log_verbose("[emperor] vassal %s is now loyal\n", ui_current->name); // remove it from the blacklist uwsgi_emperor_blacklist_remove(ui_current->name); // TODO post-start hook } // heartbeat can be used for spotting blocked instances else if (byte == 26) { ui_current->last_heartbeat = uwsgi_now(); } else if (byte == 22) { // command 22 changes meaning when in "on_demand" mode if (ui_current->on_demand_fd != -1) { emperor_back_to_ondemand(ui_current); } else { emperor_stop(ui_current); } } else if (byte == 30 && uwsgi.emperor_broodlord > 0 && uwsgi.emperor_broodlord_count < uwsgi.emperor_broodlord) { uwsgi_log_verbose("[emperor] going in broodlord mode: launching zergs for %s\n", ui_current->name); char *zerg_name = uwsgi_concat3(ui_current->name, ":", "zerg"); // here we discard socket name as broodlord/zerg cannot be on demand emperor_add(ui_current->scanner, zerg_name, uwsgi_now(), NULL, 0, ui_current->uid, ui_current->gid, NULL); free(zerg_name); } else if (byte == 5) { ui_current->accepting = 1; ui_current->last_accepting = uwsgi_now(); uwsgi_log_verbose("[emperor] vassal %s is ready to accept requests\n", ui_current->name); } else if (byte == 1) { ui_current->ready = 1; ui_current->last_ready = uwsgi_now(); uwsgi_log_verbose("[emperor] vassal %s has been spawned\n", ui_current->name); } else if (byte == 2) { emperor_push_config(ui_current); } } } else { ui_current = emperor_get_by_socket_fd(interesting_fd); if (ui_current) { event_queue_del_fd(uwsgi.emperor_queue, ui_current->on_demand_fd, event_queue_read()); if (uwsgi_emperor_vassal_start(ui_current)) { emperor_del(ui_current); } } else { uwsgi_log("[emperor] unrecognized vassal event on fd %d\n", interesting_fd); close(interesting_fd); } } } uwsgi_emperor_run_scanners(); // check for heartbeat (if required) ui_current = ui->ui_next; while (ui_current) { if (ui_current->last_heartbeat > 0) { #ifdef UWSGI_DEBUG uwsgi_log("%d %d %d %d\n", ui_current->last_heartbeat, uwsgi.emperor_heartbeat, ui_current->last_heartbeat + uwsgi.emperor_heartbeat, uwsgi_now()); #endif if ((ui_current->last_heartbeat + uwsgi.emperor_heartbeat) < uwsgi_now()) { uwsgi_log("[emperor] vassal %s sent no heartbeat in last %d seconds, brutally respawning it...\n", ui_current->name, uwsgi.emperor_heartbeat); // set last_heartbeat to 0 avoiding races ui_current->last_heartbeat = 0; if (ui_current->pid > 0) { if (kill(ui_current->pid, SIGKILL) < 0) { uwsgi_error("[emperor] kill()"); emperor_del(ui_current); break; } } } } ui_current = ui_current->ui_next; } recheck: // check for removed instances ui_current = ui; has_children = 0; while (ui_current->ui_next) { ui_current = ui_current->ui_next; if (ui_current->pid > -1) { has_children++; } } if (uwsgi.notify) { if (snprintf(notification_message, 64, "The Emperor is governing %d vassals", has_children) >= 34) { uwsgi_notify(notification_message); } } if (has_children) { diedpid = waitpid(WAIT_ANY, &waitpid_status, WNOHANG); } else { // vacuum waitpid(WAIT_ANY, &waitpid_status, WNOHANG); diedpid = 0; } if (diedpid < 0) { // it looks like it happens when OOM is triggered to Linux cgroup, but it could be a uWSGI bug :P // by the way, fallback to a clean situation... if (errno == ECHILD) { uwsgi_log("--- MUTINY DETECTED !!! IMPALING VASSALS... ---\n"); ui_current = ui->ui_next; while (ui_current) { struct uwsgi_instance *rebel_vassal = ui_current; ui_current = ui_current->ui_next; emperor_del(rebel_vassal); } } else { uwsgi_error("waitpid()"); } } ui_current = ui; while (ui_current->ui_next) { ui_current = ui_current->ui_next; time_t now = uwsgi_now(); if (diedpid > 0 && ui_current->pid == diedpid) { if (ui_current->status == 0) { // respawn an accidentally dead instance if its exit code is not UWSGI_EXILE_CODE if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_EXILE_CODE) { // SAFE emperor_del(ui_current); } else { // UNSAFE char *config = NULL; if (ui_current->config) { config = uwsgi_str(ui_current->config); } char *socket_name = NULL; if (ui_current->socket_name) { socket_name = uwsgi_str(ui_current->socket_name); } emperor_add(ui_current->scanner, ui_current->name, ui_current->last_mod, config, ui_current->config_len, ui_current->uid, ui_current->gid, socket_name); // temporarily set frequency to 0, so we can eventually fast-restart the instance emperor_del(ui_current); freq = 0; } break; } else if (ui_current->status == 1) { // remove 'marked for dead' instance emperor_del(ui_current); // temporarily set frequency to 0, so we can eventually fast-restart the instance freq = 0; break; } // back to on_demand mode ... else if (ui_current->status == 2) { event_queue_add_fd_read(uwsgi.emperor_queue, ui_current->on_demand_fd); close(ui_current->pipe[0]); ui_current->pipe[0] = -1; if (ui_current->use_config) { close(ui_current->pipe_config[0]); ui_current->pipe_config[0] = -1; } ui_current->pid = -1; ui_current->status = 0; ui_current->cursed_at = 0; ui_current->ready = 0; ui_current->accepting = 0; uwsgi_log("[uwsgi-emperor] %s -> back to \"on demand\" mode, waiting for connections on socket \"%s\" ...\n", ui_current->name, ui_current->socket_name); break; } } else if (ui_current->cursed_at > 0) { if (ui_current->pid == -1) { emperor_del(ui_current); // temporarily set frequency to 0, so we can eventually fast-restart the instance freq = 0; break; } else if (now - ui_current->cursed_at >= uwsgi.emperor_curse_tolerance) { ui_current->cursed_at = now; if (kill(ui_current->pid, SIGKILL) < 0) { uwsgi_error("[emperor] kill()"); // delete the vassal, something is seriously wrong better to not leak memory... emperor_del(ui_current); } break; } } } // if waitpid returned an item, let's check for another (potential) one if (diedpid > 0) goto recheck; } uwsgi_log_verbose("The Emperor is buried.\n"); uwsgi_notify("The Emperor is buried."); exit(0); } void emperor_send_stats(int fd) { struct sockaddr_un client_src; socklen_t client_src_len = 0; int client_fd = accept(fd, (struct sockaddr *) &client_src, &client_src_len); if (client_fd < 0) { uwsgi_error("accept()"); return; } if (uwsgi.stats_http) { if (uwsgi_send_http_stats(client_fd)) { close(client_fd); return; } } struct uwsgi_stats *us = uwsgi_stats_new(8192); if (uwsgi_stats_keyval_comma(us, "version", UWSGI_VERSION)) goto end; if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) getpid())) goto end; if (uwsgi_stats_keylong_comma(us, "uid", (unsigned long long) getuid())) goto end; if (uwsgi_stats_keylong_comma(us, "gid", (unsigned long long) getgid())) goto end; char *cwd = uwsgi_get_cwd(); if (uwsgi_stats_keyval_comma(us, "cwd", cwd)) goto end0; if (uwsgi_stats_key(us, "emperor")) goto end0; if (uwsgi_stats_list_open(us)) goto end0; struct uwsgi_emperor_scanner *ues = emperor_scanners; while (ues) { if (uwsgi_stats_str(us, ues->arg)) goto end0; ues = ues->next; if (ues) { if (uwsgi_stats_comma(us)) goto end0; } } if (uwsgi_stats_list_close(us)) goto end0; if (uwsgi_stats_comma(us)) goto end0; if (uwsgi_stats_keylong_comma(us, "emperor_tyrant", (unsigned long long) uwsgi.emperor_tyrant)) goto end0; // will be zero for now if (uwsgi_stats_keylong_comma(us, "throttle_level", (unsigned long long) 0)) goto end0; if (uwsgi_stats_key(us, "vassals")) goto end0; if (uwsgi_stats_list_open(us)) goto end0; struct uwsgi_instance *c_ui = ui->ui_next; while (c_ui) { if (uwsgi_stats_object_open(us)) goto end0; if (uwsgi_stats_keyval_comma(us, "id", c_ui->name)) goto end0; if (uwsgi_stats_keyslong_comma(us, "pid", (long long) c_ui->pid)) goto end0; if (uwsgi_stats_keylong_comma(us, "born", (unsigned long long) c_ui->born)) goto end0; if (uwsgi_stats_keylong_comma(us, "last_mod", (unsigned long long) c_ui->last_mod)) goto end0; if (uwsgi_stats_keylong_comma(us, "last_heartbeat", (unsigned long long) c_ui->last_heartbeat)) goto end0; if (uwsgi_stats_keylong_comma(us, "loyal", (unsigned long long) c_ui->loyal)) goto end0; if (uwsgi_stats_keylong_comma(us, "ready", (unsigned long long) c_ui->ready)) goto end0; if (uwsgi_stats_keylong_comma(us, "accepting", (unsigned long long) c_ui->accepting)) goto end0; if (uwsgi_stats_keylong_comma(us, "last_loyal", (unsigned long long) c_ui->last_loyal)) goto end0; if (uwsgi_stats_keylong_comma(us, "last_ready", (unsigned long long) c_ui->last_ready)) goto end0; if (uwsgi_stats_keylong_comma(us, "last_accepting", (unsigned long long) c_ui->last_accepting)) goto end0; if (uwsgi_stats_keylong_comma(us, "first_run", (unsigned long long) c_ui->first_run)) goto end0; if (uwsgi_stats_keylong_comma(us, "last_run", (unsigned long long) c_ui->last_run)) goto end0; if (uwsgi_stats_keylong_comma(us, "cursed", (unsigned long long) c_ui->cursed_at)) goto end0; if (uwsgi_stats_keylong_comma(us, "zerg", (unsigned long long) c_ui->zerg)) goto end0; if (uwsgi_stats_keyval_comma(us, "on_demand", c_ui->socket_name ? c_ui->socket_name : "")) goto end0; if (uwsgi_stats_keylong_comma(us, "uid", (unsigned long long) c_ui->uid)) goto end0; if (uwsgi_stats_keylong_comma(us, "gid", (unsigned long long) c_ui->gid)) goto end0; if (uwsgi_stats_keyval_comma(us, "monitor", c_ui->scanner->arg)) goto end0; if (uwsgi_stats_keylong(us, "respawns", (unsigned long long) c_ui->respawns)) goto end0; if (uwsgi_stats_object_close(us)) goto end0; c_ui = c_ui->ui_next; if (c_ui) { if (uwsgi_stats_comma(us)) goto end0; } } if (uwsgi_stats_list_close(us)) goto end0; if (uwsgi_stats_comma(us)) goto end0; if (uwsgi_stats_key(us, "blacklist")) goto end0; if (uwsgi_stats_list_open(us)) goto end0; struct uwsgi_emperor_blacklist_item *uebi = emperor_blacklist; while (uebi) { if (uwsgi_stats_object_open(us)) goto end0; if (uwsgi_stats_keyval_comma(us, "id", uebi->id)) goto end0; if (uwsgi_stats_keylong_comma(us, "throttle_level", uebi->throttle_level / 1000)) goto end0; if (uwsgi_stats_keylong_comma(us, "attempt", (unsigned long long) uebi->attempt)) goto end0; if (uwsgi_stats_keylong_comma(us, "first_attempt", (unsigned long long) uebi->first_attempt.tv_sec)) goto end0; if (uwsgi_stats_keylong(us, "last_attempt", (unsigned long long) uebi->last_attempt.tv_sec)) goto end0; if (uwsgi_stats_object_close(us)) goto end0; uebi = uebi->next; if (uebi) { if (uwsgi_stats_comma(us)) goto end0; } } if (uwsgi_stats_list_close(us)) goto end0; if (uwsgi_stats_object_close(us)) goto end0; size_t remains = us->pos; off_t pos = 0; while (remains > 0) { int ret = uwsgi_waitfd_write(client_fd, uwsgi.socket_timeout); if (ret <= 0) { goto end0; } ssize_t res = write(client_fd, us->base + pos, remains); if (res <= 0) { if (res < 0) { uwsgi_error("write()"); } goto end0; } pos += res; remains -= res; } end0: free(cwd); end: free(us->base); free(us); close(client_fd); } void uwsgi_emperor_start() { if (!uwsgi.sockets && !ushared->gateways_cnt && !uwsgi.master_process) { if (uwsgi.emperor_procname) { uwsgi_set_processname(uwsgi.emperor_procname); } uwsgi_notify_ready(); emperor_loop(); // never here exit(1); } if (uwsgi.emperor_procname) { uwsgi.emperor_pid = uwsgi_fork(uwsgi.emperor_procname); } else { uwsgi.emperor_pid = uwsgi_fork("uWSGI Emperor"); } if (uwsgi.emperor_pid < 0) { uwsgi_error("pid()"); exit(1); } else if (uwsgi.emperor_pid == 0) { #ifdef __linux__ if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) { uwsgi_error("prctl()"); } #endif emperor_loop(); // never here exit(1); } } void uwsgi_check_emperor() { char *emperor_fd_pass = getenv("UWSGI_EMPEROR_PROXY"); if (emperor_fd_pass) { for (;;) { int proxy_fd = uwsgi_connect(emperor_fd_pass, 30, 0); if (proxy_fd < 0) { uwsgi_error("uwsgi_check_emperor()/uwsgi_connect()"); sleep(1); continue; } int count = 2; int *fds = uwsgi_attach_fd(proxy_fd, &count, "uwsgi-emperor", 13); if (fds && count > 0) { char *env_emperor_fd = uwsgi_num2str(fds[0]); if (setenv("UWSGI_EMPEROR_FD", env_emperor_fd, 1)) { uwsgi_error("uwsgi_check_emperor()/setenv(UWSGI_EMPEROR_FD)"); free(env_emperor_fd); int i; for (i = 0; i < count; i++) close(fds[i]); goto next; } free(env_emperor_fd); if (count > 1) { char *env_emperor_fd_config = uwsgi_num2str(fds[1]); if (setenv("UWSGI_EMPEROR_FD_CONFIG", env_emperor_fd_config, 1)) { uwsgi_error("uwsgi_check_emperor()/setenv(UWSGI_EMPEROR_FD_CONFIG)"); free(env_emperor_fd_config); int i; for (i = 0; i < count; i++) close(fds[i]); goto next; } free(env_emperor_fd_config); } if (fds) free(fds); close(proxy_fd); break; } next: if (fds) free(fds); close(proxy_fd); sleep(1); } unsetenv("UWSGI_EMPEROR_PROXY"); } char *emperor_env = getenv("UWSGI_EMPEROR_FD"); if (emperor_env) { uwsgi.has_emperor = 1; uwsgi.emperor_fd = atoi(emperor_env); uwsgi.master_process = 1; uwsgi_log("*** has_emperor mode detected (fd: %d) ***\n", uwsgi.emperor_fd); if (getenv("UWSGI_EMPEROR_FD_CONFIG")) { uwsgi.emperor_fd_config = atoi(getenv("UWSGI_EMPEROR_FD_CONFIG")); } } } void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char *config, time_t ts, uid_t uid, gid_t gid, char *socket_name) { if (!uwsgi_emperor_is_valid(name)) return; struct uwsgi_instance *ui_current = emperor_get(name); if (ui_current) { // skip in case the instance is going down... if (ui_current->status > 0) return; // check if uid or gid are changed, in such case, stop the instance if (uwsgi.emperor_tyrant) { if (uid != ui_current->uid || gid != ui_current->gid) { uwsgi_log("[emperor-tyrant] !!! permissions of vassal %s changed. stopping the instance... !!!\n", name); emperor_stop(ui_current); return; } } // check if mtime is changed and the uWSGI instance must be reloaded if (ts > ui_current->last_mod) { // now we neeed a special check for allowing an instance to move to "on_demand" mode (and back) // allowing means "stoppping the instance" if ((!ui_current->socket_name && ui_current->on_demand_fd == -1) && socket_name) { uwsgi_log("[uwsgi-emperor] %s -> requested move to \"on demand\" mode for socket \"%s\" ...\n", name, socket_name); emperor_stop(ui_current); return; } else if ((ui_current->socket_name && ui_current->on_demand_fd > -1) && !socket_name) { uwsgi_log("[uwsgi-emperor] %s -> asked for leaving \"on demand\" mode for socket \"%s\" ...\n", name, ui_current->socket_name); emperor_stop(ui_current); return; } // make a new config (free the old one) if needed if (config) { if (ui_current->config) free(ui_current->config); ui_current->config = uwsgi_str(config); ui_current->config_len = strlen(ui_current->config); } // reload the instance emperor_respawn(ui_current, ts); } } else { // make a copy of the config as it will be freed char *new_config = NULL; size_t new_config_len = 0; if (config) { new_config = uwsgi_str(config); new_config_len = strlen(new_config); } emperor_add(ues, name, ts, new_config, new_config_len, uid, gid, socket_name); } } void uwsgi_master_manage_emperor() { char byte; #ifdef UWSGI_EVENT_USE_PORT // special cose for port event system // place the socket in non-blocking mode uwsgi_socket_nb(uwsgi.emperor_fd); #endif ssize_t rlen = read(uwsgi.emperor_fd, &byte, 1); #ifdef UWSGI_EVENT_USE_PORT // special cose for port event system // and place back in blocking mode uwsgi_socket_b(uwsgi.emperor_fd); #endif if (rlen > 0) { uwsgi_log_verbose("received message %d from emperor\n", byte); // remove me if (byte == 0) { uwsgi_hooks_run(uwsgi.hook_emperor_stop, "emperor-stop", 0); close(uwsgi.emperor_fd); if (!uwsgi.status.brutally_reloading && !uwsgi.status.brutally_destroying) { kill_them_all(0); } } // reload me else if (byte == 1) { uwsgi_hooks_run(uwsgi.hook_emperor_reload, "emperor-reload", 0); // un-lazy the stack to trigger a real reload uwsgi.lazy = 0; uwsgi_block_signal(SIGHUP); grace_them_all(0); uwsgi_unblock_signal(SIGHUP); } // remove me gracefully else if (byte == 2) { uwsgi_hooks_run(uwsgi.hook_emperor_stop, "emperor-stop", 0); close(uwsgi.emperor_fd); if (!uwsgi.status.brutally_reloading && !uwsgi.status.brutally_destroying) { gracefully_kill_them_all(0); } } } #ifdef UWSGI_EVENT_USE_PORT // special cose for port event system else if (rlen < 0 && uwsgi_is_again()) { return; } #endif else { uwsgi_error("uwsgi_master_manage_emperor()/read()"); uwsgi_log("lost connection with my emperor !!!\n"); uwsgi_hooks_run(uwsgi.hook_emperor_lost, "emperor-lost", 0); close(uwsgi.emperor_fd); if (!uwsgi.status.brutally_reloading) kill_them_all(0); sleep(2); exit(1); } } void uwsgi_master_manage_emperor_proxy() { struct sockaddr_un epsun; socklen_t epsun_len = sizeof(struct sockaddr_un); int ep_client = accept(uwsgi.emperor_fd_proxy, (struct sockaddr *) &epsun, &epsun_len); if (ep_client < 0) { uwsgi_error("uwsgi_master_manage_emperor_proxy()/accept()"); return; } int num_fds = 1; if (uwsgi.emperor_fd_config > -1) num_fds++; struct msghdr ep_msg; void *ep_msg_control = uwsgi_malloc(CMSG_SPACE(sizeof(int) * num_fds)); struct iovec ep_iov[2]; struct cmsghdr *cmsg; ep_iov[0].iov_base = "uwsgi-emperor"; ep_iov[0].iov_len = 13; ep_iov[1].iov_base = &num_fds; ep_iov[1].iov_len = sizeof(int); ep_msg.msg_name = NULL; ep_msg.msg_namelen = 0; ep_msg.msg_iov = ep_iov; ep_msg.msg_iovlen = 2; ep_msg.msg_flags = 0; ep_msg.msg_control = ep_msg_control; ep_msg.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds); cmsg = CMSG_FIRSTHDR(&ep_msg); cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; unsigned char *ep_fd_ptr = CMSG_DATA(cmsg); memcpy(ep_fd_ptr, &uwsgi.emperor_fd, sizeof(int)); if (num_fds > 1) { memcpy(ep_fd_ptr + sizeof(int), &uwsgi.emperor_fd_config, sizeof(int)); } if (sendmsg(ep_client, &ep_msg, 0) < 0) { uwsgi_error("uwsgi_master_manage_emperor_proxy()/sendmsg()"); } free(ep_msg_control); close(ep_client); } static void emperor_notify_ready() { if (!uwsgi.has_emperor) return; char byte = 1; if (write(uwsgi.emperor_fd, &byte, 1) != 1) { uwsgi_error("emperor_notify_ready()/write()"); exit(1); } } void uwsgi_setup_emperor() { if (!uwsgi.has_emperor) return; uwsgi.notify_ready = emperor_notify_ready; } uwsgi-2.0.29/core/errors.c000066400000000000000000000057571477626554400154140ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; static int error_page(struct wsgi_request *wsgi_req, struct uwsgi_string_list *l) { struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, l) { struct stat st; if (!stat(usl->value, &st)) { int fd = open(usl->value, O_RDONLY); if (fd >= 0) { if (uwsgi_response_add_header(wsgi_req, "Content-Type", 12, "text/html", 9)) { close(fd); return 0;} if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) { close(fd); return 0;} uwsgi_response_sendfile_do(wsgi_req, fd, 0, st.st_size); return -1; } } } return 0; } // generate internal server error message void uwsgi_500(struct wsgi_request *wsgi_req) { if (uwsgi_response_prepare_headers(wsgi_req, "500 Internal Server Error", 25)) return; if (uwsgi_response_add_connection_close(wsgi_req)) return; if (error_page(wsgi_req, uwsgi.error_page_500)) return; if (uwsgi_response_add_header(wsgi_req, "Content-Type", 12, "text/plain", 10)) return; uwsgi_response_write_body_do(wsgi_req, "Internal Server Error", 21); } void uwsgi_404(struct wsgi_request *wsgi_req) { if (uwsgi_response_prepare_headers(wsgi_req, "404 Not Found", 13)) return; if (uwsgi_response_add_connection_close(wsgi_req)) return; if (error_page(wsgi_req, uwsgi.error_page_404)) return; if (uwsgi_response_add_header(wsgi_req, "Content-Type", 12, "text/plain", 10)) return; uwsgi_response_write_body_do(wsgi_req, "Not Found", 9); } void uwsgi_403(struct wsgi_request *wsgi_req) { if (uwsgi_response_prepare_headers(wsgi_req, "403 Forbidden", 13)) return; if (uwsgi_response_add_connection_close(wsgi_req)) return; if (error_page(wsgi_req, uwsgi.error_page_403)) return; if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) return; uwsgi_response_write_body_do(wsgi_req, "Forbidden", 9); } void uwsgi_405(struct wsgi_request *wsgi_req) { if (uwsgi_response_prepare_headers(wsgi_req, "405 Method Not Allowed", 22)) return; if (uwsgi_response_add_connection_close(wsgi_req)) return; if (error_page(wsgi_req, uwsgi.error_page_403)) return; if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) return; uwsgi_response_write_body_do(wsgi_req, "Method Not Allowed", 18); } void uwsgi_redirect_to_slash(struct wsgi_request *wsgi_req) { char *redirect = NULL; size_t redirect_len = 0; if (uwsgi_response_prepare_headers(wsgi_req, "301 Moved Permanently", 21)) return; if (uwsgi_response_add_connection_close(wsgi_req)) return; if (wsgi_req->query_string_len == 0) { redirect = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "/", 1); redirect_len = wsgi_req->path_info_len + 1; } else { redirect = uwsgi_concat3n(wsgi_req->path_info, wsgi_req->path_info_len, "/?", 2, wsgi_req->query_string, wsgi_req->query_string_len); redirect_len = wsgi_req->path_info_len + 2 + wsgi_req->query_string_len; } uwsgi_response_add_header(wsgi_req, "Location", 8, redirect, redirect_len); free(redirect); return; } uwsgi-2.0.29/core/event.c000066400000000000000000000702771477626554400152200ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; #ifdef UWSGI_EVENT_USE_POLL #define UWSGI_EVENT_IN POLLIN #define UWSGI_EVENT_OUT POLLOUT int uwsgi_poll_event_queue_max = 0; struct uwsgi_poll_event { int nevents; int max_events; pthread_mutex_t lock; struct pollfd *poll; }; struct uwsgi_poll_event **uwsgi_poll_event_queue; // all of the public functions must be heavy locked static int uwsgi_poll_fd_is_registered(struct uwsgi_poll_event *upe, int fd) { int i; for(i=0;inevents;i++) { if (upe->poll[i].fd == fd) { return 1; } } return 0; } static int uwsgi_poll_fd_add(struct uwsgi_poll_event *upe, int fd, int event) { int pos = upe->nevents; if (pos > upe->max_events) return -1; upe->poll[pos].fd = fd; upe->poll[pos].events = event; upe->nevents++; return 0; } static int uwsgi_poll_fd_del(struct uwsgi_poll_event *upe, int fd) { int i; for(i=0;inevents;i++) { if (upe->poll[i].fd == fd) { if (i < upe->nevents-1) { memcpy(&upe->poll[i], &upe->poll[i+1], sizeof(struct uwsgi_poll_event) * (upe->nevents - (i+1))); } upe->nevents--; return 0; } } return -1; } static void uwsgi_poll_queue_rebuild(struct uwsgi_poll_event *upe) { // we need to check if some file descriptor is no more valid int i; for(i=0;inevents;i++) { if (!uwsgi_valid_fd(upe->poll[i].fd)) { uwsgi_poll_fd_del(upe, upe->poll[i].fd); } } } int event_queue_wait(int eq, int timeout, int *interesting_fd) { struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq]; pthread_mutex_lock(&upe->lock); uwsgi_poll_queue_rebuild(upe); int ret = poll(upe->poll, upe->nevents, timeout * 1000); if (ret > 0) { int i; for(i=0;inevents;i++) { if (upe->poll[i].revents) { *interesting_fd = upe->poll[i].fd; pthread_mutex_unlock(&upe->lock); return 1; } } } pthread_mutex_unlock(&upe->lock); return ret; } int event_queue_init() { if (!uwsgi_poll_event_queue) { uwsgi_poll_event_queue = uwsgi_calloc(sizeof(struct uwsgi_poll_event *) * uwsgi.max_fd); } int eq = uwsgi_poll_event_queue_max; uwsgi_poll_event_queue[eq] = uwsgi_calloc(sizeof(struct uwsgi_poll_event)); uwsgi_poll_event_queue_max++; uwsgi_poll_event_queue[eq]->poll = uwsgi_malloc(sizeof(struct pollfd) * uwsgi.max_fd); uwsgi_poll_event_queue[eq]->max_events = uwsgi.max_fd; pthread_mutex_init(&uwsgi_poll_event_queue[eq]->lock, NULL); return eq; } void *event_queue_alloc(int nevents) { return uwsgi_calloc(sizeof(struct pollfd) * nevents); } int event_queue_interesting_fd_is_read(void *events, int id) { struct pollfd *pevents = (struct pollfd *)events; struct pollfd *upoll = &pevents[id]; if (upoll->revents & POLLIN) { return 1; } return 0; } int event_queue_fd_write_to_readwrite(int eq, int fd) { struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq]; pthread_mutex_lock(&upe->lock); int i; for(i=0;inevents;i++) { if (upe->poll[i].fd == fd) { upe->poll[i].events = POLLIN|POLLOUT; pthread_mutex_unlock(&upe->lock); return 0; } } pthread_mutex_unlock(&upe->lock); return -1; } int event_queue_fd_read_to_readwrite(int eq, int fd) { return event_queue_fd_write_to_readwrite(eq, fd); } int event_queue_interesting_fd_is_write(void *events, int id) { struct pollfd *pevents = (struct pollfd *)events; struct pollfd *upoll = &pevents[id]; if (upoll->revents & POLLOUT) { return 1; } return 0; } int event_queue_add_fd_read(int eq, int fd) { struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq]; pthread_mutex_lock(&upe->lock); if (uwsgi_poll_fd_is_registered(upe, fd)) { pthread_mutex_unlock(&upe->lock); return 0; } int ret = uwsgi_poll_fd_add(upe, fd, POLLIN); pthread_mutex_unlock(&upe->lock); return ret; } int event_queue_add_fd_write(int eq, int fd) { struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq]; pthread_mutex_lock(&upe->lock); if (uwsgi_poll_fd_is_registered(upe, fd)) { pthread_mutex_unlock(&upe->lock); return 0; } int ret = uwsgi_poll_fd_add(upe, fd, POLLOUT); pthread_mutex_unlock(&upe->lock); return ret; } int event_queue_del_fd(int eq, int fd, int event) { struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq]; pthread_mutex_lock(&upe->lock); int ret = uwsgi_poll_fd_del(upe, fd); pthread_mutex_unlock(&upe->lock); return ret; } int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) { struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq]; pthread_mutex_lock(&upe->lock); uwsgi_poll_queue_rebuild(upe); int ret = poll(upe->poll, upe->nevents, timeout * 1000); int cnt = 0; if (ret > 0) { int i; for(i=0;inevents;i++) { if (upe->poll[i].revents) { if (cnt >= nevents) break; struct pollfd *pevents = (struct pollfd *)events; struct pollfd *upoll = &pevents[cnt]; upoll->fd = upe->poll[i].fd; upoll->revents = upe->poll[i].revents; upoll->events = upe->poll[i].events; cnt++; } } } pthread_mutex_unlock(&upe->lock); if (ret <= 0) return ret; return cnt; } int event_queue_interesting_fd_has_error(void *events, int id) { struct pollfd *pevents = (struct pollfd *)events; struct pollfd *upoll = &pevents[id]; if (upoll->revents & POLLERR || upoll->revents & POLLHUP || upoll->revents & POLLNVAL) { return 1; } return 0; } int event_queue_interesting_fd(void *events, int id) { struct pollfd *pevents = (struct pollfd *)events; struct pollfd *upoll = &pevents[id]; return upoll->fd; } int event_queue_fd_write_to_read(int eq, int fd) { struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq]; pthread_mutex_lock(&upe->lock); int i; for(i=0;inevents;i++) { if (upe->poll[i].fd == fd) { upe->poll[i].events = POLLIN; pthread_mutex_unlock(&upe->lock); return 0; } } pthread_mutex_unlock(&upe->lock); return -1; } int event_queue_fd_read_to_write(int eq, int fd) { struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq]; pthread_mutex_lock(&upe->lock); int i; for(i=0;inevents;i++) { if (upe->poll[i].fd == fd) { upe->poll[i].events = POLLOUT; pthread_mutex_unlock(&upe->lock); return 0; } } pthread_mutex_unlock(&upe->lock); return -1; } #endif #ifdef UWSGI_EVENT_USE_PORT #include #define UWSGI_EVENT_IN POLLIN #define UWSGI_EVENT_OUT POLLOUT int event_queue_init() { int port = port_create(); if (port < 0) { uwsgi_error("port_create()"); return -1; } return port; } int event_queue_del_fd(int eq, int fd, int event) { if (port_dissociate(eq, PORT_SOURCE_FD, fd)) { uwsgi_error("port_disassociate"); return -1; } return 0; } int event_queue_fd_write_to_read(int eq, int fd) { if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, (void *)((long) eq))) { uwsgi_error("port_associate"); return -1; } return 0; } int event_queue_fd_read_to_write(int eq, int fd) { if (port_associate(eq, PORT_SOURCE_FD, fd, POLLOUT, (void *)((long) eq))) { uwsgi_error("port_associate"); return -1; } return 0; } int event_queue_fd_readwrite_to_read(int eq, int fd) { if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, (void *)((long) eq))) { uwsgi_error("port_associate"); return -1; } return 0; } int event_queue_fd_readwrite_to_write(int eq, int fd) { if (port_associate(eq, PORT_SOURCE_FD, fd, POLLOUT, (void *)((long) eq))) { uwsgi_error("port_associate"); return -1; } return 0; } int event_queue_fd_write_to_readwrite(int eq, int fd) { if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN | POLLOUT, (void *)((long) eq))) { uwsgi_error("port_associate"); return -1; } return 0; } int event_queue_fd_read_to_readwrite(int eq, int fd) { if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN | POLLOUT, (void *)((long) eq))) { uwsgi_error("port_associate"); return -1; } return 0; } int event_queue_interesting_fd_has_error(void *events, int id) { port_event_t *pe = (port_event_t *) events; if (pe[id].portev_events == POLLHUP || pe[id].portev_events == POLLERR) { return 1; } return 0; } int event_queue_interesting_fd_is_read(void *events, int id) { port_event_t *pe = (port_event_t *) events; if (pe[id].portev_events == POLLIN) { return 1; } return 0; } int event_queue_interesting_fd_is_write(void *events, int id) { port_event_t *pe = (port_event_t *) events; if (pe[id].portev_events == POLLOUT) { return 1; } return 0; } int event_queue_add_fd_read(int eq, int fd) { if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, (void *)((long) eq))) { uwsgi_error("port_associate"); return -1; } return 0; } int event_queue_add_fd_write(int eq, int fd) { if (port_associate(eq, PORT_SOURCE_FD, fd, POLLOUT, (void *)((long) eq))) { uwsgi_error("port_associate"); return -1; } return 0; } void *event_queue_alloc(int nevents) { return uwsgi_malloc(sizeof(port_event_t) * nevents); } int event_queue_interesting_fd(void *events, int id) { port_event_t *pe = (port_event_t *) events; #ifdef PORT_SOURCE_FILE if (pe[id].portev_source == PORT_SOURCE_FILE || pe[id].portev_source == PORT_SOURCE_TIMER) { #else if (pe[id].portev_source == PORT_SOURCE_TIMER) { #endif return (long) pe[id].portev_user; } int fd = (int) pe[id].portev_object; int eq = (long) pe[id].portev_user; if (pe[id].portev_events == POLLOUT) { event_queue_add_fd_write(eq, fd); } if (pe[id].portev_events == POLLIN) { event_queue_add_fd_read(eq, fd); } return fd; } int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) { int ret; uint_t nget = 1; timespec_t ts; if (timeout >= 0) { ts.tv_sec = timeout; ts.tv_nsec = 0; ret = port_getn(eq, events, nevents, &nget, &ts); } else { ret = port_getn(eq, events, nevents, &nget, NULL); } if (ret < 0) { if (errno == ETIME) return 0; if (errno != EINTR) { uwsgi_error("port_getn()"); } return -1; } uint_t i; port_event_t *pe = (port_event_t *) events; for(i=0;iportev_source == PORT_SOURCE_FD) { // event must be readded (damn Oracle/Sun why the fu*k you made such a horrible choice ???? why not adding a ONESHOT flag ???) if (port_associate(eq, pe_i->portev_source, pe_i->portev_object, pe_i->portev_events, (void *)((long) eq))) { uwsgi_error("port_associate"); } } } return nget; } int event_queue_wait(int eq, int timeout, int *interesting_fd) { int ret; port_event_t pe; timespec_t ts; if (timeout > 0) { ts.tv_sec = timeout; ts.tv_nsec = 0; ret = port_get(eq, &pe, &ts); } else { ret = port_get(eq, &pe, NULL); } if (ret < 0) { if (errno == ETIME) return 0; if (errno != EINTR) { uwsgi_error("port_get()"); } return -1; } if (pe.portev_source == PORT_SOURCE_FD) { // event must be readded (damn Oracle/Sun why the fu*k you made such a horrible choice ???? why not adding a ONESHOT flag ???) if (port_associate(eq, pe.portev_source, pe.portev_object, pe.portev_events, (void *)((long) eq))) { uwsgi_error("port_associate"); } } #ifdef PORT_SOURCE_FILE if (pe.portev_source == PORT_SOURCE_FILE || pe.portev_source == PORT_SOURCE_TIMER) { #else if (pe.portev_source == PORT_SOURCE_TIMER) { #endif *interesting_fd = (long) pe.portev_user; } else { *interesting_fd = (int) pe.portev_object; } return 1; } #endif #ifdef UWSGI_EVENT_USE_EPOLL #include #define UWSGI_EVENT_IN EPOLLIN #define UWSGI_EVENT_OUT EPOLLOUT int event_queue_init() { int epfd; epfd = epoll_create(256); if (epfd < 0) { uwsgi_error("epoll_create()"); return -1; } return epfd; } int event_queue_add_fd_read(int eq, int fd) { struct epoll_event ee; memset(&ee, 0, sizeof(struct epoll_event)); ee.events = EPOLLIN; ee.data.fd = fd; if (epoll_ctl(eq, EPOLL_CTL_ADD, fd, &ee)) { uwsgi_error("epoll_ctl()"); return -1; } return 0; } int event_queue_fd_write_to_read(int eq, int fd) { struct epoll_event ee; memset(&ee, 0, sizeof(struct epoll_event)); ee.events = EPOLLIN; ee.data.fd = fd; if (epoll_ctl(eq, EPOLL_CTL_MOD, fd, &ee)) { uwsgi_error("epoll_ctl()"); return -1; } return 0; } int event_queue_fd_read_to_write(int eq, int fd) { struct epoll_event ee; memset(&ee, 0, sizeof(struct epoll_event)); ee.events = EPOLLOUT; ee.data.fd = fd; if (epoll_ctl(eq, EPOLL_CTL_MOD, fd, &ee)) { uwsgi_error("epoll_ctl()"); return -1; } return 0; } int event_queue_fd_readwrite_to_read(int eq, int fd) { struct epoll_event ee; memset(&ee, 0, sizeof(struct epoll_event)); ee.events = EPOLLIN; ee.data.fd = fd; if (epoll_ctl(eq, EPOLL_CTL_MOD, fd, &ee)) { uwsgi_error("epoll_ctl()"); return -1; } return 0; } int event_queue_fd_readwrite_to_write(int eq, int fd) { struct epoll_event ee; memset(&ee, 0, sizeof(struct epoll_event)); ee.events = EPOLLOUT; ee.data.fd = fd; if (epoll_ctl(eq, EPOLL_CTL_MOD, fd, &ee)) { uwsgi_error("epoll_ctl()"); return -1; } return 0; } int event_queue_fd_read_to_readwrite(int eq, int fd) { struct epoll_event ee; memset(&ee, 0, sizeof(struct epoll_event)); ee.events = EPOLLIN | EPOLLOUT; ee.data.fd = fd; if (epoll_ctl(eq, EPOLL_CTL_MOD, fd, &ee)) { uwsgi_error("epoll_ctl()"); return -1; } return 0; } int event_queue_fd_write_to_readwrite(int eq, int fd) { struct epoll_event ee; memset(&ee, 0, sizeof(struct epoll_event)); ee.events = EPOLLIN | EPOLLOUT; ee.data.fd = fd; if (epoll_ctl(eq, EPOLL_CTL_MOD, fd, &ee)) { uwsgi_error("epoll_ctl()"); return -1; } return 0; } int event_queue_del_fd(int eq, int fd, int event) { struct epoll_event ee; memset(&ee, 0, sizeof(struct epoll_event)); ee.data.fd = fd; ee.events = event; if (epoll_ctl(eq, EPOLL_CTL_DEL, fd, &ee)) { uwsgi_error("epoll_ctl()"); return -1; } return 0; } int event_queue_add_fd_write(int eq, int fd) { struct epoll_event ee; memset(&ee, 0, sizeof(struct epoll_event)); ee.events = EPOLLOUT; ee.data.fd = fd; if (epoll_ctl(eq, EPOLL_CTL_ADD, fd, &ee)) { uwsgi_error("epoll_ctl()"); return -1; } return 0; } void *event_queue_alloc(int nevents) { return uwsgi_malloc(sizeof(struct epoll_event) * nevents); } int event_queue_interesting_fd(void *events, int id) { struct epoll_event *ee = (struct epoll_event *) events; return ee[id].data.fd; } int event_queue_interesting_fd_has_error(void *events, int id) { struct epoll_event *ee = (struct epoll_event *) events; if (ee[id].events == EPOLLHUP || ee[id].events == EPOLLERR || (ee[id].events == (EPOLLERR | EPOLLHUP))) { return 1; } return 0; } int event_queue_interesting_fd_is_read(void *events, int id) { struct epoll_event *ee = (struct epoll_event *) events; if (ee[id].events & EPOLLIN) { return 1; } return 0; } int event_queue_interesting_fd_is_write(void *events, int id) { struct epoll_event *ee = (struct epoll_event *) events; if (ee[id].events & EPOLLOUT) { return 1; } return 0; } int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) { int ret; if (timeout > 0) { timeout = timeout * 1000; } ret = epoll_wait(eq, (struct epoll_event *) events, nevents, timeout); if (ret < 0) { if (errno != EINTR) uwsgi_error("epoll_wait()"); } return ret; } int event_queue_wait(int eq, int timeout, int *interesting_fd) { int ret; struct epoll_event ee; if (timeout > 0) { timeout = timeout * 1000; } ret = epoll_wait(eq, &ee, 1, timeout); if (ret < 0) { if (errno != EINTR) uwsgi_error("epoll_wait()"); } if (ret > 0) { *interesting_fd = ee.data.fd; } return ret; } #endif #ifdef UWSGI_EVENT_USE_KQUEUE #define UWSGI_EVENT_IN EVFILT_READ #define UWSGI_EVENT_OUT EVFILT_WRITE int event_queue_init() { int kfd = kqueue(); if (kfd < 0) { uwsgi_error("kqueue()"); return -1; } return kfd; } int event_queue_fd_write_to_read(int eq, int fd) { struct kevent kev; EV_SET(&kev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0); if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) { uwsgi_error("kevent()"); return -1; } EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) { uwsgi_error("kevent()"); return -1; } return 0; } int event_queue_fd_read_to_write(int eq, int fd) { struct kevent kev; EV_SET(&kev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) { uwsgi_error("kevent()"); return -1; } EV_SET(&kev, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0); if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) { uwsgi_error("kevent()"); return -1; } return 0; } int event_queue_fd_readwrite_to_read(int eq, int fd) { struct kevent kev; EV_SET(&kev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0); if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) { uwsgi_error("kevent()"); return -1; } return 0; } int event_queue_fd_readwrite_to_write(int eq, int fd) { struct kevent kev; EV_SET(&kev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) { uwsgi_error("kevent()"); return -1; } return 0; } int event_queue_fd_read_to_readwrite(int eq, int fd) { struct kevent kev; EV_SET(&kev, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0); if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) { uwsgi_error("kevent()"); return -1; } return 0; } int event_queue_fd_write_to_readwrite(int eq, int fd) { struct kevent kev; EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) { uwsgi_error("kevent()"); return -1; } return 0; } int event_queue_del_fd(int eq, int fd, int event) { struct kevent kev; EV_SET(&kev, fd, event, EV_DELETE, 0, 0, 0); if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) { uwsgi_error("kevent()"); return -1; } return 0; } int event_queue_add_fd_read(int eq, int fd) { struct kevent kev; EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) { uwsgi_error("kevent()"); return -1; } return 0; } int event_queue_add_fd_write(int eq, int fd) { struct kevent kev; EV_SET(&kev, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0); if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) { uwsgi_error("kevent()"); return -1; } return 0; } void *event_queue_alloc(int nevents) { return uwsgi_malloc(sizeof(struct kevent) * nevents); } int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) { int ret; struct timespec ts; if (timeout < 0) { ret = kevent(eq, NULL, 0, events, nevents, NULL); } else { memset(&ts, 0, sizeof(struct timespec)); ts.tv_sec = timeout; ret = kevent(eq, NULL, 0, (struct kevent *) events, nevents, &ts); } if (ret < 0) { if (errno != EINTR) uwsgi_error("kevent()"); } return ret; } int event_queue_interesting_fd(void *events, int id) { struct kevent *ev = (struct kevent *) events; return ev[id].ident; } int event_queue_interesting_fd_has_error(void *events, int id) { struct kevent *ev = (struct kevent *) events; // DO NOT CHECK FOR EOF !!! if (ev[id].flags & EV_ERROR) { return 1; } return 0; } int event_queue_interesting_fd_is_read(void *events, int id) { struct kevent *ev = (struct kevent *) events; if (ev[id].filter == EVFILT_READ) { return 1; } return 0; } int event_queue_interesting_fd_is_write(void *events, int id) { struct kevent *ev = (struct kevent *) events; if (ev[id].filter == EVFILT_WRITE) { return 1; } return 0; } int event_queue_wait(int eq, int timeout, int *interesting_fd) { int ret; struct timespec ts; struct kevent ev; if (timeout < 0) { ret = kevent(eq, NULL, 0, &ev, 1, NULL); } else { memset(&ts, 0, sizeof(struct timespec)); ts.tv_sec = timeout; ret = kevent(eq, NULL, 0, &ev, 1, &ts); } if (ret < 0) { if (errno != EINTR) uwsgi_error("kevent()"); } if (ret > 0) { *interesting_fd = ev.ident; } return ret; } #endif #ifdef UWSGI_EVENT_FILEMONITOR_USE_NONE int event_queue_add_file_monitor(int eq, char *filename, int *id) { return -1; } struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) { return NULL; } #endif #ifdef UWSGI_EVENT_FILEMONITOR_USE_PORT #ifdef PORT_SOURCE_FILE int event_queue_add_file_monitor(int eq, char *filename, int *id) { struct file_obj fo; struct stat st; static int fmon_id = 0xffffee00; if (stat(filename, &st)) { uwsgi_error("stat()"); return -1; } fo.fo_name = filename; fo.fo_atime = st.st_atim; fo.fo_mtime = st.st_mtim; fo.fo_ctime = st.st_ctim; fmon_id++; if (port_associate(eq, PORT_SOURCE_FILE, (uintptr_t) & fo, FILE_MODIFIED | FILE_ATTRIB, (void *) (long) fmon_id)) { uwsgi_error("port_associate()"); return -1; } *id = fmon_id; uwsgi_log("added new file to monitor %s [%d]\n", filename, *id); return *id; } struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) { int i; struct file_obj fo; struct stat st; for (i = 0; i < ushared->files_monitored_cnt; i++) { if (ushared->files_monitored[i].registered) { if (ushared->files_monitored[i].fd == id) { if (stat(ushared->files_monitored[i].filename, &st)) { uwsgi_error("stat()"); return NULL; } fo.fo_name = ushared->files_monitored[i].filename; fo.fo_atime = st.st_atim; fo.fo_mtime = st.st_mtim; fo.fo_ctime = st.st_ctim; if (port_associate(eq, PORT_SOURCE_FILE, (uintptr_t) & fo, FILE_MODIFIED | FILE_ATTRIB, (void *) (long) id)) { uwsgi_error("port_associate()"); return NULL; } return &ushared->files_monitored[i]; } } } return NULL; } #else int event_queue_add_file_monitor(int eq, char *filename, int *id) { return -1; } struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) { return NULL; } #endif #endif #ifdef UWSGI_EVENT_FILEMONITOR_USE_KQUEUE int event_queue_add_file_monitor(int eq, char *filename, int *id) { struct kevent kev; int fd = open(filename, O_RDONLY); if (fd < 0) { uwsgi_error_open(filename); return -1; } EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE | NOTE_DELETE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE, 0, 0); if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) { uwsgi_error("kevent()"); return -1; } *id = fd; uwsgi_log("added new file to monitor %s\n", filename); return fd; } struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) { int i; for (i = 0; i < ushared->files_monitored_cnt; i++) { if (ushared->files_monitored[i].registered) { if (ushared->files_monitored[i].fd == id) { return &ushared->files_monitored[i]; } } } return NULL; } #endif #ifdef UWSGI_EVENT_FILEMONITOR_USE_INOTIFY #ifdef OBSOLETE_LINUX_KERNEL int event_queue_add_file_monitor(int eq, char *filename, int *id) { return -1; } struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) { return NULL; } #else #include int event_queue_add_file_monitor(int eq, char *filename, int *id) { int ifd = -1; int i; int add_to_queue = 0; for (i = 0; i < ushared->files_monitored_cnt; i++) { if (ushared->files_monitored[i].registered) { ifd = ushared->files_monitored[0].fd; break; } } if (ifd == -1) { ifd = inotify_init(); if (ifd < 0) { uwsgi_error("inotify_init()"); return -1; } add_to_queue = 1; } *id = inotify_add_watch(ifd, filename, IN_ATTRIB | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_MOVED_FROM | IN_MOVED_TO); #ifdef UWSGI_DEBUG uwsgi_log("added watch %d for filename %s\n", *id, filename); #endif if (add_to_queue) { if (event_queue_add_fd_read(eq, ifd)) { return -1; } } return ifd; } struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) { ssize_t rlen = 0; struct inotify_event ie, *bie, *iie; int i, j; int items = 0; unsigned int isize = sizeof(struct inotify_event); struct uwsgi_fmon *uf = NULL; if (ioctl(id, FIONREAD, &isize) < 0) { uwsgi_error("ioctl()"); return NULL; } if (isize > sizeof(struct inotify_event)) { bie = uwsgi_malloc(isize); rlen = read(id, bie, isize); } else { rlen = read(id, &ie, sizeof(struct inotify_event)); bie = &ie; } if (rlen < 0) { uwsgi_error("read()"); } else { items = isize / (sizeof(struct inotify_event)); #ifdef UWSGI_DEBUG uwsgi_log("inotify returned %d items\n", items); #endif for (j = 0; j < items; j++) { iie = &bie[j]; for (i = 0; i < ushared->files_monitored_cnt; i++) { if (ushared->files_monitored[i].registered) { if (ushared->files_monitored[i].fd == id && ushared->files_monitored[i].id == iie->wd) { uf = &ushared->files_monitored[i]; } } } } if (items > 1) { free(bie); } return uf; } return NULL; } #endif #endif #ifdef UWSGI_EVENT_TIMER_USE_TIMERFD #ifndef UWSGI_EVENT_TIMER_USE_TIMERFD_NOINC #include #endif #ifndef TFD_CLOEXEC // timerfd support enum { TFD_CLOEXEC = 02000000, #define TFD_CLOEXEC TFD_CLOEXEC TFD_NONBLOCK = 04000 #define TFD_NONBLOCK TFD_NONBLOCK }; /* Bits to be set in the FLAGS parameter of `timerfd_settime'. */ enum { TFD_TIMER_ABSTIME = 1 << 0 #define TFD_TIMER_ABSTIME TFD_TIMER_ABSTIME }; static int timerfd_create(clockid_t __clock_id, int __flags) { #ifdef __amd64__ return syscall(283, __clock_id, __flags); #elif defined(__i386__) return syscall(322, __clock_id, __flags); #elif defined(__arm__) return syscall(350, __clock_id, __flags); #else return -1; #endif } static int timerfd_settime(int __ufd, int __flags, __const struct itimerspec *__utmr, struct itimerspec *__otmr) { #ifdef __amd64__ return syscall(286, __ufd, __flags, __utmr, __otmr); #elif defined(__i386__) return syscall(325, __ufd, __flags, __utmr, __otmr); #elif defined(__arm__) return syscall(353, __ufd, __flags, __utmr, __otmr); #else return -1; #endif } #endif int event_queue_add_timer(int eq, int *id, int sec) { struct itimerspec it; int tfd = timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC); if (tfd < 0) { uwsgi_error("timerfd_create()"); return -1; } it.it_value.tv_sec = sec; it.it_value.tv_nsec = 0; it.it_interval.tv_sec = sec; it.it_interval.tv_nsec = 0; if (timerfd_settime(tfd, 0, &it, NULL)) { uwsgi_error("timerfd_settime()"); close(tfd); return -1; } *id = tfd; if (event_queue_add_fd_read(eq, tfd)) { return -1; } return tfd; } struct uwsgi_timer *event_queue_ack_timer(int id) { int i; ssize_t rlen; uint64_t counter; struct uwsgi_timer *ut = NULL; for (i = 0; i < ushared->timers_cnt; i++) { if (ushared->timers[i].registered) { if (ushared->timers[i].id == id) { ut = &ushared->timers[i]; } } } rlen = read(id, &counter, sizeof(uint64_t)); if (rlen < 0) { uwsgi_error("read()"); } return ut; } #endif #ifdef UWSGI_EVENT_TIMER_USE_NONE int event_queue_add_timer(int eq, int *id, int sec) { return -1; } struct uwsgi_timer *event_queue_ack_timer(int id) { return NULL; } #endif #ifdef UWSGI_EVENT_TIMER_USE_PORT int event_queue_add_timer(int eq, int *id, int sec) { static int timer_id = 0xffffff00; port_notify_t pnotif; struct sigevent sigev; itimerspec_t it; timer_t tid; timer_id++; pnotif.portnfy_port = eq; pnotif.portnfy_user = (void *) (long) timer_id; sigev.sigev_notify = SIGEV_PORT; sigev.sigev_value.sival_ptr = &pnotif; if (timer_create(CLOCK_REALTIME, &sigev, &tid) < 0) { uwsgi_error("timer_create()"); return -1; } it.it_value.tv_sec = sec; it.it_value.tv_nsec = 0; it.it_interval.tv_sec = sec; it.it_interval.tv_nsec = 0; if (timer_settime(tid, 0, &it, NULL) < 0) { uwsgi_error("timer_settime()"); return -1; } *id = timer_id; return *id; } struct uwsgi_timer *event_queue_ack_timer(int id) { int i; struct uwsgi_timer *ut = NULL; for (i = 0; i < uwsgi.shared->timers_cnt; i++) { if (uwsgi.shared->timers[i].registered) { if (uwsgi.shared->timers[i].id == id) { ut = &uwsgi.shared->timers[i]; } } } return ut; } #endif #ifdef UWSGI_EVENT_TIMER_USE_KQUEUE int event_queue_add_timer(int eq, int *id, int sec) { static int timer_id = 0xffffff00; struct kevent kev; *id = timer_id; timer_id++; EV_SET(&kev, *id, EVFILT_TIMER, EV_ADD, 0, sec * 1000, 0); if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) { uwsgi_error("kevent()"); return -1; } return *id; } struct uwsgi_timer *event_queue_ack_timer(int id) { int i; struct uwsgi_timer *ut = NULL; for (i = 0; i < uwsgi.shared->timers_cnt; i++) { if (uwsgi.shared->timers[i].registered) { if (uwsgi.shared->timers[i].id == id) { ut = &uwsgi.shared->timers[i]; } } } return ut; } #endif int event_queue_read() { return UWSGI_EVENT_IN; } int event_queue_write() { return UWSGI_EVENT_OUT; } uwsgi-2.0.29/core/exceptions.c000066400000000000000000000406041477626554400162470ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; /* Exceptions management generally exceptions are printed in the logs, but if you enable an exception manager they will be stored in a (relatively big) uwsgi packet with the following structure. "vars" -> keyval of request vars "backtrace" -> list of backtrace lines. Each line is a list of 5 elements filename,line,function,text,custom "unix" -> seconds since the epoch "class" -> the exception class "msg" -> a text message mapped to the extension "repr" -> a text message mapped to the extension in language-specific gergo "wid" -> worker id "core" -> the core generating the exception "pid" -> pid of the worker "node" -> hostname Other vars can be added, but you cannot be sure they will be used by exceptions handler. The exception-uwsgi packet is passed "as is" to the exception handler Exceptions hooks: a request plugin can export that hooks: struct uwsgi_buffer *backtrace(struct wsgi_request *); struct uwsgi_buffer *exception_class(struct wsgi_request *); struct uwsgi_buffer *exception_msg(struct wsgi_request *); struct uwsgi_buffer *exception_repr(struct wsgi_request *); void exception_log(struct wsgi_request *); Remember to reset the exception status (if possibile) after each call Exceptions catcher: This is a special development-mode in which exceptions are printed to the HTTP client. */ struct uwsgi_buffer *uwsgi_exception_handler_object(struct wsgi_request *wsgi_req) { struct uwsgi_buffer *ub = uwsgi_buffer_new(4096); if (uwsgi_buffer_append_keyval(ub, "vars", 4, wsgi_req->buffer,wsgi_req->uh->pktsize)) goto error; if (uwsgi.p[wsgi_req->uh->modifier1]->backtrace) { struct uwsgi_buffer *bt = uwsgi.p[wsgi_req->uh->modifier1]->backtrace(wsgi_req); if (bt) { if (uwsgi_buffer_append_keyval(ub, "backtrace", 9, bt->buf, bt->pos)) { uwsgi_buffer_destroy(bt); goto error; } uwsgi_buffer_destroy(bt); } } if (uwsgi.p[wsgi_req->uh->modifier1]->exception_class) { struct uwsgi_buffer *ec = uwsgi.p[wsgi_req->uh->modifier1]->exception_class(wsgi_req); if (ec) { if (uwsgi_buffer_append_keyval(ub, "class", 5, ec->buf, ec->pos)) { uwsgi_buffer_destroy(ec); goto error; } uwsgi_buffer_destroy(ec); } } if (uwsgi.p[wsgi_req->uh->modifier1]->exception_msg) { struct uwsgi_buffer *em = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req); if (em) { if (uwsgi_buffer_append_keyval(ub, "msg", 3, em->buf, em->pos)) { uwsgi_buffer_destroy(em); goto error; } uwsgi_buffer_destroy(em); } } if (uwsgi.p[wsgi_req->uh->modifier1]->exception_repr) { struct uwsgi_buffer *er = uwsgi.p[wsgi_req->uh->modifier1]->exception_repr(wsgi_req); if (er) { if (uwsgi_buffer_append_keyval(ub, "repr", 4, er->buf, er->pos)) { uwsgi_buffer_destroy(er); goto error; } uwsgi_buffer_destroy(er); } } if (uwsgi_buffer_append_keynum(ub, "unix", 4, uwsgi_now())) goto error; if (uwsgi_buffer_append_keynum(ub, "wid", 3, uwsgi.mywid)) goto error; if (uwsgi_buffer_append_keynum(ub, "pid", 3, uwsgi.mypid)) goto error; if (uwsgi_buffer_append_keynum(ub, "core", 4, wsgi_req->async_id)) goto error; if (uwsgi_buffer_append_keyval(ub, "node", 4, uwsgi.hostname, uwsgi.hostname_len)) goto error; return ub; error: uwsgi_buffer_destroy(ub); return NULL; } static void append_vars_to_ubuf(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) { struct uwsgi_buffer *ub = (struct uwsgi_buffer *) data; if (uwsgi_buffer_append(ub, key, keylen)) return; if (uwsgi_buffer_append(ub, " = ", 3)) return; if (uwsgi_buffer_append(ub, val, vallen)) return; if (uwsgi_buffer_append(ub, "\n", 1)) return; } static void append_backtrace_to_ubuf(uint16_t pos, char *value, uint16_t len, void *data) { struct uwsgi_buffer *ub = (struct uwsgi_buffer *) data; uint16_t item = 0; if (pos > 0) { item = pos % 5; } switch(item) { // filename case 0: if (uwsgi_buffer_append(ub, "filename: \"", 11)) return; if (uwsgi_buffer_append(ub, value, len)) return; if (uwsgi_buffer_append(ub, "\" ", 2)) return; break; // lineno case 1: if (uwsgi_buffer_append(ub, "line: ", 6)) return; if (uwsgi_buffer_append(ub, value, len)) return; if (uwsgi_buffer_append(ub, " ", 1)) return; break; // function case 2: if (uwsgi_buffer_append(ub, "function: \"", 11)) return; if (uwsgi_buffer_append(ub, value, len)) return; if (uwsgi_buffer_append(ub, "\" ", 2)) return; break; // text case 3: if (len > 0) { if (uwsgi_buffer_append(ub, "text/code: \"", 12)) return; if (uwsgi_buffer_append(ub, value, len)) return; if (uwsgi_buffer_append(ub, "\" ", 2)) return; } break; // custom case 4: if (len > 0) { if (uwsgi_buffer_append(ub, "custom: \"", 9)) return; if (uwsgi_buffer_append(ub, value, len)) return; if (uwsgi_buffer_append(ub, "\" ", 2)) return; } if (uwsgi_buffer_append(ub, "\n", 1)) return; break; default: break; } } int uwsgi_exceptions_catch(struct wsgi_request *wsgi_req) { if (uwsgi_response_prepare_headers(wsgi_req, "500 Internal Server Error", 25)) { return -1; } if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) { return -1; } struct uwsgi_buffer *ub = uwsgi_buffer_new(4096); if (uwsgi_buffer_append(ub, "uWSGI exceptions catcher for \"", 30)) goto error; if (uwsgi_buffer_append(ub, wsgi_req->method, wsgi_req->method_len)) goto error; if (uwsgi_buffer_append(ub, " ", 1)) goto error; if (uwsgi_buffer_append(ub, wsgi_req->uri, wsgi_req->uri_len)) goto error; if (uwsgi_buffer_append(ub, "\" (request plugin: \"", 20)) goto error; if (uwsgi_buffer_append(ub, (char *) uwsgi.p[wsgi_req->uh->modifier1]->name, strlen(uwsgi.p[wsgi_req->uh->modifier1]->name))) goto error; if (uwsgi_buffer_append(ub, "\", modifier1: ", 14 )) goto error; if (uwsgi_buffer_num64(ub, wsgi_req->uh->modifier1)) goto error; if (uwsgi_buffer_append(ub, ")\n\n", 3)) goto error; if (uwsgi_buffer_append(ub, "Exception: ", 11)) goto error; if (uwsgi.p[wsgi_req->uh->modifier1]->exception_repr) { struct uwsgi_buffer *ub_exc_repr = uwsgi.p[wsgi_req->uh->modifier1]->exception_repr(wsgi_req); if (ub_exc_repr) { if (uwsgi_buffer_append(ub, ub_exc_repr->buf, ub_exc_repr->pos)) { uwsgi_buffer_destroy(ub_exc_repr); goto error; } uwsgi_buffer_destroy(ub_exc_repr); } else { goto notavail3; } } else { notavail3: if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error; } if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error; if (uwsgi_buffer_append(ub, "Exception class: ", 17)) goto error; if (uwsgi.p[wsgi_req->uh->modifier1]->exception_class) { struct uwsgi_buffer *ub_exc_class = uwsgi.p[wsgi_req->uh->modifier1]->exception_class(wsgi_req); if (ub_exc_class) { if (uwsgi_buffer_append(ub, ub_exc_class->buf, ub_exc_class->pos)) { uwsgi_buffer_destroy(ub_exc_class); goto error; } uwsgi_buffer_destroy(ub_exc_class); } else { goto notavail; } } else { notavail: if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error; } if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error; if (uwsgi_buffer_append(ub, "Exception message: ", 19)) goto error; if (uwsgi.p[wsgi_req->uh->modifier1]->exception_msg) { struct uwsgi_buffer *ub_exc_msg = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req); if (ub_exc_msg) { if (uwsgi_buffer_append(ub, ub_exc_msg->buf, ub_exc_msg->pos)) { uwsgi_buffer_destroy(ub_exc_msg); goto error; } uwsgi_buffer_destroy(ub_exc_msg); } else { goto notavail2; } } else { notavail2: if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error; } if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error; if (uwsgi_buffer_append(ub, "Backtrace:\n", 11)) goto error; if (uwsgi.p[wsgi_req->uh->modifier1]->backtrace) { struct uwsgi_buffer *ub_exc_bt = uwsgi.p[wsgi_req->uh->modifier1]->backtrace(wsgi_req); if (ub_exc_bt) { struct uwsgi_buffer *parsed_bt = uwsgi_buffer_new(4096); if (uwsgi_hooked_parse_array(ub_exc_bt->buf, ub_exc_bt->pos, append_backtrace_to_ubuf, parsed_bt)) { uwsgi_buffer_destroy(ub_exc_bt); uwsgi_buffer_destroy(parsed_bt); goto error; } uwsgi_buffer_destroy(ub_exc_bt); if (uwsgi_buffer_append(ub, parsed_bt->buf, parsed_bt->pos)) { uwsgi_buffer_destroy(parsed_bt); goto error; } uwsgi_buffer_destroy(parsed_bt); } else { goto notavail4; } } else { notavail4: if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error; } if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error; if (uwsgi_hooked_parse(wsgi_req->buffer, wsgi_req->uh->pktsize, append_vars_to_ubuf, ub)) { goto error; } if (uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos)) { goto error; } uwsgi_buffer_destroy(ub); return 0; error: uwsgi_buffer_destroy(ub); return -1; } static void uwsgi_exception_run_handlers(struct uwsgi_buffer *ub) { struct uwsgi_string_list *usl = uwsgi.exception_handlers_instance; struct iovec iov[2]; iov[1].iov_base = ub->buf; iov[1].iov_len = ub->pos; while(usl) { struct uwsgi_exception_handler_instance *uehi = (struct uwsgi_exception_handler_instance *) usl->custom_ptr; iov[0].iov_base = &uehi; iov[0].iov_len = sizeof(long); // now send the message to the exception handler thread if (writev(uwsgi.exception_handler_thread->pipe[0], iov, 2) != (ssize_t) (ub->pos+sizeof(long))) { uwsgi_error("[uwsgi-exception-handler-error] uwsgi_exception_run_handlers()/writev()"); } usl = usl->next; } } void uwsgi_manage_exception(struct wsgi_request *wsgi_req,int catch) { int do_exit = uwsgi.reload_on_exception; if (!wsgi_req) goto log2; if (do_exit) goto check_catch; if (uwsgi.exception_handlers_instance) { struct uwsgi_buffer *ehi = uwsgi_exception_handler_object(wsgi_req); if (ehi) { uwsgi_exception_run_handlers(ehi); uwsgi_buffer_destroy(ehi); } } uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].exceptions++; uwsgi_apps[wsgi_req->app_id].exceptions++; if (uwsgi.reload_on_exception_type && uwsgi.p[wsgi_req->uh->modifier1]->exception_class) { struct uwsgi_buffer *ub = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req); if (ub) { struct uwsgi_string_list *usl = uwsgi.reload_on_exception_type; while (usl) { if (!uwsgi_strncmp(usl->value, usl->len, ub->buf, ub->len)) { do_exit = 1; uwsgi_buffer_destroy(ub); goto check_catch; } usl = usl->next; } uwsgi_buffer_destroy(ub); } } if (uwsgi.reload_on_exception_value && uwsgi.p[wsgi_req->uh->modifier1]->exception_msg) { struct uwsgi_buffer *ub = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req); if (ub) { struct uwsgi_string_list *usl = uwsgi.reload_on_exception_value; while (usl) { if (!uwsgi_strncmp(usl->value, usl->len, ub->buf, ub->len)) { do_exit = 1; uwsgi_buffer_destroy(ub); goto check_catch; } usl = usl->next; } uwsgi_buffer_destroy(ub); } } if (uwsgi.reload_on_exception_repr && uwsgi.p[wsgi_req->uh->modifier1]->exception_repr) { struct uwsgi_buffer *ub = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req); if (ub) { struct uwsgi_string_list *usl = uwsgi.reload_on_exception_repr; while (usl) { if (!uwsgi_strncmp(usl->value, usl->len, ub->buf, ub->len)) { do_exit = 1; uwsgi_buffer_destroy(ub); goto check_catch; } usl = usl->next; } uwsgi_buffer_destroy(ub); } } check_catch: if (catch && wsgi_req) { if (uwsgi_exceptions_catch(wsgi_req)) { // for now, just goto, new features could be added goto log; } } log: if (uwsgi.p[wsgi_req->uh->modifier1]->exception_log) { uwsgi.p[wsgi_req->uh->modifier1]->exception_log(wsgi_req); } log2: if (do_exit) { exit(UWSGI_EXCEPTION_CODE); } } struct uwsgi_exception_handler *uwsgi_register_exception_handler(char *name, int (*func)(struct uwsgi_exception_handler_instance *, char *, size_t)) { struct uwsgi_exception_handler *old_ueh = NULL, *ueh = uwsgi.exception_handlers; while(ueh) { if (!strcmp(name, ueh->name)) { return NULL; } old_ueh = ueh; ueh = ueh->next; } ueh = uwsgi_calloc(sizeof(struct uwsgi_exception_handler)); ueh->name = name; ueh->func = func; if (old_ueh) { old_ueh->next = ueh; } else { uwsgi.exception_handlers = ueh; } return ueh; } struct uwsgi_exception_handler *uwsgi_exception_handler_by_name(char *name) { struct uwsgi_exception_handler *ueh = uwsgi.exception_handlers; while(ueh) { if (!strcmp(name, ueh->name)) { return ueh; } ueh = ueh->next; } return NULL; } static void uwsgi_exception_handler_thread_loop(struct uwsgi_thread *ut) { char *buf = uwsgi_malloc(uwsgi.exception_handler_msg_size + sizeof(long)); for (;;) { int interesting_fd = -1; int ret = event_queue_wait(ut->queue, -1, &interesting_fd); if (ret > 0) { ssize_t len = read(ut->pipe[1], buf, uwsgi.exception_handler_msg_size + sizeof(long)); if (len > (ssize_t)(sizeof(long) + 1)) { size_t msg_size = len - sizeof(long); char *msg = buf + sizeof(long); long ptr = 0; memcpy(&ptr, buf, sizeof(long)); struct uwsgi_exception_handler_instance *uehi = (struct uwsgi_exception_handler_instance *) ptr; if (!uehi) break; if (uehi->handler->func(uehi, msg, msg_size)) { uwsgi_log("[uwsgi-exception] error running the handler \"%s\" args: \"%s\"\n", uehi->handler->name, uehi->arg ? uehi->arg : ""); } } } } free(buf); } void uwsgi_exception_setup_handlers() { struct uwsgi_string_list *usl = uwsgi.exception_handlers_instance; while(usl) { // do not free handler !!! char *handler = uwsgi_str(usl->value); char *colon = strchr(handler, ':'); if (colon) { *colon = 0; } struct uwsgi_exception_handler *ueh = uwsgi_exception_handler_by_name(handler); if (!ueh) { uwsgi_log("unable to find exception handler: %s\n", handler); exit(1); } struct uwsgi_exception_handler_instance *uehi = uwsgi_calloc(sizeof(struct uwsgi_exception_handler_instance)); uehi->handler = ueh; if (colon) { uehi->arg = colon+1; } usl->custom_ptr = uehi; usl = usl->next; } } void uwsgi_exceptions_handler_thread_start() { if (!uwsgi.exception_handlers_instance) return; // start the exception_handler_thread uwsgi.exception_handler_thread = uwsgi_thread_new(uwsgi_exception_handler_thread_loop); if (!uwsgi.exception_handler_thread) { uwsgi_log("unable to spawn exception handler thread\n"); exit(1); } } uwsgi-2.0.29/core/fifo.c000066400000000000000000000111621477626554400150060ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; /* the --master-fifo option create a unix named pipe (fifo) you can use to send management commands to the master: echo r > myfifo */ // this var can be accessed by plugins and hooks void (*uwsgi_fifo_table[256])(int); static char *uwsgi_fifo_by_slot() { int count = 0; struct uwsgi_string_list *usl; uwsgi_foreach(usl, uwsgi.master_fifo) { if (count == uwsgi.master_fifo_slot) return usl->value; count++; } return uwsgi.master_fifo->value; } #define announce_fifo uwsgi_log_verbose("active master fifo is now %s\n", uwsgi_fifo_by_slot()) static void uwsgi_fifo_set_slot_zero(int signum) { uwsgi.master_fifo_slot = 0; announce_fifo; } static void uwsgi_fifo_set_slot_one(int signum) { uwsgi.master_fifo_slot = 1; announce_fifo; } static void uwsgi_fifo_set_slot_two(int signum) { uwsgi.master_fifo_slot = 2; announce_fifo; } static void uwsgi_fifo_set_slot_three(int signum) { uwsgi.master_fifo_slot = 3; announce_fifo; } static void uwsgi_fifo_set_slot_four(int signum) { uwsgi.master_fifo_slot = 4; announce_fifo; } static void uwsgi_fifo_set_slot_five(int signum) { uwsgi.master_fifo_slot = 5; announce_fifo; } static void uwsgi_fifo_set_slot_six(int signum) { uwsgi.master_fifo_slot = 6; announce_fifo; } static void uwsgi_fifo_set_slot_seven(int signum) { uwsgi.master_fifo_slot = 7; announce_fifo; } static void uwsgi_fifo_set_slot_eight(int signum) { uwsgi.master_fifo_slot = 8; announce_fifo; } static void uwsgi_fifo_set_slot_nine(int signum) { uwsgi.master_fifo_slot = 9; announce_fifo; } static void subscriptions_blocker(int signum) { if (uwsgi.subscriptions_blocked) { uwsgi_log_verbose("subscriptions re-enabled\n"); uwsgi.subscriptions_blocked = 0; } else { uwsgi.subscriptions_blocked = 1; uwsgi_log_verbose("subscriptions blocked\n"); } } static void emperor_rescan(int signum) { if (uwsgi.emperor_pid > 0) { if (kill(uwsgi.emperor_pid, SIGWINCH)) { uwsgi_error("emperor_rescan()/kill()"); } } } /* this is called as soon as possibile allowing plugins (or hooks) to override it */ void uwsgi_master_fifo_prepare() { int i; for(i=0;i<256;i++) { uwsgi_fifo_table[i] = NULL; } uwsgi_fifo_table['0'] = uwsgi_fifo_set_slot_zero; uwsgi_fifo_table['1'] = uwsgi_fifo_set_slot_one; uwsgi_fifo_table['2'] = uwsgi_fifo_set_slot_two; uwsgi_fifo_table['3'] = uwsgi_fifo_set_slot_three; uwsgi_fifo_table['4'] = uwsgi_fifo_set_slot_four; uwsgi_fifo_table['5'] = uwsgi_fifo_set_slot_five; uwsgi_fifo_table['6'] = uwsgi_fifo_set_slot_six; uwsgi_fifo_table['7'] = uwsgi_fifo_set_slot_seven; uwsgi_fifo_table['8'] = uwsgi_fifo_set_slot_eight; uwsgi_fifo_table['9'] = uwsgi_fifo_set_slot_nine; uwsgi_fifo_table['-'] = (void (*)(int))uwsgi_cheaper_decrease; uwsgi_fifo_table['+'] = (void (*)(int))uwsgi_cheaper_increase; uwsgi_fifo_table['B'] = (void (*)(int))vassal_sos; uwsgi_fifo_table['c'] = (void (*)(int))uwsgi_chain_reload; uwsgi_fifo_table['C'] = (void (*)(int))uwsgi_go_cheap; uwsgi_fifo_table['E'] = emperor_rescan; uwsgi_fifo_table['f'] = (void (*)(int))uwsgi_refork_master; uwsgi_fifo_table['l'] = (void (*)(int))uwsgi_log_reopen; uwsgi_fifo_table['L'] = (void (*)(int))uwsgi_log_rotate; uwsgi_fifo_table['p'] = suspend_resume_them_all; uwsgi_fifo_table['P'] = (void (*)(int))uwsgi_update_pidfiles; uwsgi_fifo_table['q'] = gracefully_kill_them_all; uwsgi_fifo_table['Q'] = kill_them_all; uwsgi_fifo_table['r'] = grace_them_all; uwsgi_fifo_table['R'] = reap_them_all; uwsgi_fifo_table['s'] = stats; uwsgi_fifo_table['S'] = subscriptions_blocker; uwsgi_fifo_table['w'] = (void (*)(int))uwsgi_reload_workers; uwsgi_fifo_table['W'] = (void (*)(int))uwsgi_brutally_reload_workers; } int uwsgi_master_fifo() { char *path = uwsgi_fifo_by_slot(); if (unlink(path) != 0 && errno != ENOENT) { uwsgi_error("uwsgi_master_fifo()/unlink()"); } if (mkfifo(path, S_IRUSR|S_IWUSR)) { uwsgi_error("uwsgi_master_fifo()/mkfifo()"); exit(1); } int fd = open(path, O_RDONLY|O_NONBLOCK); if (fd < 0) { uwsgi_error("uwsgi_master_fifo()/open()"); exit(1); } uwsgi_socket_nb(fd); return fd; } int uwsgi_master_fifo_manage(int fd) { unsigned char cmd; ssize_t rlen = read(fd, &cmd, 1); if (rlen < 0) { if (uwsgi_is_again()) return 0; uwsgi_error("uwsgi_master_fifo_manage()/read()"); exit(1); } // fifo destroyed, recreate it else if (rlen == 0) { event_queue_del_fd(uwsgi.master_queue, uwsgi.master_fifo_fd, event_queue_read()); close(fd); uwsgi.master_fifo_fd = uwsgi_master_fifo(); event_queue_add_fd_read(uwsgi.master_queue, uwsgi.master_fifo_fd); return 0; } if (uwsgi_fifo_table[(int) cmd]) { uwsgi_fifo_table[(int) cmd](0); } return 0; } uwsgi-2.0.29/core/fsmon.c000066400000000000000000000105131477626554400152040ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; #ifdef UWSGI_EVENT_FILEMONITOR_USE_INOTIFY #ifndef OBSOLETE_LINUX_KERNEL #include #endif #endif static int fsmon_add(struct uwsgi_fsmon *fs) { #ifdef UWSGI_EVENT_FILEMONITOR_USE_INOTIFY #ifndef OBSOLETE_LINUX_KERNEL static int inotify_fd = -1; if (inotify_fd == -1) { inotify_fd = inotify_init(); if (inotify_fd < 0) { uwsgi_error("fsmon_add()/inotify_init()"); return -1; } if (event_queue_add_fd_read(uwsgi.master_queue, inotify_fd)) { uwsgi_error("fsmon_add()/event_queue_add_fd_read()"); return -1; } } int wd = inotify_add_watch(inotify_fd, fs->path, IN_ATTRIB | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_MOVED_FROM | IN_MOVED_TO); if (wd < 0) { uwsgi_error("fsmon_add()/inotify_add_watch()"); return -1; } fs->fd = inotify_fd; fs->id = wd; return 0; #endif #endif #ifdef UWSGI_EVENT_FILEMONITOR_USE_KQUEUE struct kevent kev; int fd = open(fs->path, O_RDONLY); if (fd < 0) { uwsgi_error_open(fs->path); uwsgi_error("fsmon_add()/open()"); return -1; } EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE | NOTE_DELETE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE, 0, 0); if (kevent(uwsgi.master_queue, &kev, 1, NULL, 0, NULL) < 0) { uwsgi_error("fsmon_add()/kevent()"); return -1; } fs->fd = fd; return 0; #endif uwsgi_log("[uwsgi-fsmon] filesystem monitoring interface not available in this platform !!!\n"); return 1; } static void fsmon_reload(struct uwsgi_fsmon *fs) { uwsgi_block_signal(SIGHUP); grace_them_all(0); uwsgi_unblock_signal(SIGHUP); } static void fsmon_brutal_reload(struct uwsgi_fsmon *fs) { if (uwsgi.die_on_term) { uwsgi_block_signal(SIGQUIT); reap_them_all(0); uwsgi_unblock_signal(SIGQUIT); } else { uwsgi_block_signal(SIGTERM); reap_them_all(0); uwsgi_unblock_signal(SIGTERM); } } static void fsmon_signal(struct uwsgi_fsmon *fs) { uwsgi_route_signal(atoi((char *) fs->data)); } void uwsgi_fsmon_setup() { struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, uwsgi.fs_reload) { uwsgi_register_fsmon(usl->value, fsmon_reload, NULL); } uwsgi_foreach(usl, uwsgi.fs_brutal_reload) { uwsgi_register_fsmon(usl->value, fsmon_brutal_reload, NULL); } uwsgi_foreach(usl, uwsgi.fs_signal) { char *copy = uwsgi_str(usl->value); char *space = strchr(copy, ' '); if (!space) { uwsgi_log("[uwsgi-fsmon] invalid syntax: \"%s\"\n", usl->value); free(copy); continue; } *space = 0; uwsgi_register_fsmon(copy, fsmon_signal, space + 1); } struct uwsgi_fsmon *fs = uwsgi.fsmon; while (fs) { if (fsmon_add(fs)) { uwsgi_log("[uwsgi-fsmon] unable to register monitor for \"%s\"\n", fs->path); } else { uwsgi_log("[uwsgi-fsmon] registered monitor for \"%s\"\n", fs->path); } fs = fs->next; } } struct uwsgi_fsmon *uwsgi_register_fsmon(char *path, void (*func) (struct uwsgi_fsmon *), void *data) { struct uwsgi_fsmon *old_fs = NULL, *fs = uwsgi.fsmon; while(fs) { old_fs = fs; fs = fs->next; } fs = uwsgi_calloc(sizeof(struct uwsgi_fsmon)); fs->path = path; fs->func = func; fs->data = data; if (old_fs) { old_fs->next = fs; } else { uwsgi.fsmon = fs; } return fs; } static struct uwsgi_fsmon *uwsgi_fsmon_ack(int interesting_fd) { struct uwsgi_fsmon *found_fs = NULL; struct uwsgi_fsmon *fs = uwsgi.fsmon; while (fs) { if (fs->fd == interesting_fd) { found_fs = fs; break; } fs = fs->next; } #ifdef UWSGI_EVENT_FILEMONITOR_USE_INOTIFY #ifndef OBSOLETE_LINUX_KERNEL if (!found_fs) return NULL; found_fs = NULL; unsigned int isize = 0; if (ioctl(interesting_fd, FIONREAD, &isize) < 0) { uwsgi_error("uwsgi_fsmon_ack()/ioctl()"); return NULL; } if (isize == 0) return NULL; struct inotify_event *ie = uwsgi_malloc(isize); // read from the inotify descriptor ssize_t len = read(interesting_fd, ie, isize); if (len < 0) { free(ie); uwsgi_error("uwsgi_fsmon_ack()/read()"); return NULL; } fs = uwsgi.fsmon; while (fs) { if (fs->fd == interesting_fd && fs->id == ie->wd) { found_fs = fs; break; } fs = fs->next; } free(ie); #endif #endif return found_fs; } int uwsgi_fsmon_event(int interesting_fd) { struct uwsgi_fsmon *fs = uwsgi_fsmon_ack(interesting_fd); if (!fs) return 0; uwsgi_log_verbose("[uwsgi-fsmon] detected event on \"%s\"\n", fs->path); fs->func(fs); return 1; } uwsgi-2.0.29/core/gateway.c000066400000000000000000000111621477626554400155240ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; struct uwsgi_gateway *register_gateway(char *name, void (*loop) (int, void *), void *data) { struct uwsgi_gateway *ug; int num = 1, i; if (ushared->gateways_cnt >= MAX_GATEWAYS) { uwsgi_log("you can register max %d gateways\n", MAX_GATEWAYS); return NULL; } for (i = 0; i < ushared->gateways_cnt; i++) { if (!strcmp(name, ushared->gateways[i].name)) { num++; } } char *str = uwsgi_num2str(num); char *fullname = uwsgi_concat3(name, " ", str); free(str); ug = &ushared->gateways[ushared->gateways_cnt]; ug->pid = 0; ug->name = name; ug->loop = loop; ug->num = num; ug->fullname = fullname; ug->data = data; ug->uid = 0; ug->gid = 0; #if defined(SOCK_SEQPACKET) && defined(__linux__) if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, ug->internal_subscription_pipe)) { #else if (socketpair(AF_UNIX, SOCK_DGRAM, 0, ug->internal_subscription_pipe)) { #endif uwsgi_error("socketpair()"); } uwsgi_socket_nb(ug->internal_subscription_pipe[0]); uwsgi_socket_nb(ug->internal_subscription_pipe[1]); if (!uwsgi.master_process && !uwsgi.force_gateway) gateway_respawn(ushared->gateways_cnt); ushared->gateways_cnt++; return ug; } static void gateway_brutal_end() { _exit(UWSGI_END_CODE); } void gateway_respawn(int id) { pid_t gw_pid; struct uwsgi_gateway *ug = &ushared->gateways[id]; if (uwsgi.master_process) uwsgi.shared->gateways_harakiri[id] = 0; gw_pid = uwsgi_fork(ug->fullname); if (gw_pid < 0) { uwsgi_error("fork()"); return; } if (gw_pid == 0) { uwsgi_fixup_fds(0, 0, ug); uwsgi_close_all_unshared_sockets(); if (uwsgi.master_as_root) uwsgi_as_root(); #ifdef __linux__ if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) { uwsgi_error("prctl()"); } #endif uwsgi.mypid = getpid(); atexit(gateway_brutal_end); signal(SIGALRM, SIG_IGN); signal(SIGHUP, SIG_IGN); signal(SIGINT, end_me); signal(SIGTERM, end_me); signal(SIGUSR1, SIG_IGN); signal(SIGUSR2, SIG_IGN); signal(SIGPIPE, SIG_IGN); signal(SIGSTOP, SIG_IGN); signal(SIGTSTP, SIG_IGN); uwsgi_hooks_run(uwsgi.hook_as_gateway, "as-gateway", 1); if (ug->gid) { uwsgi_log("%s %d setgid() to %d\n", ug->name, ug->num, (int) ug->gid); if (setgid(ug->gid)) { uwsgi_error("gateway_respawn()/setgid()"); exit(1); } } if (ug->uid) { uwsgi_log("%s %d setuid() to %d\n", ug->name, ug->num, (int) ug->uid); if (setuid(ug->uid)) { uwsgi_error("gateway_respawn()/setuid()"); exit(1); } } ug->loop(id, ug->data); // never here !!! (i hope) exit(1); } ug->pid = gw_pid; ug->respawns++; if (ug->respawns == 1) { uwsgi_log("spawned %s %d (pid: %d)\n", ug->name, ug->num, (int) gw_pid); } else { uwsgi_log("respawned %s %d (pid: %d)\n", ug->name, ug->num, (int) gw_pid); } } struct uwsgi_gateway_socket *uwsgi_new_gateway_socket(char *name, char *owner) { struct uwsgi_gateway_socket *uwsgi_sock = uwsgi.gateway_sockets, *old_uwsgi_sock; if (!uwsgi_sock) { uwsgi.gateway_sockets = uwsgi_malloc(sizeof(struct uwsgi_gateway_socket)); uwsgi_sock = uwsgi.gateway_sockets; } else { while (uwsgi_sock) { old_uwsgi_sock = uwsgi_sock; uwsgi_sock = uwsgi_sock->next; } uwsgi_sock = uwsgi_malloc(sizeof(struct uwsgi_gateway_socket)); old_uwsgi_sock->next = uwsgi_sock; } memset(uwsgi_sock, 0, sizeof(struct uwsgi_gateway_socket)); uwsgi_sock->fd = -1; uwsgi_sock->shared = 0; uwsgi_sock->name = name; uwsgi_sock->name_len = strlen(name); uwsgi_sock->owner = owner; return uwsgi_sock; } struct uwsgi_gateway_socket *uwsgi_new_gateway_socket_from_fd(int fd, char *owner) { struct uwsgi_gateway_socket *uwsgi_sock = uwsgi.gateway_sockets, *old_uwsgi_sock; if (!uwsgi_sock) { uwsgi.gateway_sockets = uwsgi_malloc(sizeof(struct uwsgi_gateway_socket)); uwsgi_sock = uwsgi.gateway_sockets; } else { while (uwsgi_sock) { old_uwsgi_sock = uwsgi_sock; uwsgi_sock = uwsgi_sock->next; } uwsgi_sock = uwsgi_malloc(sizeof(struct uwsgi_gateway_socket)); old_uwsgi_sock->next = uwsgi_sock; } memset(uwsgi_sock, 0, sizeof(struct uwsgi_gateway_socket)); uwsgi_sock->fd = fd; uwsgi_sock->name = uwsgi_getsockname(fd); uwsgi_sock->name_len = strlen(uwsgi_sock->name); uwsgi_sock->owner = owner; return uwsgi_sock; } void uwsgi_gateway_go_cheap(char *gw_id, int queue, int *i_am_cheap) { uwsgi_log("[%s pid %d] no more nodes available. Going cheap...\n", gw_id, (int) uwsgi.mypid); struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets; while (ugs) { if (!strcmp(ugs->owner, gw_id) && !ugs->subscription) { event_queue_del_fd(queue, ugs->fd, event_queue_read()); } ugs = ugs->next; } *i_am_cheap = 1; } uwsgi-2.0.29/core/hash.c000066400000000000000000000045471477626554400150170ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; // Bernstein classic hash (this is not static as it is used by other areas) uint32_t djb33x_hash(char *key, uint64_t keylen) { register uint32_t hash = 5381; uint64_t i; for (i = 0; i < keylen; i++) { hash = ((hash << 5) + hash) ^ key[i]; } return hash; } // Murmur2 hash Copyright (C) Austin Appleby // adapted from nginx static uint32_t murmur2_hash(char *key, uint64_t keylen) { uint32_t h, k; uint8_t *ukey = (uint8_t *) key; h = 0 ^ keylen; while (keylen >= 4) { k = ukey[0]; k |= ukey[1] << 8; k |= ukey[2] << 16; k |= ukey[3] << 24; k *= 0x5bd1e995; k ^= k >> 24; k *= 0x5bd1e995; h *= 0x5bd1e995; h ^= k; ukey += 4; keylen -= 4; } switch (keylen) { case 3: h ^= key[2] << 16; /* fallthrough */ case 2: h ^= key[1] << 8; /* fallthrough */ case 1: h ^= key[0]; h *= 0x5bd1e995; } h ^= h >> 13; h *= 0x5bd1e995; h ^= h >> 15; return h; } static uint32_t random_hash(char *key, uint64_t keylen) { return (uint32_t) rand(); } /* not atomic, avoid its use in multithreaded modes */ static uint32_t rr_hash(char *key, uint64_t keylen) { static uint32_t rr = 0; uint32_t max_value = uwsgi_str_num(key, keylen); uint32_t ret = rr; rr++; if (rr > max_value) { rr = 0; } return ret; } struct uwsgi_hash_algo *uwsgi_hash_algo_get(char *name) { struct uwsgi_hash_algo *uha = uwsgi.hash_algos; while(uha) { if (!strcmp(name, uha->name)) { return uha; } uha = uha->next; } return NULL; } void uwsgi_hash_algo_register(char *name, uint32_t (*func)(char *, uint64_t)) { struct uwsgi_hash_algo *old_uha = NULL, *uha = uwsgi.hash_algos; while(uha) { if (!strcmp(uha->name, name)) return; old_uha = uha; uha = uha->next; } uha = uwsgi_calloc(sizeof(struct uwsgi_hash_algo)); uha->name = name; uha->func = func; if (old_uha) { old_uha->next = uha; } else { uwsgi.hash_algos = uha; } } void uwsgi_hash_algo_register_all() { uwsgi_hash_algo_register("djb33x", djb33x_hash); uwsgi_hash_algo_register("murmur2", murmur2_hash); uwsgi_hash_algo_register("random", random_hash); uwsgi_hash_algo_register("rand", random_hash); uwsgi_hash_algo_register("rr", rr_hash); } uwsgi-2.0.29/core/hooks.c000066400000000000000000000443101477626554400152070ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; /* advanced (pluggable) hooks they are executed before the other hooks, and can be extended by plugins if a plugin tries to register an hook with a name already available in the list, its function will be overridden */ struct uwsgi_hook *uwsgi_hook_by_name(char *name) { struct uwsgi_hook *uh = uwsgi.hooks; while(uh) { if (!strcmp(uh->name, name)) { return uh; } uh = uh->next; } return NULL; } void uwsgi_register_hook(char *name, int (*func)(char *)) { struct uwsgi_hook *old_uh = NULL, *uh = uwsgi.hooks; while(uh) { if (!strcmp(uh->name, name)) { uh->func = func; return; } old_uh = uh; uh = uh->next; } uh = uwsgi_calloc(sizeof(struct uwsgi_hook)); uh->name = name; uh->func = func; if (old_uh) { old_uh->next = uh; } else { uwsgi.hooks = uh; } } static int uwsgi_hook_alarm(char *arg) { char *space = strchr(arg,' '); if (!space) { uwsgi_log("invalid alarm hook syntax, must be: \n"); return -1; } *space = 0; uwsgi_alarm_trigger(arg, space+1, strlen(space+1)); *space = ' '; return 0; } static int uwsgi_hook_chdir(char *arg) { int ret = chdir(arg); if (ret) { uwsgi_error("uwsgi_hook_chdir()"); } return ret; } static int uwsgi_hook_mkdir(char *arg) { int ret = mkdir(arg, 0777); if (ret) { uwsgi_error("uwsgi_hook_mkdir()"); } return ret; } static int uwsgi_hook_putenv(char *arg) { int ret = putenv(arg); if (ret) { uwsgi_error("uwsgi_hook_putenv()"); } return ret; } static int uwsgi_hook_exec(char *arg) { int ret = uwsgi_run_command_and_wait(NULL, arg); if (ret != 0) { uwsgi_log("command \"%s\" exited with non-zero code: %d\n", arg, ret); } return ret; } static int uwsgi_hook_safeexec(char *arg) { int ret = uwsgi_run_command_and_wait(NULL, arg); if (ret != 0) { uwsgi_log("command \"%s\" exited with non-zero code: %d\n", arg, ret); } return 0; } static int uwsgi_hook_exit(char *arg) { int exit_code = 0; if (strlen(arg) > 1) { exit_code = atoi(arg); } exit(exit_code); } static int uwsgi_hook_print(char *arg) { char *line = uwsgi_concat2(arg, "\n"); uwsgi_log(line); free(line); return 0; } static int uwsgi_hook_unlink(char *arg) { int ret = unlink(arg); if (ret) { uwsgi_error("uwsgi_hook_unlink()/unlink()"); } return ret; } static int uwsgi_hook_writefifo(char *arg) { char *space = strchr(arg, ' '); if (!space) { uwsgi_log("invalid hook writefifo syntax, must be: \n"); return -1; } *space = 0; int fd = open(arg, O_WRONLY|O_NONBLOCK); if (fd < 0) { uwsgi_error_open(arg); *space = ' '; if (errno == ENODEV) return 0; #ifdef ENXIO if (errno == ENXIO) return 0; #endif return -1; } *space = ' '; size_t l = strlen(space+1); if (write(fd, space+1, l) != (ssize_t) l) { uwsgi_error("uwsgi_hook_writefifo()/write()"); close(fd); return -1; } close(fd); return 0; } static int uwsgi_hook_write(char *arg) { char *space = strchr(arg, ' '); if (!space) { uwsgi_log("invalid hook write syntax, must be: \n"); return -1; } *space = 0; int fd = open(arg, O_WRONLY|O_CREAT|O_TRUNC, 0666); if (fd < 0) { uwsgi_error_open(arg); *space = ' '; return -1; } *space = ' '; size_t l = strlen(space+1); if (write(fd, space+1, l) != (ssize_t) l) { uwsgi_error("uwsgi_hook_write()/write()"); close(fd); return -1; } close(fd); return 0; } static int uwsgi_hook_creat(char *arg) { int fd = open(arg, O_WRONLY|O_CREAT|O_TRUNC, 0666); if (fd < 0) { uwsgi_error_open(arg); return -1; } close(fd); return 0; } static int uwsgi_hook_append(char *arg) { char *space = strchr(arg, ' '); if (!space) { uwsgi_log("invalid hook append syntax, must be: \n"); return -1; } *space = 0; int fd = open(arg, O_WRONLY|O_CREAT|O_APPEND, 0666); if (fd < 0) { uwsgi_error_open(arg); *space = ' '; return -1; } *space = ' '; size_t l = strlen(space+1); if (write(fd, space+1, l) != (ssize_t) l) { uwsgi_error("uwsgi_hook_append()/write()"); close(fd); return -1; } close(fd); return 0; } static int uwsgi_hook_writen(char *arg) { char *space = strchr(arg, ' '); if (!space) { uwsgi_log("invalid hook writen syntax, must be: \n"); return -1; } *space = 0; int fd = open(arg, O_WRONLY|O_CREAT|O_TRUNC, 0666); if (fd < 0) { uwsgi_error_open(arg); *space = ' '; return -1; } *space = ' '; size_t l = strlen(space+1); char *buf = uwsgi_malloc(l + 1); memcpy(buf, space+1, l); buf[l] = '\n'; if (write(fd, buf, l+1) != (ssize_t) (l+1)) { uwsgi_error("uwsgi_hook_writen()/write()"); free(buf); close(fd); return -1; } free(buf); close(fd); return 0; } static int uwsgi_hook_appendn(char *arg) { char *space = strchr(arg, ' '); if (space) *space = 0; int fd = open(arg, O_WRONLY|O_CREAT|O_APPEND, 0666); if (fd < 0) { uwsgi_error_open(arg); if (space) *space = ' '; return -1; } if (!space) { // simple newline if (write(fd, "\n", 1) != 1) { uwsgi_error("uwsgi_hook_appendn()/write()"); close(fd); return -1; } close(fd); return 0; } *space = ' '; size_t l = strlen(space+1); char *buf = uwsgi_malloc(l + 1); memcpy(buf, space+1, l); buf[l] = '\n'; if (write(fd, buf, l+1) != (ssize_t) (l+1)) { uwsgi_error("uwsgi_hook_appendn()/write()"); free(buf); close(fd); return -1; } free(buf); close(fd); return 0; } static int uwsgi_hook_chmod(char *arg) { char *space = strchr(arg, ' '); if (!space) { uwsgi_log("invalid hook chmod syntax, must be: \n"); return -1; } *space = 0; int error = 0; mode_t mask = uwsgi_mode_t(space+1, &error); if (error) { uwsgi_log("invalid hook chmod mask: %s\n", space+1); *space = ' '; return -1; } int ret = chmod(arg, mask); *space = ' '; if (ret) { uwsgi_error("uwsgi_hook_chmod()/chmod()"); } return ret; } static int uwsgi_hook_sticky(char *arg) { struct stat st; if (stat(arg, &st)) { uwsgi_error("uwsgi_hook_sticky()/stat()"); return -1; } if (chmod(arg, st.st_mode | S_ISVTX)) { uwsgi_error("uwsgi_hook_sticky()/chmod()"); return -1; } return 0; } static int uwsgi_hook_chown(char *arg) { char *space = strchr(arg, ' '); if (!space) { uwsgi_log("invalid hook chown syntax, must be: \n"); return -1; } *space = 0; char *space2 = strchr(space+1, ' '); if (!space2) { *space = ' '; uwsgi_log("invalid hook chown syntax, must be: \n"); return -1; } *space2 = 0; struct passwd *pw = getpwnam(space+1); if (!pw) { uwsgi_log("unable to find uid %s\n", space+1); *space = ' '; *space2 = ' '; return -1; } struct group *gr = getgrnam(space2+1); if (!gr) { uwsgi_log("unable to find gid %s\n", space2+1); *space = ' '; *space2 = ' '; return -1; } int ret = chown(arg, pw->pw_uid, gr->gr_gid); *space = ' '; *space2 = ' '; if (ret) { uwsgi_error("uwsgi_hook_chown()/chown)"); } return ret; } static int uwsgi_hook_chown2(char *arg) { char *space = strchr(arg, ' '); if (!space) { uwsgi_log("invalid hook chown2 syntax, must be: \n"); return -1; } *space = 0; char *space2 = strchr(space+1, ' '); if (!space2) { *space = ' '; uwsgi_log("invalid hook chown2 syntax, must be: \n"); return -1; } *space2 = 0; if (!is_a_number(space+1)) { uwsgi_log("invalid hook chown2 syntax, uid must be a number\n"); *space = ' '; *space2 = ' '; return -1; } if (!is_a_number(space2+1)) { uwsgi_log("invalid hook chown2 syntax, gid must be a number\n"); *space = ' '; *space2 = ' '; return -1; } int ret = chown(arg, atoi(space+1), atoi(space2+1)); *space = ' '; *space2 = ' '; if (ret) { uwsgi_error("uwsgi_hook_chown2()/chown)"); } return ret; } #ifdef __sun__ extern int sethostname(char *, int); #endif static int uwsgi_hook_hostname(char *arg) { #ifdef __CYGWIN__ return -1; #else return sethostname(arg, strlen(arg)); #endif } static int uwsgi_hook_unix_signal(char *arg) { char *space = strchr(arg, ' '); if (!space) { uwsgi_log("invalid unix_signal syntax, must be \n"); return -1; } *space = 0; int signum = atoi(arg); *space = ' '; void (*func)(int) = dlsym(RTLD_DEFAULT, space+1); if (!func) { uwsgi_log("unable to find function \"%s\"\n", space+1); return -1; } uwsgi_unix_signal(signum, func); return 0; } static int uwsgi_hook_callint(char *arg) { char *space = strchr(arg, ' '); if (space) { *space = 0; int num = atoi(space+1); void (*func)(int) = dlsym(RTLD_DEFAULT, arg); if (!func) { uwsgi_log("unable to call function \"%s(%d)\"\n", arg, num); *space = ' '; return -1; } *space = ' '; func(num); } else { void (*func)(void) = dlsym(RTLD_DEFAULT, arg); if (!func) { uwsgi_log("unable to call function \"%s\"\n", arg); return -1; } func(); } return 0; } static int uwsgi_hook_call(char *arg) { char *space = strchr(arg, ' '); if (space) { *space = 0; void (*func)(char *) = dlsym(RTLD_DEFAULT, arg); if (!func) { uwsgi_log("unable to call function \"%s(%s)\"\n", arg, space + 1); *space = ' '; return -1; } *space = ' '; func(space + 1); } else { void (*func)(void) = dlsym(RTLD_DEFAULT, arg); if (!func) { uwsgi_log("unable to call function \"%s\"\n", arg); return -1; } func(); } return 0; } static int uwsgi_hook_callintret(char *arg) { char *space = strchr(arg, ' '); if (space) { *space = 0; int num = atoi(space+1); int (*func)(int) = dlsym(RTLD_DEFAULT, arg); if (!func) { uwsgi_log("unable to call function \"%s(%d)\"\n", arg, num); *space = ' '; return -1; } *space = ' '; return func(num); } int (*func)(void) = dlsym(RTLD_DEFAULT, arg); if (!func) { uwsgi_log("unable to call function \"%s\"\n", arg); return -1; } return func(); } static int uwsgi_hook_callret(char *arg) { char *space = strchr(arg, ' '); if (space) { *space = 0; int (*func)(char *) = dlsym(RTLD_DEFAULT, arg); if (!func) { uwsgi_log("unable to call function \"%s(%s)\"\n", arg, space + 1); *space = ' '; return -1; } *space = ' '; return func(space + 1); } int (*func)(void) = dlsym(RTLD_DEFAULT, arg); if (!func) { uwsgi_log("unable to call function \"%s\"\n", arg); return -1; } return func(); } static int uwsgi_hook_rpc(char *arg) { int ret = -1; size_t i, argc = 0; char **rargv = uwsgi_split_quoted(arg, strlen(arg), " \t", &argc); if (!argc) goto end; if (argc > 256) goto destroy; char *argv[256]; uint16_t argvs[256]; char *node = NULL; char *func = rargv[0]; char *at = strchr(func, '@'); if (at) { *at = 0; node = at + 1; } for(i=0;i<(argc-1);i++) { size_t a_len = strlen(rargv[i+1]); if (a_len > 0xffff) goto destroy; argv[i] = rargv[i+1] ; argvs[i] = a_len; } uint64_t size = 0; // response must be always freed char *response = uwsgi_do_rpc(node, func, argc-1, argv, argvs, &size); if (response) { if (at) *at = '@'; uwsgi_log("[rpc result from \"%s\"] %.*s\n", rargv[0], size, response); free(response); ret = 0; } destroy: for(i=0;i \n"); return -1; } *space = 0; retry: uwsgi_log("waiting for %s ...\n", arg); fd = open(arg, O_WRONLY|O_NONBLOCK); if (fd < 0) { if (errno == ENODEV || errno == ENOENT) { sleep(1); goto retry; } #ifdef ENXIO if (errno == ENXIO) { sleep(1); goto retry; } #endif uwsgi_error_open(arg); *space = ' '; return -1; } *space = ' '; size_t l = strlen(space+1); if (write(fd, space+1, l) != (ssize_t) l) { uwsgi_error("spinningfifo_hook()/write()"); close(fd); return -1; } close(fd); return 0; } void uwsgi_register_base_hooks() { uwsgi_register_hook("cd", uwsgi_hook_chdir); uwsgi_register_hook("chdir", uwsgi_hook_chdir); uwsgi_register_hook("mkdir", uwsgi_hook_mkdir); uwsgi_register_hook("putenv", uwsgi_hook_putenv); uwsgi_register_hook("chmod", uwsgi_hook_chmod); uwsgi_register_hook("chown", uwsgi_hook_chown); uwsgi_register_hook("chown2", uwsgi_hook_chown2); uwsgi_register_hook("sticky", uwsgi_hook_sticky); uwsgi_register_hook("exec", uwsgi_hook_exec); uwsgi_register_hook("safeexec", uwsgi_hook_safeexec); uwsgi_register_hook("create", uwsgi_hook_creat); uwsgi_register_hook("creat", uwsgi_hook_creat); uwsgi_register_hook("write", uwsgi_hook_write); uwsgi_register_hook("writen", uwsgi_hook_writen); uwsgi_register_hook("append", uwsgi_hook_append); uwsgi_register_hook("appendn", uwsgi_hook_appendn); uwsgi_register_hook("writefifo", uwsgi_hook_writefifo); uwsgi_register_hook("unlink", uwsgi_hook_unlink); uwsgi_register_hook("mount", uwsgi_mount_hook); uwsgi_register_hook("umount", uwsgi_umount_hook); uwsgi_register_hook("call", uwsgi_hook_call); uwsgi_register_hook("callret", uwsgi_hook_callret); uwsgi_register_hook("callint", uwsgi_hook_callint); uwsgi_register_hook("callintret", uwsgi_hook_callintret); uwsgi_register_hook("hostname", uwsgi_hook_hostname); uwsgi_register_hook("alarm", uwsgi_hook_alarm); uwsgi_register_hook("rpc", uwsgi_hook_rpc); uwsgi_register_hook("retryrpc", uwsgi_hook_retryrpc); uwsgi_register_hook("wait_for_fs", uwsgi_hook_wait_for_fs); uwsgi_register_hook("wait_for_file", uwsgi_hook_wait_for_file); uwsgi_register_hook("wait_for_dir", uwsgi_hook_wait_for_dir); uwsgi_register_hook("wait_for_socket", uwsgi_hook_wait_for_socket); uwsgi_register_hook("unix_signal", uwsgi_hook_unix_signal); uwsgi_register_hook("spinningfifo", spinningfifo_hook); // for testing uwsgi_register_hook("exit", uwsgi_hook_exit); uwsgi_register_hook("print", uwsgi_hook_print); uwsgi_register_hook("log", uwsgi_hook_print); } void uwsgi_hooks_run(struct uwsgi_string_list *l, char *phase, int fatal) { struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, l) { char *colon = strchr(usl->value, ':'); if (!colon) { uwsgi_log("invalid hook syntax, must be hook:args\n"); exit(1); } *colon = 0; int private = 0; char *action = usl->value; // private hook ? if (action[0] == '!') { action++; private = 1; } struct uwsgi_hook *uh = uwsgi_hook_by_name(action); if (!uh) { uwsgi_log("hook action not found: %s\n", action); exit(1); } *colon = ':'; if (private) { uwsgi_log("running --- PRIVATE HOOK --- (%s)...\n", phase); } else { uwsgi_log("running \"%s\" (%s)...\n", usl->value, phase); } int ret = uh->func(colon+1); if (fatal && ret != 0) { uwsgi_log_verbose("FATAL hook failed, destroying instance\n"); if (uwsgi.master_process) { if (uwsgi.workers) { if (uwsgi.workers[0].pid == getpid()) { kill_them_all(0); return; } else { if (kill(uwsgi.workers[0].pid, SIGINT)) { uwsgi_error("uwsgi_hooks_run()/kill()"); exit(1); } return; } } } exit(1); } } } uwsgi-2.0.29/core/ini.c000066400000000000000000000053501477626554400146440ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; /* ini file must be read ALL into memory. This memory must not be freed for all the server lifecycle */ static char *last_file = NULL; void ini_rstrip(char *line) { off_t i; for (i = strlen(line) - 1; i >= 0; i--) { if (line[i] == ' ' || line[i] == '\t' || line[i] == '\r') { line[i] = 0; continue; } break; } } char *ini_lstrip(char *line) { off_t i; char *ptr = line; for (i = 0; i < (int) strlen(line); i++) { if (line[i] == ' ' || line[i] == '\t' || line[i] == '\r') { ptr++; continue; } break; } return ptr; } char *ini_get_key(char *key) { off_t i; char *ptr = key; for (i = 0; i < (int) strlen(key); i++) { ptr++; if (key[i] == '=') { key[i] = 0; return ptr; } } return ptr; } char *ini_get_line(char *ini, size_t size) { size_t i; char *ptr = ini; for (i = 0; i < size; i++) { ptr++; if (ini[i] == '\n') { ini[i] = 0; return ptr; } } // check if it is a stupid file without \n at the end if (ptr > ini) { return ptr; } return NULL; } void uwsgi_ini_config(char *file, char *magic_table[]) { size_t len = 0; char *ini; char *ini_line; char *section = ""; char *key; char *val; char *section_asked = "uwsgi"; char *colon; int got_section = 0; if (uwsgi_check_scheme(file)) { colon = uwsgi_get_last_char(file, '/'); colon = uwsgi_get_last_char(colon, ':'); } else { colon = uwsgi_get_last_char(file, ':'); } if (colon) { colon[0] = 0; if (colon[1] != 0) { section_asked = colon + 1; } if (colon == file) { file = last_file; } } if (file[0] != 0 && file != last_file) { uwsgi_log_initial("[uWSGI] getting INI configuration from %s\n", file); } ini = uwsgi_open_and_read(file, &len, 1, magic_table); if (file != last_file) { if (last_file) { free(last_file); } last_file = uwsgi_str(file); } while (len) { ini_line = ini_get_line(ini, len); if (ini_line == NULL) { break; } // skip empty line key = ini_lstrip(ini); ini_rstrip(key); if (key[0] != 0) { if (key[0] == '[') { section = key + 1; section[strlen(section) - 1] = 0; } else if (key[0] == ';' || key[0] == '#') { // this is a comment } else { // val is always valid, but (obviously) can be ignored val = ini_get_key(key); if (!strcmp(section, section_asked)) { got_section = 1; ini_rstrip(key); val = ini_lstrip(val); ini_rstrip(val); add_exported_option((char *) key, val, 0); } } } len -= (ini_line - ini); ini += (ini_line - ini); } if (!got_section) { uwsgi_log("*** WARNING: Can't find section \"%s\" in INI configuration file %s ***\n", section_asked, file); } if (colon) { colon[0] = ':'; } } uwsgi-2.0.29/core/init.c000066400000000000000000000346761477626554400150450ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; struct http_status_codes { const char key[4]; const char *message; int message_size; }; /* statistically ordered */ struct http_status_codes hsc[] = { {"200", "OK"}, {"302", "Found"}, {"404", "Not Found"}, {"500", "Internal Server Error"}, {"301", "Moved Permanently"}, {"304", "Not Modified"}, {"303", "See Other"}, {"403", "Forbidden"}, {"307", "Temporary Redirect"}, {"401", "Unauthorized"}, {"400", "Bad Request"}, {"405", "Method Not Allowed"}, {"408", "Request Timeout"}, {"100", "Continue"}, {"101", "Switching Protocols"}, {"201", "Created"}, {"202", "Accepted"}, {"203", "Non-Authoritative Information"}, {"204", "No Content"}, {"205", "Reset Content"}, {"206", "Partial Content"}, {"300", "Multiple Choices"}, {"305", "Use Proxy"}, {"402", "Payment Required"}, {"406", "Not Acceptable"}, {"407", "Proxy Authentication Required"}, {"409", "Conflict"}, {"410", "Gone"}, {"411", "Length Required"}, {"412", "Precondition Failed"}, {"413", "Request Entity Too Large"}, {"414", "Request-URI Too Long"}, {"415", "Unsupported Media Type"}, {"416", "Requested Range Not Satisfiable"}, {"417", "Expectation Failed"}, {"418", "I'm a teapot"}, {"422", "Unprocessable Entity"}, {"425", "Too Early"}, {"426", "Upgrade Required"}, {"428", "Precondition Required"}, {"429", "Too Many Requests"}, {"431", "Request Header Fields Too Large"}, {"451", "Unavailable For Legal Reasons"}, {"501", "Not Implemented"}, {"502", "Bad Gateway"}, {"503", "Service Unavailable"}, {"504", "Gateway Timeout"}, {"505", "HTTP Version Not Supported"}, {"509", "Bandwidth Limit Exceeded"}, {"511", "Network Authentication Required"}, {"", NULL}, }; void uwsgi_init_default() { uwsgi.cpus = 1; uwsgi.new_argc = -1; uwsgi.backtrace_depth = 64; uwsgi.max_apps = 64; uwsgi.master_queue = -1; uwsgi.signal_socket = -1; uwsgi.my_signal_socket = -1; uwsgi.stats_fd = -1; uwsgi.stats_pusher_default_freq = 3; uwsgi.original_log_fd = 2; uwsgi.emperor_fd_config = -1; uwsgi.emperor_fd_proxy = -1; // default emperor scan frequency uwsgi.emperor_freq = 3; uwsgi.emperor_throttle = 1000; uwsgi.emperor_heartbeat = 30; uwsgi.emperor_curse_tolerance = 30; // max 3 minutes throttling uwsgi.emperor_max_throttle = 1000 * 180; uwsgi.emperor_pid = -1; uwsgi.subscribe_freq = 10; uwsgi.subscription_tolerance = 17; uwsgi.cores = 1; uwsgi.threads = 1; // default max number of rpc slot uwsgi.rpc_max = 64; uwsgi.offload_threads_events = 64; uwsgi.default_app = -1; uwsgi.buffer_size = 4096; uwsgi.body_read_warning = 8; uwsgi.numproc = 1; uwsgi.forkbomb_delay = 2; uwsgi.async = 1; uwsgi.listen_queue = 100; uwsgi.cheaper_overload = 3; uwsgi.log_master_bufsize = 8192; uwsgi.worker_reload_mercy = 60; uwsgi.mule_reload_mercy = 60; uwsgi.max_vars = MAX_VARS; uwsgi.vec_size = 4 + 1 + (4 * MAX_VARS); uwsgi.socket_timeout = 4; uwsgi.logging_options.enabled = 1; // a workers hould be running for at least 10 seconds uwsgi.min_worker_lifetime = 10; uwsgi.spooler_frequency = 30; uwsgi.shared->spooler_signal_pipe[0] = -1; uwsgi.shared->spooler_signal_pipe[1] = -1; uwsgi.shared->mule_signal_pipe[0] = -1; uwsgi.shared->mule_signal_pipe[1] = -1; uwsgi.shared->mule_queue_pipe[0] = -1; uwsgi.shared->mule_queue_pipe[1] = -1; uwsgi.shared->worker_log_pipe[0] = -1; uwsgi.shared->worker_log_pipe[1] = -1; uwsgi.shared->worker_req_log_pipe[0] = -1; uwsgi.shared->worker_req_log_pipe[1] = -1; uwsgi.req_log_fd = 2; #ifdef UWSGI_SSL // 1 day of tolerance uwsgi.subscriptions_sign_check_tolerance = 3600 * 24; uwsgi.ssl_sessions_timeout = 300; uwsgi.ssl_verify_depth = 1; #endif uwsgi.alarm_freq = 3; uwsgi.alarm_msg_size = 8192; uwsgi.exception_handler_msg_size = 65536; uwsgi.multicast_ttl = 1; uwsgi.multicast_loop = 1; // filling http status codes struct http_status_codes *http_sc; for (http_sc = hsc; http_sc->message != NULL; http_sc++) { http_sc->message_size = strlen(http_sc->message); } uwsgi.empty = ""; #ifdef __linux__ uwsgi.cgroup_dir_mode = "0700"; #endif uwsgi.wait_read_hook = uwsgi_simple_wait_read_hook; uwsgi.wait_write_hook = uwsgi_simple_wait_write_hook; uwsgi.wait_milliseconds_hook = uwsgi_simple_wait_milliseconds_hook; uwsgi.wait_read2_hook = uwsgi_simple_wait_read2_hook; uwsgi_websockets_init(); // 1 MB default limit uwsgi.chunked_input_limit = 1024*1024; // clear reforked status uwsgi.master_is_reforked = 0; uwsgi.master_fifo_fd = -1; uwsgi_master_fifo_prepare(); uwsgi.notify_socket_fd = -1; uwsgi.harakiri_graceful_signal = SIGTERM; } void uwsgi_setup_reload() { char env_reload_buf[11]; char *env_reloads = getenv("UWSGI_RELOADS"); if (env_reloads) { //convert env value to int uwsgi.reloads = atoi(env_reloads); uwsgi.reloads++; //convert reloads to string int rlen = snprintf(env_reload_buf, 10, "%u", uwsgi.reloads); if (rlen > 0 && rlen < 10) { env_reload_buf[rlen] = 0; if (setenv("UWSGI_RELOADS", env_reload_buf, 1)) { uwsgi_error("setenv()"); } } uwsgi.is_a_reload = 1; } else { if (setenv("UWSGI_RELOADS", "0", 1)) { uwsgi_error("setenv()"); } } } void uwsgi_autoload_plugins_by_name(char *argv_zero) { char *plugins_requested = NULL; char *original_proc_name = getenv("UWSGI_ORIGINAL_PROC_NAME"); if (!original_proc_name) { // here we use argv[0]; original_proc_name = argv_zero; setenv("UWSGI_ORIGINAL_PROC_NAME", original_proc_name, 1); } char *p = strrchr(original_proc_name, '/'); if (p == NULL) p = original_proc_name; p = strstr(p, "uwsgi_"); if (p != NULL) { char *ctx = NULL; uwsgi_foreach_token(uwsgi_str(p + 6), "_", plugins_requested, ctx) { uwsgi_log("[uwsgi] implicit plugin requested %s\n", plugins_requested); uwsgi_load_plugin(-1, plugins_requested, NULL); } } plugins_requested = getenv("UWSGI_PLUGINS"); if (plugins_requested) { plugins_requested = uwsgi_concat2(plugins_requested, ""); char *p, *ctx = NULL; uwsgi_foreach_token(plugins_requested, ",", p, ctx) { uwsgi_load_plugin(-1, p, NULL); } } } void uwsgi_commandline_config() { int i; uwsgi.option_index = -1; int argc = uwsgi.argc; char **argv = uwsgi.argv; if (uwsgi.new_argc > -1 && uwsgi.new_argv) { argc = uwsgi.new_argc; argv = uwsgi.new_argv; } char *optname; while ((i = getopt_long(argc, argv, uwsgi.short_options, uwsgi.long_options, &uwsgi.option_index)) != -1) { if (i == '?') { uwsgi_log("getopt_long() error\n"); exit(1); } if (uwsgi.option_index > -1) { optname = (char *) uwsgi.long_options[uwsgi.option_index].name; } else { optname = uwsgi_get_optname_by_index(i); } if (!optname) { uwsgi_log("unable to parse command line options\n"); exit(1); } uwsgi.option_index = -1; add_exported_option(optname, optarg, 0); } #ifdef UWSGI_DEBUG uwsgi_log("optind:%d argc:%d\n", optind, uwsgi.argc); #endif if (optind < argc) { for (i = optind; i < argc; i++) { char *lazy = argv[i]; if (lazy[0] != '[') { uwsgi_opt_load(NULL, lazy, NULL); // manage magic mountpoint int magic = 0; int j; for (j = 0; j < uwsgi.gp_cnt; j++) { if (uwsgi.gp[j]->magic) { if (uwsgi.gp[j]->magic(NULL, lazy)) { magic = 1; break; } } } if (!magic) { for (j = 0; j < 256; j++) { if (uwsgi.p[j]->magic) { if (uwsgi.p[j]->magic(NULL, lazy)) { magic = 1; break; } } } } } } } } void uwsgi_setup_workers() { int i, j; // allocate shared memory for workers + master uwsgi.workers = (struct uwsgi_worker *) uwsgi_calloc_shared(sizeof(struct uwsgi_worker) * (uwsgi.numproc + 1)); for (i = 0; i <= uwsgi.numproc; i++) { // allocate memory for apps uwsgi.workers[i].apps = (struct uwsgi_app *) uwsgi_calloc_shared(sizeof(struct uwsgi_app) * uwsgi.max_apps); // allocate memory for cores uwsgi.workers[i].cores = (struct uwsgi_core *) uwsgi_calloc_shared(sizeof(struct uwsgi_core) * uwsgi.cores); // this is a trick for avoiding too much memory areas void *ts = uwsgi_calloc_shared(sizeof(void *) * uwsgi.max_apps * uwsgi.cores); // add 4 bytes for uwsgi header void *buffers = uwsgi_malloc_shared((uwsgi.buffer_size+4) * uwsgi.cores); void *hvec = uwsgi_malloc_shared(sizeof(struct iovec) * uwsgi.vec_size * uwsgi.cores); void *post_buf = NULL; if (uwsgi.post_buffering > 0) post_buf = uwsgi_malloc_shared(uwsgi.post_buffering_bufsize * uwsgi.cores); for (j = 0; j < uwsgi.cores; j++) { // allocate shared memory for thread states (required for some language, like python) uwsgi.workers[i].cores[j].ts = ts + ((sizeof(void *) * uwsgi.max_apps) * j); // raw per-request buffer (+4 bytes for uwsgi header) uwsgi.workers[i].cores[j].buffer = buffers + ((uwsgi.buffer_size+4) * j); // iovec for uwsgi vars uwsgi.workers[i].cores[j].hvec = hvec + ((sizeof(struct iovec) * uwsgi.vec_size) * j); if (post_buf) uwsgi.workers[i].cores[j].post_buf = post_buf + (uwsgi.post_buffering_bufsize * j); } // master does not need to following steps... if (i == 0) continue; uwsgi.workers[i].signal_pipe[0] = -1; uwsgi.workers[i].signal_pipe[1] = -1; snprintf(uwsgi.workers[i].name, 0xff, "uWSGI worker %d", i); } uint64_t total_memory = (sizeof(struct uwsgi_app) * uwsgi.max_apps) + (sizeof(struct uwsgi_core) * uwsgi.cores) + (sizeof(void *) * uwsgi.max_apps * uwsgi.cores) + (uwsgi.buffer_size * uwsgi.cores) + (sizeof(struct iovec) * uwsgi.vec_size * uwsgi.cores); if (uwsgi.post_buffering > 0) { total_memory += (uwsgi.post_buffering_bufsize * uwsgi.cores); } total_memory *= (uwsgi.numproc + uwsgi.master_process); if (uwsgi.numproc > 0) uwsgi_log("mapped %llu bytes (%llu KB) for %d cores\n", (unsigned long long) total_memory, (unsigned long long) (total_memory / 1024), uwsgi.cores * uwsgi.numproc); // allocate signal table uwsgi.shared->signal_table = uwsgi_calloc_shared(sizeof(struct uwsgi_signal_entry) * 256 * (uwsgi.numproc + 1)); #ifdef UWSGI_ROUTING uwsgi_fixup_routes(uwsgi.routes); uwsgi_fixup_routes(uwsgi.error_routes); uwsgi_fixup_routes(uwsgi.response_routes); uwsgi_fixup_routes(uwsgi.final_routes); #endif } pid_t uwsgi_daemonize2() { if (uwsgi.has_emperor) { logto(uwsgi.daemonize2); } else { if (!uwsgi.is_a_reload) { uwsgi_log("*** daemonizing uWSGI ***\n"); daemonize(uwsgi.daemonize2); } else if (uwsgi.log_reopen) { logto(uwsgi.daemonize2); } } uwsgi.mypid = getpid(); uwsgi.workers[0].pid = uwsgi.mypid; if (uwsgi.pidfile && !uwsgi.is_a_reload) { uwsgi_write_pidfile(uwsgi.pidfile); } if (uwsgi.pidfile2 && !uwsgi.is_a_reload) { uwsgi_write_pidfile(uwsgi.pidfile2); } if (uwsgi.log_master) uwsgi_setup_log_master(); return uwsgi.mypid; } // fix/check related options void sanitize_args() { if (uwsgi.async > 1) { uwsgi.cores = uwsgi.async; } uwsgi.has_threads = 1; if (uwsgi.threads > 1) { uwsgi.cores = uwsgi.threads; } if (uwsgi.harakiri_options.workers > 0) { if (!uwsgi.post_buffering) { uwsgi_log(" *** WARNING: you have enabled harakiri without post buffering. Slow upload could be rejected on post-unbuffered webservers *** \n"); } } if (uwsgi.write_errors_exception_only) { uwsgi.ignore_sigpipe = 1; uwsgi.ignore_write_errors = 1; } if (uwsgi.cheaper_count == 0) uwsgi.cheaper = 0; if (uwsgi.cheaper_count > 0 && uwsgi.cheaper_count >= uwsgi.numproc) { uwsgi_log("invalid cheaper value: must be lower than processes\n"); exit(1); } if (uwsgi.cheaper && uwsgi.cheaper_count) { if (uwsgi.cheaper_initial) { if (uwsgi.cheaper_initial < uwsgi.cheaper_count) { uwsgi_log("warning: invalid cheaper-initial value (%d), must be equal or higher than cheaper (%d), using %d as initial number of workers\n", uwsgi.cheaper_initial, uwsgi.cheaper_count, uwsgi.cheaper_count); uwsgi.cheaper_initial = uwsgi.cheaper_count; } else if (uwsgi.cheaper_initial > uwsgi.numproc) { uwsgi_log("warning: invalid cheaper-initial value (%d), must be lower or equal than worker count (%d), using %d as initial number of workers\n", uwsgi.cheaper_initial, uwsgi.numproc, uwsgi.numproc); uwsgi.cheaper_initial = uwsgi.numproc; } } else { uwsgi.cheaper_initial = uwsgi.cheaper_count; } } if (uwsgi.max_worker_lifetime > 0 && uwsgi.min_worker_lifetime >= uwsgi.max_worker_lifetime) { uwsgi_log("invalid min-worker-lifetime value (%d), must be lower than max-worker-lifetime (%d)\n", uwsgi.min_worker_lifetime, uwsgi.max_worker_lifetime); exit(1); } if (uwsgi.cheaper_rss_limit_soft && uwsgi.logging_options.memory_report != 1 && uwsgi.force_get_memusage != 1) { uwsgi_log("enabling cheaper-rss-limit-soft requires enabling also memory-report\n"); exit(1); } if (uwsgi.cheaper_rss_limit_hard && !uwsgi.cheaper_rss_limit_soft) { uwsgi_log("enabling cheaper-rss-limit-hard requires setting also cheaper-rss-limit-soft\n"); exit(1); } if ( uwsgi.cheaper_rss_limit_hard && uwsgi.cheaper_rss_limit_hard <= uwsgi.cheaper_rss_limit_soft) { uwsgi_log("cheaper-rss-limit-hard value must be higher than cheaper-rss-limit-soft value\n"); exit(1); } if (uwsgi.evil_reload_on_rss || uwsgi.evil_reload_on_as) { if (!uwsgi.mem_collector_freq) uwsgi.mem_collector_freq = 3; } /* here we try to choose if thunder lock is a good thing */ #ifdef UNBIT if (uwsgi.numproc > 1 && !uwsgi.map_socket) { uwsgi.use_thunder_lock = 1; } #endif } const char *uwsgi_http_status_msg(char *status, uint16_t *len) { struct http_status_codes *http_sc; for (http_sc = hsc; http_sc->message != NULL; http_sc++) { if (!strncmp(http_sc->key, status, 3)) { *len = http_sc->message_size; return http_sc->message; } } return NULL; } uwsgi-2.0.29/core/io.c000066400000000000000000001025351477626554400144770ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; /* poll based fd waiter. Use it for blocking areas (like startup functions) DO NOT USE IN REQUEST PLUGINS !!! */ int uwsgi_waitfd_event(int fd, int timeout, int event) { int ret; struct pollfd upoll; if (!timeout) timeout = uwsgi.socket_timeout; timeout = timeout * 1000; if (timeout < 0) timeout = -1; upoll.fd = fd; upoll.events = event; upoll.revents = 0; ret = poll(&upoll, 1, timeout); if (ret < 0) { uwsgi_error("uwsgi_waitfd_event()/poll()"); } else if (ret > 0) { if (upoll.revents & event) { return ret; } return -1; } return ret; } /* consume data from an fd (blocking) */ char *uwsgi_read_fd(int fd, size_t *size, int add_zero) { char stack_buf[4096]; ssize_t len; char *buffer = NULL; len = 1; while (len > 0) { len = read(fd, stack_buf, 4096); if (len > 0) { *size += len; char *tmp = realloc(buffer, *size); if (!tmp) { uwsgi_error("uwsgi_read_fd()/realloc()"); exit(1); } buffer = tmp; memcpy(buffer + (*size - len), stack_buf, len); } } if (add_zero) { *size = *size + 1; buffer = realloc(buffer, *size); if (!buffer) { uwsgi_error("uwsgi_read_fd()/realloc()"); exit(1); } buffer[*size - 1] = 0; } return buffer; } // simply read the whole content of a file char *uwsgi_simple_file_read(char *filename) { struct stat sb; char *buffer; ssize_t len; int fd = open(filename, O_RDONLY); if (fd < 0) { uwsgi_error_open(filename); goto end; } if (fstat(fd, &sb)) { uwsgi_error("fstat()"); close(fd); goto end; } buffer = uwsgi_malloc(sb.st_size + 1); len = read(fd, buffer, sb.st_size); if (len != sb.st_size) { uwsgi_error("read()"); free(buffer); close(fd); goto end; } close(fd); if (buffer[sb.st_size - 1] == '\n' || buffer[sb.st_size - 1] == '\r') { buffer[sb.st_size - 1] = 0; } buffer[sb.st_size] = 0; return buffer; end: return (char *) ""; } static char *uwsgi_scheme_fd(char *url, size_t *size, int add_zero) { int fd = atoi(url); return uwsgi_read_fd(fd, size, add_zero); } static char *uwsgi_scheme_exec(char *url, size_t *size, int add_zero) { int cpipe[2]; if (pipe(cpipe)) { uwsgi_error("pipe()"); exit(1); } uwsgi_run_command(url, NULL, cpipe[1]); char *buffer = uwsgi_read_fd(cpipe[0], size, add_zero); close(cpipe[0]); close(cpipe[1]); return buffer; } static char *uwsgi_scheme_http(char *url, size_t *size, int add_zero) { char byte; int body = 0; char *buffer = NULL; char *domain = url; char *uri = strchr(domain, '/'); if (!uri) { uwsgi_log("invalid http url\n"); exit(1); } uri[0] = 0; uwsgi_log("domain: %s\n", domain); char *colon = uwsgi_get_last_char(domain, ':'); if (colon) { colon[0] = 0; } char *ip = uwsgi_resolve_ip(domain); if (!ip) { uwsgi_log("unable to resolve address %s\n", domain); exit(1); } if (colon) { colon[0] = ':'; ip = uwsgi_concat2(ip, colon); } else { ip = uwsgi_concat2(ip, ":80"); } int fd = uwsgi_connect(ip, 0, 0); if (fd < 0) { uwsgi_error("uwsgi_scheme_http()/connect()"); exit(1); } free(ip); uri[0] = '/'; if (write(fd, "GET ", 4) != 4) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);} if (write(fd, uri, strlen(uri)) != (ssize_t) strlen(uri)) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);} if (write(fd, " HTTP/1.0\r\n", 11) != 11) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);} if (write(fd, "Host: ", 6) != 6) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);} uri[0] = 0; if (write(fd, domain, strlen(domain)) != (ssize_t) strlen(domain)) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);} uri[0] = '/'; if (write(fd, "\r\nUser-Agent: uWSGI on ", 23) != 23) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);} if (write(fd, uwsgi.hostname, uwsgi.hostname_len) != uwsgi.hostname_len) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);} if (write(fd, "\r\n\r\n", 4) != 4) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);} int http_status_code_ptr = 0; while (read(fd, &byte, 1) == 1) { if (byte == '\r' && body == 0) { body = 1; } else if (byte == '\n' && body == 1) { body = 2; } else if (byte == '\r' && body == 2) { body = 3; } else if (byte == '\n' && body == 3) { body = 4; } else if (body == 4) { *size = *size + 1; char *tmp = realloc(buffer, *size); if (!tmp) { uwsgi_error("uwsgi_open_and_read()/realloc()"); exit(1); } buffer = tmp; buffer[*size - 1] = byte; } else { body = 0; http_status_code_ptr++; if (http_status_code_ptr == 10) { if (byte != '2') { uwsgi_log("Not usable HTTP response: %cxx\n", byte); if (uwsgi.has_emperor) { exit(UWSGI_EXILE_CODE); } else { exit(1); } } } } } close(fd); if (add_zero) { *size = *size + 1; char *tmp = realloc(buffer, *size); if (!tmp) { uwsgi_error("uwsgi_open_and_read()/realloc()"); exit(1); } buffer = tmp; buffer[*size - 1] = 0; } return buffer; } static char *uwsgi_scheme_emperor(char *url, size_t *size, int add_zero) { if (uwsgi.emperor_fd_config < 0) { uwsgi_log("this is not a vassal instance\n"); exit(1); } ssize_t rlen; struct uwsgi_header uh; size_t remains = 4; char *ptr = (char *) &uh; while(remains) { int ret = uwsgi_waitfd(uwsgi.emperor_fd_config, 5); if (ret <= 0) { uwsgi_log("[uwsgi-vassal] error waiting for config header %s !!!\n", url); exit(1); } rlen = read(uwsgi.emperor_fd_config, ptr, remains); if (rlen <= 0) { uwsgi_log("[uwsgi-vassal] error reading config header from %s !!!\n", url); exit(1); } ptr+=rlen; remains-=rlen; } remains = uh.pktsize; if (!remains) { uwsgi_log("[uwsgi-vassal] invalid config from %s\n", url); exit(1); } char *buffer = uwsgi_calloc(remains + add_zero); ptr = buffer; while (remains) { int ret = uwsgi_waitfd(uwsgi.emperor_fd_config, 5); if (ret <= 0) { uwsgi_log("[uwsgi-vassal] error waiting for config %s !!!\n", url); exit(1); } rlen = read(uwsgi.emperor_fd_config, ptr, remains); if (rlen <= 0) { uwsgi_log("[uwsgi-vassal] error reading config from %s !!!\n", url); exit(1); } ptr+=rlen; remains-=rlen; } *size = uh.pktsize + add_zero; return buffer; } static char *uwsgi_scheme_data(char *url, size_t *size, int add_zero) { char *buffer = NULL; int fd = open(uwsgi.binary_path, O_RDONLY); if (fd < 0) { uwsgi_error_open(uwsgi.binary_path); exit(1); } int slot = atoi(url); if (slot < 0) { uwsgi_log("invalid binary data slot requested\n"); exit(1); } uwsgi_log("requesting binary data slot %d\n", slot); off_t fo = lseek(fd, 0, SEEK_END); if (fo < 0) { uwsgi_error("lseek()"); uwsgi_log("invalid binary data slot requested\n"); exit(1); } int i = 0; uint64_t datasize = 0; for (i = 0; i <= slot; i++) { fo = lseek(fd, -8, SEEK_CUR); if (fo < 0) { uwsgi_error("lseek()"); uwsgi_log("invalid binary data slot requested\n"); exit(1); } ssize_t len = read(fd, &datasize, 8); if (len != 8) { uwsgi_error("read()"); uwsgi_log("invalid binary data slot requested\n"); exit(1); } if (datasize == 0) { uwsgi_log("0 size binary data !!!\n"); exit(1); } fo = lseek(fd, -(datasize + 8), SEEK_CUR); if (fo < 0) { uwsgi_error("lseek()"); uwsgi_log("invalid binary data slot requested\n"); exit(1); } if (i == slot) { *size = datasize; if (add_zero) { *size += 1; } buffer = uwsgi_malloc(*size); memset(buffer, 0, *size); len = read(fd, buffer, datasize); if (len != (ssize_t) datasize) { uwsgi_error("read()"); uwsgi_log("invalid binary data slot requested\n"); exit(1); } } } close(fd); return buffer; } static char *uwsgi_scheme_call(char *url, size_t *size, int add_zero) { char *(*func)(void) = dlsym(RTLD_DEFAULT, url); if (!func) { uwsgi_log("unable to find symbol %s\n", url); exit(1); } char *s = func(); if (!s) { uwsgi_log("called symbol %s did not return a string\n", url); exit(1); } *size = strlen(s); if (add_zero) { *size += 1; } char *buffer = uwsgi_malloc(*size); memset(buffer, 0, *size); memcpy(buffer, s, strlen(s)); return buffer; } static char *uwsgi_scheme_callint(char *url, size_t *size, int add_zero) { int (*func)(void) = dlsym(RTLD_DEFAULT, url); if (!func) { uwsgi_log("unable to find symbol %s\n", url); exit(1); } char *s = uwsgi_num2str(func()); *size = strlen(s); if (add_zero) { *size += 1; } char *buffer = uwsgi_malloc(*size); memset(buffer, 0, *size); memcpy(buffer, s, strlen(s)); free(s); return buffer; } static char *uwsgi_scheme_sym(char *url, size_t *size, int add_zero) { void *sym_start_ptr = NULL, *sym_end_ptr = NULL; char **raw_symbol = dlsym(RTLD_DEFAULT, url); if (raw_symbol) { sym_start_ptr = *raw_symbol; sym_end_ptr = sym_start_ptr + strlen(sym_start_ptr); goto found; } char *symbol = uwsgi_concat3("_binary_", url, "_start"); sym_start_ptr = dlsym(RTLD_DEFAULT, symbol); if (!sym_start_ptr) { uwsgi_log("unable to find symbol %s\n", symbol); exit(1); } free(symbol); symbol = uwsgi_concat3("_binary_", url, "_end"); sym_end_ptr = dlsym(RTLD_DEFAULT, symbol); if (!sym_end_ptr) { uwsgi_log("unable to find symbol %s\n", symbol); exit(1); } free(symbol); found: *size = sym_end_ptr - sym_start_ptr; if (add_zero) { *size += 1; } char *buffer = uwsgi_malloc(*size); memset(buffer, 0, *size); memcpy(buffer, sym_start_ptr, sym_end_ptr - sym_start_ptr); return buffer; } static char *uwsgi_scheme_section(char *url, size_t *size, int add_zero) { #ifdef UWSGI_ELF size_t s_len = 0; char *buffer = uwsgi_elf_section(uwsgi.binary_path, url, &s_len); if (!buffer) { uwsgi_log("unable to find section %s in %s\n", url + 10, uwsgi.binary_path); exit(1); } *size = s_len; if (add_zero) *size += 1; return buffer; #else uwsgi_log("section:// scheme not supported on this platform\n"); exit(1); #endif } struct uwsgi_string_list *uwsgi_register_scheme(char *name, char * (*func)(char *, size_t *, int)) { struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, uwsgi.schemes) { if (!strcmp(usl->value, name)) goto found; } usl = uwsgi_string_new_list(&uwsgi.schemes, name); found: usl->custom_ptr = func; return usl; } char *uwsgi_open_and_read(char *url, size_t *size, int add_zero, char *magic_table[]) { struct stat sb; char *buffer = NULL; ssize_t len; char *magic_buf; int fd; *size = 0; // stdin ? if (!strcmp(url, "-")) { buffer = uwsgi_read_fd(0, size, add_zero); goto end; } #ifdef UWSGI_EMBED_CONFIG else if (url[0] == 0) { *size = &UWSGI_EMBED_CONFIG_END - &UWSGI_EMBED_CONFIG; if (add_zero) { *size += 1; } buffer = uwsgi_malloc(*size); memset(buffer, 0, *size); memcpy(buffer, &UWSGI_EMBED_CONFIG, &UWSGI_EMBED_CONFIG_END - &UWSGI_EMBED_CONFIG); goto end; } #endif struct uwsgi_string_list *usl = uwsgi_check_scheme(url); if (!usl) goto fallback; char *(*func)(char *, size_t *, int) = (char *(*)(char *, size_t *, int)) usl->custom_ptr; buffer = func(url + usl->len + 3, size, add_zero); if (buffer) goto end; // never here !!! uwsgi_log("unable to parse config file %s\n", url); exit(1); // fallback to file fallback: fd = open(url, O_RDONLY); if (fd < 0) { uwsgi_error_open(url); exit(1); } if (fstat(fd, &sb)) { uwsgi_error("fstat()"); exit(1); } if (S_ISFIFO(sb.st_mode)) { buffer = uwsgi_read_fd(fd, size, add_zero); close(fd); goto end; } // is it a potential virtual file (/proc, /sys...) ? int is_virtual = 0; if (sb.st_size == 0) { is_virtual = 1; sb.st_size = 4096; } buffer = uwsgi_malloc(sb.st_size + add_zero); len = read(fd, buffer, sb.st_size); if (!is_virtual) { if (len != sb.st_size) { } } else { if (len >= 0) { sb.st_size = len; } else { uwsgi_error("read()"); exit(1); } } close(fd); *size = sb.st_size + add_zero; if (add_zero) buffer[sb.st_size] = 0; end: if (magic_table) { // here we inject blobs struct uwsgi_string_list *usl = NULL; if (uwsgi.inject_before || uwsgi.inject_after) { struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); uwsgi_foreach(usl, uwsgi.inject_before) { size_t rlen = 0; char *before = uwsgi_open_and_read(usl->value, &rlen, 0, NULL); if (uwsgi_buffer_append(ub, before, rlen)) { uwsgi_log("unable to inject data in the config file\n"); exit(1); } free(before); } if (uwsgi_buffer_append(ub, buffer, *size - add_zero)) { uwsgi_log("unable to inject data in the config file\n"); exit(1); } uwsgi_foreach(usl, uwsgi.inject_after) { size_t rlen = 0; char *after = uwsgi_open_and_read(usl->value, &rlen, 0, NULL); if (uwsgi_buffer_append(ub, after, rlen)) { uwsgi_log("unable to inject data in the config file\n"); exit(1); } free(after); } if (add_zero) { if (uwsgi_buffer_append(ub, "\0", 1)) { uwsgi_log("unable to inject data in the config file\n"); exit(1); } } *size = ub->pos; // free resources free(buffer); buffer = ub->buf; // aboid destroying buffer ub->buf = NULL; uwsgi_buffer_destroy(ub); } magic_buf = magic_sub(buffer, *size, size, magic_table); free(buffer); return magic_buf; } return buffer; } // attach an fd using UNIX sockets int *uwsgi_attach_fd(int fd, int *count_ptr, char *code, size_t code_len) { struct msghdr msg; ssize_t len; char *id = NULL; struct iovec iov; struct cmsghdr *cmsg; int *ret; int i; int count = *count_ptr; void *msg_control = uwsgi_malloc(CMSG_SPACE(sizeof(int) * count)); memset(msg_control, 0, CMSG_SPACE(sizeof(int) * count)); if (code && code_len > 0) { // allocate space for code and num_sockets id = uwsgi_malloc(code_len + sizeof(int)); memset(id, 0, code_len); iov.iov_len = code_len + sizeof(int); } iov.iov_base = id; memset(&msg, 0, sizeof(msg)); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = msg_control; msg.msg_controllen = CMSG_SPACE(sizeof(int) * count); msg.msg_flags = 0; len = recvmsg(fd, &msg, 0); if (len <= 0) { uwsgi_error("recvmsg()"); free(msg_control); return NULL; } if (code && code_len > 0) { if (uwsgi_strncmp(id, code_len, code, code_len)) { free(msg_control); return NULL; } if ((size_t) len == code_len + sizeof(int)) { memcpy(&i, id + code_len, sizeof(int)); if (i > count) { *count_ptr = i; free(msg_control); free(id); return NULL; } } } cmsg = CMSG_FIRSTHDR(&msg); if (!cmsg) { free(msg_control); return NULL; } if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { free(msg_control); return NULL; } if ((size_t) (cmsg->cmsg_len - ((char *) CMSG_DATA(cmsg) - (char *) cmsg)) > (size_t) (sizeof(int) * (count + 1))) { uwsgi_log("not enough space for sockets data, consider increasing it\n"); free(msg_control); return NULL; } ret = uwsgi_malloc(sizeof(int) * (count + 1)); for (i = 0; i < count + 1; i++) { ret[i] = -1; } memcpy(ret, CMSG_DATA(cmsg), cmsg->cmsg_len - ((char *) CMSG_DATA(cmsg) - (char *) cmsg)); free(msg_control); if (code && code_len > 0) { free(id); } return ret; } // signal free close void uwsgi_protected_close(int fd) { sigset_t mask, oset; sigfillset(&mask); if (sigprocmask(SIG_BLOCK, &mask, &oset)) { uwsgi_error("sigprocmask()"); exit(1); } close(fd); if (sigprocmask(SIG_SETMASK, &oset, NULL)) { uwsgi_error("sigprocmask()"); exit(1); } } // signal free read ssize_t uwsgi_protected_read(int fd, void *buf, size_t len) { sigset_t mask, oset; sigfillset(&mask); if (sigprocmask(SIG_BLOCK, &mask, &oset)) { uwsgi_error("sigprocmask()"); exit(1); } ssize_t ret = read(fd, buf, len); if (sigprocmask(SIG_SETMASK, &oset, NULL)) { uwsgi_error("sigprocmask()"); exit(1); } return ret; } // pipe datas from a fd to another (blocking) ssize_t uwsgi_pipe(int src, int dst, int timeout) { char buf[8192]; size_t written = -1; ssize_t len; for (;;) { int ret = uwsgi_waitfd(src, timeout); if (ret > 0) { len = read(src, buf, 8192); if (len == 0) { return written; } else if (len < 0) { uwsgi_error("read()"); return -1; } size_t remains = len; while (remains > 0) { int ret = uwsgi_waitfd_write(dst, timeout); if (ret > 0) { len = write(dst, buf, remains); if (len > 0) { remains -= len; written += len; } else if (len == 0) { return written; } else { uwsgi_error("write()"); return -1; } } else if (ret == 0) { goto timeout; } else { return -1; } } } else if (ret == 0) { goto timeout; } else { return -1; } } return written; timeout: uwsgi_log("timeout while piping from %d to %d !!!\n", src, dst); return -1; } /* even if it is marked as non-blocking, so not use in request plugins as it uses poll() and not the hooks */ int uwsgi_write_nb(int fd, char *buf, size_t remains, int timeout) { char *ptr = buf; while(remains > 0) { int ret = uwsgi_waitfd_write(fd, timeout); if (ret > 0) { ssize_t len = write(fd, ptr, remains); if (len <= 0) { return -1; } ptr += len; remains -= len; continue; } return -1; } return 0; } /* this is like uwsgi_write_nb() but with fast initial write and hooked wait (use it in request plugin) */ int uwsgi_write_true_nb(int fd, char *buf, size_t remains, int timeout) { char *ptr = buf; int ret; while(remains > 0) { errno = 0; ssize_t len = write(fd, ptr, remains); if (len > 0) goto written; if (len == 0) return -1; if (len < 0) { if (uwsgi_is_again()) goto wait; return -1; } wait: ret = uwsgi.wait_write_hook(fd, timeout); if (ret > 0) { len = write(fd, ptr, remains); if (len > 0) goto written; } return -1; written: ptr += len; remains -= len; continue; } return 0; } // like uwsgi_pipe but with fixed size ssize_t uwsgi_pipe_sized(int src, int dst, size_t required, int timeout) { char buf[8192]; size_t written = 0; ssize_t len; while (written < required) { int ret = uwsgi_waitfd(src, timeout); if (ret > 0) { len = read(src, buf, UMIN(8192, required - written)); if (len == 0) { return written; } else if (len < 0) { uwsgi_error("read()"); return -1; } size_t remains = len; while (remains > 0) { int ret = uwsgi_waitfd_write(dst, timeout); if (ret > 0) { len = write(dst, buf, remains); if (len > 0) { remains -= len; written += len; } else if (len == 0) { return written; } else { uwsgi_error("write()"); return -1; } } else if (ret == 0) { goto timeout; } else { return -1; } } } else if (ret == 0) { goto timeout; } else { return -1; } } return written; timeout: uwsgi_log("timeout while piping from %d to %d !!!\n", src, dst); return -1; } // check if an fd is valid int uwsgi_valid_fd(int fd) { int ret = fcntl(fd, F_GETFL); if (ret == -1) { return 0; } return 1; } void uwsgi_close_all_fds(void) { int i; for (i = 3; i < (int) uwsgi.max_fd; i++) { #ifdef __APPLE__ fcntl(i, F_SETFD, FD_CLOEXEC); #else close(i); #endif } } int uwsgi_read_uh(int fd, struct uwsgi_header *uh, int timeout) { char *ptr = (char *) uh; size_t remains = 4; while(remains > 0) { int ret = uwsgi_waitfd(fd, timeout); if (ret > 0) { ssize_t len = read(fd, ptr, remains); if (len <= 0) { return -1; } remains -=len; ptr +=len; continue; } return -1; } return 0; } int uwsgi_read_nb(int fd, char *buf, size_t remains, int timeout) { char *ptr = buf; while(remains > 0) { int ret = uwsgi_waitfd(fd, timeout); if (ret > 0) { ssize_t len = read(fd, ptr, remains); if (len <= 0) { return -1; } remains -=len; ptr +=len; continue; } return -1; } return 0; } /* this is like uwsgi_read_nb() but with fast initial read and hooked wait (use it in request plugin) */ ssize_t uwsgi_read_true_nb(int fd, char *buf, size_t len, int timeout) { int ret; errno = 0; ssize_t rlen = read(fd, buf, len); if (rlen > 0) { return rlen; } if (rlen == 0) return -1; if (rlen < 0) { if (uwsgi_is_again()) goto wait; } return -1; wait: errno = 0; ret = uwsgi.wait_read_hook(fd, timeout); if (ret > 0) { errno = 0; rlen = read(fd, buf, len); if (rlen > 0) { return rlen; } return -1; } return ret; } /* like the previous one but consume the whole len (if possibile) */ int uwsgi_read_whole_true_nb(int fd, char *buf, size_t remains, int timeout) { char *ptr = buf; while(remains > 0) { ssize_t len = uwsgi_read_true_nb(fd, ptr, remains, timeout); if (len <= 0) return -1; ptr += len; remains -= len; } return 0; } /* this is a pretty magic function used for reading a full uwsgi response it is true non blocking, so you can use it in request plugins buffer is expected to be at least 4 bytes, rlen is a get/set value */ int uwsgi_read_with_realloc(int fd, char **buffer, size_t *rlen, int timeout, uint8_t *modifier1, uint8_t *modifier2) { if (*rlen < 4) return -1; char *buf = *buffer; int ret; // start reading the header char *ptr = buf; size_t remains = 4; while(remains > 0) { ssize_t len = read(fd, ptr, remains); if (len > 0) goto readok; if (len == 0) return -1; if (len < 0) { if (uwsgi_is_again()) goto wait; return -1; } wait: ret = uwsgi.wait_read_hook(fd, timeout); if (ret > 0) { len = read(fd, ptr, remains); if (len > 0) goto readok; } return -1; readok: ptr += len; remains -= len; continue; } struct uwsgi_header *uh = (struct uwsgi_header *) buf; uint16_t pktsize = uh->pktsize; if (modifier1) *modifier1 = uh->modifier1; if (modifier2) *modifier2 = uh->modifier2; if (pktsize > *rlen) { char *tmp_buf = realloc(buf, pktsize); if (!tmp_buf) { uwsgi_error("uwsgi_read_with_realloc()/realloc()"); return -1; } *buffer = tmp_buf; buf = *buffer; } *rlen = pktsize; // read the body remains = pktsize; ptr = buf; while(remains > 0) { ssize_t len = read(fd, ptr, remains); if (len > 0) goto readok2; if (len == 0) return -1; if (len < 0) { if (uwsgi_is_again()) goto wait2; return -1; } wait2: ret = uwsgi.wait_read_hook(fd, timeout); if (ret > 0) { len = read(fd, ptr, remains); if (len > 0) goto readok2; } return -1; readok2: ptr += len; remains -= len; continue; } return 0; } /* this is a commodity (big) function to send a buffer and wsgi_req body to a socket and to receive back data (and send them to the client) */ int uwsgi_proxy_nb(struct wsgi_request *wsgi_req, char *addr, struct uwsgi_buffer *ub, size_t remains, int timeout) { struct uwsgi_buffer *headers = NULL; if (!ub) { return -1; } int fd = uwsgi_connect(addr, 0, 1); if (fd < 0) { return -1; } int ret = uwsgi.wait_write_hook(fd, timeout); if (ret <= 0) { goto end; } // send the request (+ remaining data) if (uwsgi_write_true_nb(fd, ub->buf, ub->pos, timeout)) { goto end; } // send the body while(remains > 0) { ssize_t rlen = 0; char *buf = uwsgi_request_body_read(wsgi_req, 8192, &rlen); if (!buf) { goto end; } if (buf == uwsgi.empty) break; // write data to the node if (uwsgi_write_true_nb(fd, buf, rlen, timeout)) { goto end; } remains -= rlen; } // read the response headers = uwsgi_buffer_new(8192); // max 64k headers ub->limit = UMAX16; for(;;) { char buf[8192]; ssize_t rlen = uwsgi_read_true_nb(fd, buf, 8192, timeout); if (rlen > 0) { if (headers) { if (uwsgi_buffer_append(headers, buf, rlen)) { goto end; } // check if we have a full HTTP response if (uwsgi_is_full_http(headers)) { int ret = uwsgi_blob_to_response(wsgi_req, headers->buf, headers->pos); if (ret) continue; uwsgi_buffer_destroy(headers); headers = NULL; } } else { if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) { break; } } continue; } break; } if (headers) uwsgi_buffer_destroy(headers); close(fd); return 0; end: if (headers) uwsgi_buffer_destroy(headers); close(fd); return -1; } void uwsgi_file_write_do(struct uwsgi_string_list *usl) { struct uwsgi_string_list *fl = usl; while(fl) { char *equal = strchr(fl->value, '='); if (equal) { *equal = 0; FILE *f = fopen(fl->value, "w"); if (!f) { uwsgi_error_open("uwsgi_file_write_do()"); exit(1); } uwsgi_log("writing \"%s\" to \"%s\" ...\n", equal+1, fl->value); if (fprintf(f, "%s\n", equal+1) <= 0 || ferror(f) || fclose(f)) { uwsgi_error("uwsgi_file_write_do()"); exit(1); } } else { uwsgi_log("unable to write empty value for \"%s\"\n", fl->value); exit(1); } *equal = '='; fl = fl->next; } } int uwsgi_fd_is_safe(int fd) { int i; for(i=0;isocket) { wsgi_req->socket->proto_close(wsgi_req); } wsgi_req->fd_closed = 1; } int uwsgi_ready_fd(struct wsgi_request *wsgi_req) { if (wsgi_req->async_ready_fd) return wsgi_req->async_last_ready_fd; return -1; } void uwsgi_setup_schemes() { uwsgi_register_scheme("emperor", uwsgi_scheme_emperor); uwsgi_register_scheme("http", uwsgi_scheme_http); uwsgi_register_scheme("data", uwsgi_scheme_data); uwsgi_register_scheme("sym", uwsgi_scheme_sym); uwsgi_register_scheme("section", uwsgi_scheme_section); uwsgi_register_scheme("fd", uwsgi_scheme_fd); uwsgi_register_scheme("exec", uwsgi_scheme_exec); uwsgi_register_scheme("call", uwsgi_scheme_call); uwsgi_register_scheme("callint", uwsgi_scheme_callint); } struct uwsgi_string_list *uwsgi_check_scheme(char *file) { struct uwsgi_string_list *usl; uwsgi_foreach(usl, uwsgi.schemes) { char *url = uwsgi_concat2(usl->value, "://"); int ret = uwsgi_startswith(file, url, strlen(url)); free(url); if (!ret) return usl; } return NULL; } void uwsgi_remap_fd(int fd, char *filename) { int fdin = open(filename, O_RDWR); if (fdin < 0) { uwsgi_error_open(filename); exit(1); } /* stdin */ if (fdin != fd) { if (dup2(fdin, fd) < 0) { uwsgi_error("uwsgi_remap_fd()/dup2()"); exit(1); } close(fdin); } } int uwsgi_is_connected(int fd) { int soopt; socklen_t solen = sizeof(int); if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *) (&soopt), &solen) < 0) { return 0; } /* is something bad ? */ if (soopt) return 0; return 1; } int uwsgi_pass_cred(int fd, char *code, size_t code_len) { #ifdef SCM_CREDENTIALS struct msghdr cr_msg; struct cmsghdr *cmsg; struct iovec cr_iov; void *cr_msg_control = uwsgi_calloc(CMSG_SPACE(sizeof(struct ucred))); cr_iov.iov_base = code; cr_iov.iov_len = code_len; cr_msg.msg_name = NULL; cr_msg.msg_namelen = 0; cr_msg.msg_iov = &cr_iov; cr_msg.msg_iovlen = 1; cr_msg.msg_flags = 0; cr_msg.msg_control = cr_msg_control; cr_msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred)); cmsg = CMSG_FIRSTHDR(&cr_msg); cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_CREDENTIALS; struct ucred *u = (struct ucred*) CMSG_DATA(cmsg); u->pid = getpid(); u->uid = getuid(); u->gid = getgid(); if (sendmsg(fd, &cr_msg, 0) < 0) { uwsgi_error("uwsgi_pass_cred()/sendmsg()"); free(cr_msg_control); return -1; } free(cr_msg_control); return 0; #else return -1; #endif } int uwsgi_pass_cred2(int fd, char *code, size_t code_len, struct sockaddr *addr, size_t addr_len) { #ifdef SCM_CREDENTIALS struct msghdr cr_msg; struct cmsghdr *cmsg; struct iovec cr_iov; void *cr_msg_control = uwsgi_calloc(CMSG_SPACE(sizeof(struct ucred))); cr_iov.iov_base = code; cr_iov.iov_len = code_len; cr_msg.msg_name = addr; cr_msg.msg_namelen = addr_len; cr_msg.msg_iov = &cr_iov; cr_msg.msg_iovlen = 1; cr_msg.msg_flags = 0; cr_msg.msg_control = cr_msg_control; cr_msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred)); cmsg = CMSG_FIRSTHDR(&cr_msg); cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_CREDENTIALS; struct ucred *u = (struct ucred*) CMSG_DATA(cmsg); u->pid = getpid(); u->uid = getuid(); u->gid = getgid(); if (sendmsg(fd, &cr_msg, 0) < 0) { uwsgi_error("uwsgi_pass_cred2()/sendmsg()"); free(cr_msg_control); return -1; } free(cr_msg_control); return 0; #else return -1; #endif } int uwsgi_recv_cred(int fd, char *code, size_t code_len, pid_t *pid, uid_t *uid, gid_t *gid) { #ifdef SCM_CREDENTIALS struct iovec iov; int ret = -1; void *msg_control = uwsgi_calloc(CMSG_SPACE(sizeof(struct ucred))); iov.iov_base = uwsgi_malloc(code_len); iov.iov_len = code_len; struct msghdr msg; memset(&msg, 0, sizeof(msg)); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = msg_control; msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred)); ssize_t len = recvmsg(fd, &msg, 0); if (len <= 0) { uwsgi_error("uwsgi_recv_cred()/recvmsg()"); goto clear; } struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); if (!cmsg) goto clear; if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDENTIALS) { goto clear; } if (uwsgi_strncmp(code, code_len, iov.iov_base, iov.iov_len)) goto clear; struct ucred *u = (struct ucred *) CMSG_DATA(cmsg); *pid = u->pid; *uid = u->uid; *gid = u->gid; ret = 0; clear: free(msg_control); free(iov.iov_base); return ret; #else return -1; #endif } ssize_t uwsgi_recv_cred2(int fd, char *buf, size_t buf_len, pid_t *pid, uid_t *uid, gid_t *gid) { #ifdef SCM_CREDENTIALS struct iovec iov; ssize_t ret = -1; void *msg_control = uwsgi_calloc(CMSG_SPACE(sizeof(struct ucred))); iov.iov_base = buf; iov.iov_len = buf_len; struct msghdr msg; memset(&msg, 0, sizeof(msg)); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = msg_control; msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred)); ssize_t len = recvmsg(fd, &msg, 0); if (len <= 0) { uwsgi_error("uwsgi_recv_cred2()/recvmsg()"); goto clear; } struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); if (!cmsg) goto clear; if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDENTIALS) { goto clear; } struct ucred *u = (struct ucred *) CMSG_DATA(cmsg); *pid = u->pid; *uid = u->uid; *gid = u->gid; ret = len; clear: free(msg_control); return ret; #else return -1; #endif } uwsgi-2.0.29/core/json.c000066400000000000000000000207741477626554400150450ustar00rootroot00000000000000#ifdef UWSGI_JSON #include "uwsgi.h" extern struct uwsgi_server uwsgi; #if defined(UWSGI_JSON_YAJL_OLD) #include struct uwsgi_yajl_old_state { char *object; char *key; int in_object; int is_array; }; static int uwsgi_yajl_cb_null(void *ctx) { struct uwsgi_yajl_old_state *uyos = (struct uwsgi_yajl_old_state *) ctx; if (!uyos->key) return 1; add_exported_option(uyos->key, strdup("0"), 0); return 1; } static int uwsgi_yajl_cb_boolean(void *ctx, int b) { struct uwsgi_yajl_old_state *uyos = (struct uwsgi_yajl_old_state *) ctx; if (!uyos->key) return 1; if (b) { add_exported_option(uyos->key, strdup("1"), 0); } else { add_exported_option(uyos->key, strdup("0"), 0); } return 1; } static int uwsgi_yajl_cb_integer(void *ctx, long n) { struct uwsgi_yajl_old_state *uyos = (struct uwsgi_yajl_old_state *) ctx; if (!uyos->key) return 1; add_exported_option(uyos->key, uwsgi_64bit2str((int64_t) n), 0); return 1; } static int uwsgi_yajl_cb_double(void *ctx, double n) { return uwsgi_yajl_cb_integer(ctx, (long) n); } static int uwsgi_yajl_cb_string(void *ctx, const unsigned char *s, unsigned int s_len) { struct uwsgi_yajl_old_state *uyos = (struct uwsgi_yajl_old_state *) ctx; if (!uyos->key) return 1; add_exported_option(uyos->key, uwsgi_concat2n((char *)s, (size_t)s_len, "", 0), 0); return 1; } static int uwsgi_yajl_cb_number(void *ctx, const char *n, unsigned int n_len) { return uwsgi_yajl_cb_string(ctx, (const unsigned char *)n, n_len); } static int uwsgi_yajl_cb_map_key(void *ctx, const unsigned char *s, unsigned int s_len) { struct uwsgi_yajl_old_state *uyos = (struct uwsgi_yajl_old_state *) ctx; if (!uyos->in_object) { if (!uwsgi_strncmp(uyos->object, strlen(uyos->object), (char *)s, (size_t)s_len)) { uyos->in_object = 1; } return 1; } uyos->key = uwsgi_concat2n((char *)s, (size_t)s_len, "", 0); return 1; } static yajl_callbacks callbacks = { .yajl_null = uwsgi_yajl_cb_null, .yajl_boolean = uwsgi_yajl_cb_boolean, .yajl_integer = uwsgi_yajl_cb_integer, .yajl_double = uwsgi_yajl_cb_double, .yajl_number = uwsgi_yajl_cb_number, .yajl_string = uwsgi_yajl_cb_string, .yajl_start_map = NULL, .yajl_map_key = uwsgi_yajl_cb_map_key, .yajl_end_map = NULL, .yajl_start_array = NULL, .yajl_end_array = NULL, }; void uwsgi_json_config(char *file, char *magic_table[]) { size_t len = 0; char *object_asked = "uwsgi"; char *colon; if (uwsgi_check_scheme(file)) { colon = uwsgi_get_last_char(file, '/'); colon = uwsgi_get_last_char(colon, ':'); } else { colon = uwsgi_get_last_char(file, ':'); } if (colon) { colon[0] = 0; if (colon[1] != 0) { object_asked = colon + 1; } } struct uwsgi_yajl_old_state uyos; memset(&uyos, 0, sizeof(struct uwsgi_yajl_old_state)); uyos.object = object_asked; uwsgi_log_initial("[uWSGI] getting JSON configuration from %s\n", file); char *json_data = uwsgi_open_and_read(file, &len, 1, magic_table); yajl_handle hand = yajl_alloc(&callbacks, NULL, NULL, &uyos); yajl_status s = yajl_parse(hand, (const unsigned char *)json_data, len); if (s != yajl_status_ok) { uwsgi_log("%s\n", yajl_get_error(hand, 1, (const unsigned char *)json_data, len)); exit(1); } } #elif defined(UWSGI_JSON_YAJL) #include void uwsgi_json_config(char *file, char *magic_table[]) { size_t len = 0; char *object_asked = "uwsgi"; char *colon; if (uwsgi_check_scheme(file)) { colon = uwsgi_get_last_char(file, '/'); colon = uwsgi_get_last_char(colon, ':'); } else { colon = uwsgi_get_last_char(file, ':'); } if (colon) { colon[0] = 0; if (colon[1] != 0) { object_asked = colon + 1; } } uwsgi_log_initial("[uWSGI] getting JSON configuration from %s\n", file); char *json_data = uwsgi_open_and_read(file, &len, 1, magic_table); char errbuf[1024]; yajl_val node = yajl_tree_parse((const char *)json_data, errbuf, sizeof(errbuf)); if (!node) { uwsgi_log("error parsing JSON data: %s\n", errbuf); exit(1); } const char * path[] = { object_asked, NULL }; yajl_val v = yajl_tree_get(node, path, yajl_t_any); if (!YAJL_IS_OBJECT(v)) { uwsgi_log("you must define a object named %s in your JSON data\n", object_asked); exit(1); } size_t i; for(i=0;iu.object.len;i++) { char *key = (char *) v->u.object.keys[i]; yajl_val o = v->u.object.values[i]; if (YAJL_IS_STRING(o)) { add_exported_option(key, YAJL_GET_STRING(o) , 0); } else if (YAJL_IS_TRUE(o)) { add_exported_option(key, strdup("1"), 0); } else if (YAJL_IS_FALSE(o) || YAJL_IS_NULL(o)) { add_exported_option(key, strdup("0"), 0); } else if (YAJL_IS_NUMBER(o) || YAJL_IS_INTEGER(o)) { add_exported_option(key, YAJL_GET_NUMBER(o), 0); } else if (YAJL_IS_ARRAY(o)) { size_t j; for(j=0;ju.array.len;j++) { yajl_val a_o = o->u.array.values[j]; if (YAJL_IS_STRING(a_o)) { add_exported_option(key, YAJL_GET_STRING(a_o) , 0); } else if (YAJL_IS_TRUE(a_o)) { add_exported_option(key, strdup("1"), 0); } else if (YAJL_IS_FALSE(a_o) || YAJL_IS_NULL(a_o)) { add_exported_option(key, strdup("0"), 0); } else if (YAJL_IS_NUMBER(a_o) || YAJL_IS_INTEGER(a_o)) { add_exported_option(key, YAJL_GET_NUMBER(a_o), 0); } } } } } #else #include void uwsgi_json_config(char *file, char *magic_table[]) { size_t len = 0; char *json_data; const char *key; json_t *root; json_error_t error; json_t *config; json_t *config_value, *config_array_item; void *config_iter; char *object_asked = "uwsgi"; char *colon; int i; if (uwsgi_check_scheme(file)) { colon = uwsgi_get_last_char(file, '/'); colon = uwsgi_get_last_char(colon, ':'); } else { colon = uwsgi_get_last_char(file, ':'); } if (colon) { colon[0] = 0; if (colon[1] != 0) { object_asked = colon + 1; } } uwsgi_log_initial("[uWSGI] getting JSON configuration from %s\n", file); json_data = uwsgi_open_and_read(file, &len, 1, magic_table); #ifdef JANSSON_MAJOR_VERSION root = json_loads(json_data, 0, &error); #else root = json_loads(json_data, &error); #endif if (!root) { uwsgi_log("error parsing JSON data: line %d %s\n", error.line, error.text); exit(1); } config = json_object_get(root, object_asked); if (!json_is_object(config)) { uwsgi_log("you must define a object named %s in your JSON data\n", object_asked); exit(1); } config_iter = json_object_iter(config); while (config_iter) { key = json_object_iter_key(config_iter); config_value = json_object_iter_value(config_iter); if (json_is_string(config_value)) { add_exported_option((char *) key, (char *) json_string_value(config_value), 0); } else if (json_is_true(config_value)) { add_exported_option((char *) key, strdup("1"), 0); } else if (json_is_false(config_value) || json_is_null(config_value)) { add_exported_option((char *) key, strdup("0"), 0); } else if (json_is_integer(config_value)) { add_exported_option((char *) key, uwsgi_num2str(json_integer_value(config_value)), 0); } else if (json_is_array(config_value)) { for (i = 0; i < (int) json_array_size(config_value); i++) { config_array_item = json_array_get(config_value, i); if (json_is_string(config_array_item)) { add_exported_option((char *) key, (char *) json_string_value(config_array_item), 0); } else if (json_is_true(config_array_item)) { add_exported_option((char *) key, strdup("1"), 0); } else if (json_is_false(config_array_item) || json_is_null(config_array_item)) { add_exported_option((char *) key, strdup("0"), 0); } else if (json_is_integer(config_array_item)) { add_exported_option((char *) key, uwsgi_num2str(json_integer_value(config_array_item)), 0); } } } config_iter = json_object_iter_next(config, config_iter); } if (colon) colon[0] = ':'; } #endif #endif uwsgi-2.0.29/core/legion.c000066400000000000000000001061511477626554400153430ustar00rootroot00000000000000#include "../uwsgi.h" extern struct uwsgi_server uwsgi; /* uWSGI Legions subsystem A Legion is a group of uWSGI instances sharing a single object. This single object can be owned only by the instance with the higher valor. Such an instance is the Lord of the Legion. There can only be one (and only one) Lord for each Legion. If a member of a Legion spawns with an higher valor than the current Lord, it became the new Lord. */ struct uwsgi_legion *uwsgi_legion_get_by_socket(int fd) { struct uwsgi_legion *ul = uwsgi.legions; while (ul) { if (ul->socket == fd) { return ul; } ul = ul->next; } return NULL; } struct uwsgi_legion *uwsgi_legion_get_by_name(char *name) { struct uwsgi_legion *ul = uwsgi.legions; while (ul) { if (!strcmp(name, ul->legion)) { return ul; } ul = ul->next; } return NULL; } void uwsgi_parse_legion(char *key, uint16_t keylen, char *value, uint16_t vallen, void *data) { struct uwsgi_legion *ul = (struct uwsgi_legion *) data; if (!uwsgi_strncmp(key, keylen, "legion", 6)) { ul->legion = value; ul->legion_len = vallen; } else if (!uwsgi_strncmp(key, keylen, "valor", 5)) { ul->valor = uwsgi_str_num(value, vallen); } else if (!uwsgi_strncmp(key, keylen, "name", 4)) { ul->name = value; ul->name_len = vallen; } else if (!uwsgi_strncmp(key, keylen, "pid", 3)) { ul->pid = uwsgi_str_num(value, vallen); } else if (!uwsgi_strncmp(key, keylen, "unix", 4)) { ul->unix_check = uwsgi_str_num(value, vallen); } else if (!uwsgi_strncmp(key, keylen, "checksum", 8)) { ul->checksum = uwsgi_str_num(value, vallen); } else if (!uwsgi_strncmp(key, keylen, "uuid", 4)) { if (vallen == 36) { memcpy(ul->uuid, value, 36); } } else if (!uwsgi_strncmp(key, keylen, "lord_valor", 10)) { ul->lord_valor = uwsgi_str_num(value, vallen); } else if (!uwsgi_strncmp(key, keylen, "lord_uuid", 9)) { if (vallen == 36) { memcpy(ul->lord_uuid, value, 36); } } else if (!uwsgi_strncmp(key, keylen, "scroll", 6)) { ul->scroll = value; ul->scroll_len = vallen; } else if (!uwsgi_strncmp(key, keylen, "dead", 4)) { ul->dead = 1; } } // this function is called when a node is added or removed (heavy locking is needed) static void legion_rebuild_scrolls(struct uwsgi_legion *ul) { uint64_t max_size = ul->scrolls_max_size; // first, try to add myself if (ul->scroll_len + (uint64_t) 2 > max_size) { uwsgi_log("[DANGER] you have configured a too much tiny buffer for the scrolls list !!! tune it with --legion-scroll-list-max-size\n"); ul->scroll_len = 0; return; } char *ptr = ul->scrolls; *ptr ++= (uint8_t) (ul->scroll_len & 0xff); *ptr ++= (uint8_t) ((ul->scroll_len >> 8) &0xff); memcpy(ptr, ul->scroll, ul->scroll_len); ptr += ul->scroll_len; ul->scrolls_len = 2 + ul->scroll_len; // ok start adding nodes; struct uwsgi_legion_node *uln = ul->nodes_head; while(uln) { if (ul->scrolls_len + 2 + uln->scroll_len > max_size) { uwsgi_log("[DANGER] you have configured a too much tiny buffer for the scrolls list !!! tune it with --legion-scroll-list-max-size\n"); return; } *ptr ++= (uint8_t) (uln->scroll_len & 0xff); *ptr ++= (uint8_t) ((uln->scroll_len >> 8) &0xff); memcpy(ptr, uln->scroll, uln->scroll_len); ptr += uln->scroll_len; ul->scrolls_len += 2 + uln->scroll_len; uln = uln->next; } } // critical section (remember to lock when you use it) struct uwsgi_legion_node *uwsgi_legion_add_node(struct uwsgi_legion *ul, uint16_t valor, char *name, uint16_t name_len, char *uuid) { struct uwsgi_legion_node *node = uwsgi_calloc(sizeof(struct uwsgi_legion_node)); if (!name_len) goto error; node->name = uwsgi_calloc(name_len); node->name_len = name_len; memcpy(node->name, name, name_len); node->valor = valor; memcpy(node->uuid, uuid, 36); if (ul->nodes_tail) { node->prev = ul->nodes_tail; ul->nodes_tail->next = node; } ul->nodes_tail = node; if (!ul->nodes_head) { ul->nodes_head = node; } return node; error: free(node); return NULL; } // critical section (remember to lock when you use it) void uwsgi_legion_remove_node(struct uwsgi_legion *ul, struct uwsgi_legion_node *node) { // check if the node is the first one if (node == ul->nodes_head) { ul->nodes_head = node->next; } // check if the node is the last one if (node == ul->nodes_tail) { ul->nodes_tail = node->prev; } if (node->prev) { node->prev->next = node->next; } if (node->next) { node->next->prev = node->prev; } if (node->name_len) { free(node->name); } if (node->scroll_len) { free(node->scroll); } free(node); legion_rebuild_scrolls(ul); } struct uwsgi_legion_node *uwsgi_legion_get_node(struct uwsgi_legion *ul, uint64_t valor, char *name, uint16_t name_len, char *uuid) { struct uwsgi_legion_node *nodes = ul->nodes_head; while (nodes) { if (valor != nodes->valor) goto next; if (name_len != nodes->name_len) goto next; if (memcmp(nodes->name, name, name_len)) goto next; if (memcmp(nodes->uuid, uuid, 36)) goto next; return nodes; next: nodes = nodes->next; } return NULL; } static void legions_check_nodes() { struct uwsgi_legion *legion = uwsgi.legions; while (legion) { time_t now = uwsgi_now(); struct uwsgi_legion_node *node = legion->nodes_head; while (node) { if (now - node->last_seen > uwsgi.legion_tolerance) { struct uwsgi_legion_node *tmp_node = node; node = node->next; uwsgi_log("[uwsgi-legion] %s: %.*s valor: %llu uuid: %.*s left Legion %s\n", tmp_node->valor > 0 ? "node" : "arbiter", tmp_node->name_len, tmp_node->name, tmp_node->valor, 36, tmp_node->uuid, legion->legion); uwsgi_wlock(legion->lock); uwsgi_legion_remove_node(legion, tmp_node); uwsgi_rwunlock(legion->lock); // trigger node_left hooks struct uwsgi_string_list *usl = legion->node_left_hooks; while (usl) { int ret = uwsgi_legion_action_call("node_left", legion, usl); if (ret) { uwsgi_log("[uwsgi-legion] ERROR, node_left hook returned: %d\n", ret); } usl = usl->next; } continue; } node = node->next; } legion = legion->next; } } struct uwsgi_legion_node *uwsgi_legion_get_lord(struct uwsgi_legion *); static void legions_report_quorum(struct uwsgi_legion *ul, uint64_t best_valor, char *best_uuid, int votes) { struct uwsgi_legion_node *nodes = ul->nodes_head; uwsgi_log("[uwsgi-legion] --- WE HAVE QUORUM FOR LEGION %s !!! (valor: %llu uuid: %.*s checksum: %llu votes: %d) ---\n", ul->legion, best_valor, 36, best_uuid, ul->checksum, votes); while (nodes) { uwsgi_log("[uwsgi-legion-node] %s: %.*s valor: %llu uuid: %.*s last_seen: %d vote_valor: %llu vote_uuid: %.*s\n", nodes->valor > 0 ? "node" : "arbiter", nodes->name_len, nodes->name, nodes->valor, 36, nodes->uuid, nodes->last_seen, nodes->lord_valor, 36, nodes->lord_uuid); nodes = nodes->next; } uwsgi_log("[uwsgi-legion] --- END OF QUORUM REPORT ---\n"); } uint64_t uwsgi_legion_checksum(struct uwsgi_legion *ul) { uint16_t i; uint64_t checksum = ul->valor; for(i=0;i<36;i++) { checksum += ul->uuid[i]; } struct uwsgi_legion_node *nodes = ul->nodes_head; while (nodes) { checksum += nodes->valor; for(i=0;i<36;i++) { checksum += nodes->uuid[i]; } nodes = nodes->next; } return checksum; } static void legions_check_nodes_step2() { struct uwsgi_legion *ul = uwsgi.legions; while (ul) { // ok now we can check the status of the lord int i_am_the_best = 0; uint64_t best_valor = 0; char best_uuid[36]; struct uwsgi_legion_node *node = uwsgi_legion_get_lord(ul); if (node) { // a node is the best candidate best_valor = node->valor; memcpy(best_uuid, node->uuid, 36); } // go on if i am not an arbiter // no potential Lord is available, i will propose myself // but only if i am not suspended... else if (ul->valor > 0 && uwsgi_now() > ul->suspended_til) { best_valor = ul->valor; memcpy(best_uuid, ul->uuid, 36); i_am_the_best = 1; } else { // empty lord memset(best_uuid, 0, 36); } // calculate the checksum uint64_t new_checksum = uwsgi_legion_checksum(ul); if (new_checksum != ul->checksum) { ul->changed = 1; } ul->checksum = new_checksum; // ... ok let's see if all of the nodes agree on the lord // ... but first check if i am not alone... int votes = 1; struct uwsgi_legion_node *nodes = ul->nodes_head; while (nodes) { if (nodes->checksum != ul->checksum) { votes = 0; break; } if (nodes->lord_valor != best_valor) { votes = 0; break; } if (memcmp(nodes->lord_uuid, best_uuid, 36)) { votes = 0; break; } votes++; nodes = nodes->next; } // we have quorum !!! if (votes > 0 && votes >= ul->quorum) { if (!ul->joined) { // triggering join hooks struct uwsgi_string_list *usl = ul->join_hooks; while (usl) { int ret = uwsgi_legion_action_call("join", ul, usl); if (ret) { uwsgi_log("[uwsgi-legion] ERROR, join hook returned: %d\n", ret); } usl = usl->next; } ul->joined = 1; } // something changed ??? if (ul->changed) { legions_report_quorum(ul, best_valor, best_uuid, votes); ul->changed = 0; } if (i_am_the_best) { if (!ul->i_am_the_lord) { // triggering lord hooks uwsgi_log("[uwsgi-legion] attempting to become the Lord of the Legion %s\n", ul->legion); struct uwsgi_string_list *usl = ul->lord_hooks; while (usl) { int ret = uwsgi_legion_action_call("lord", ul, usl); if (ret) { uwsgi_log("[uwsgi-legion] ERROR, lord hook returned: %d\n", ret); if (uwsgi.legion_death_on_lord_error) { ul->dead = 1; uwsgi_legion_announce(ul); ul->suspended_til = uwsgi_now() + uwsgi.legion_death_on_lord_error; uwsgi_log("[uwsgi-legion] suspending myself from Legion \"%s\" for %d seconds\n", ul->legion, uwsgi.legion_death_on_lord_error); goto next; } } usl = usl->next; } if (ul->scroll_len > 0 && ul->scroll_len <= ul->lord_scroll_size) { uwsgi_wlock(ul->lock); ul->lord_scroll_len = ul->scroll_len; memcpy(ul->lord_scroll, ul->scroll, ul->lord_scroll_len); uwsgi_rwunlock(ul->lock); } else { ul->lord_scroll_len = 0; } uwsgi_log("[uwsgi-legion] i am now the Lord of the Legion %s\n", ul->legion); ul->i_am_the_lord = uwsgi_now(); // trick: reduce the time needed by the old lord to unlord itself uwsgi_legion_announce(ul); } } else { if (ul->i_am_the_lord) { uwsgi_log("[uwsgi-legion] a new Lord (valor: %llu uuid: %.*s) raised for Legion %s...\n", ul->lord_valor, 36, ul->lord_uuid, ul->legion); if (ul->lord_scroll_len > 0) { uwsgi_log("*********** The New Lord Scroll ***********\n"); uwsgi_log("%.*s\n", ul->lord_scroll_len, ul->lord_scroll); uwsgi_log("*********** End of the New Lord Scroll ***********\n"); } // no more lord, trigger unlord hooks struct uwsgi_string_list *usl = ul->unlord_hooks; while (usl) { int ret = uwsgi_legion_action_call("unlord", ul, usl); if (ret) { uwsgi_log("[uwsgi-legion] ERROR, unlord hook returned: %d\n", ret); } usl = usl->next; } ul->i_am_the_lord = 0; } } } else if (votes > 0 && votes < ul->quorum && (uwsgi_now() - ul->last_warning >= 60)) { uwsgi_log("[uwsgi-legion] no quorum: only %d vote(s) for Legion %s, %d needed to elect a Lord\n", votes, ul->legion, ul->quorum); // no more quorum, leave the Lord state if (ul->i_am_the_lord) { uwsgi_log("[uwsgi-legion] i cannot be The Lord of The Legion %s without a quorum ...\n", ul->legion); // no more lord, trigger unlord hooks struct uwsgi_string_list *usl = ul->unlord_hooks; while (usl) { int ret = uwsgi_legion_action_call("unlord", ul, usl); if (ret) { uwsgi_log("[uwsgi-legion] ERROR, unlord hook returned: %d\n", ret); } usl = usl->next; } ul->i_am_the_lord = 0; } ul->last_warning = uwsgi_now(); } next: ul = ul->next; } } // check who should be the lord of the legion struct uwsgi_legion_node *uwsgi_legion_get_lord(struct uwsgi_legion *ul) { char best_uuid[36]; memcpy(best_uuid, ul->uuid, 36); uint64_t best_valor = ul->valor; struct uwsgi_legion_node *best_node = NULL; struct uwsgi_legion_node *nodes = ul->nodes_head; while (nodes) { // skip arbiters if (nodes->valor == 0) goto next; if (nodes->valor > best_valor) { best_node = nodes; best_valor = nodes->valor; memcpy(best_uuid, nodes->uuid, 36); } else if (nodes->valor == best_valor) { if (uwsgi_uuid_cmp(nodes->uuid, best_uuid) > 0) { best_node = nodes; best_valor = nodes->valor; memcpy(best_uuid, nodes->uuid, 36); } } next: nodes = nodes->next; } // first round ? (skip first round if arbiter) if (ul->valor > 0 && ul->lord_valor == 0) { ul->changed = 1; } else if (best_valor != ul->lord_valor) { ul->changed = 1; } else { if (memcmp(best_uuid, ul->lord_uuid, 36)) { ul->changed = 1; } } ul->lord_valor = best_valor; memcpy(ul->lord_uuid, best_uuid, 36); if (!best_node) return NULL; if (best_node->scroll_len > 0 && best_node->scroll_len <= ul->lord_scroll_size) { uwsgi_wlock(ul->lock); ul->lord_scroll_len = best_node->scroll_len; memcpy(ul->lord_scroll, best_node->scroll, ul->lord_scroll_len); uwsgi_rwunlock(ul->lock); } else { ul->lord_scroll_len = 0; } return best_node; } static void *legion_loop(void *foobar) { time_t last_round = uwsgi_now(); unsigned char *crypted_buf = uwsgi_malloc(UMAX16 - EVP_MAX_BLOCK_LENGTH - 4); unsigned char *clear_buf = uwsgi_malloc(UMAX16); struct uwsgi_legion legion_msg; if (!uwsgi.legion_freq) uwsgi.legion_freq = 3; if (!uwsgi.legion_tolerance) uwsgi.legion_tolerance = 15; if (!uwsgi.legion_skew_tolerance) uwsgi.legion_skew_tolerance = 60; int first_round = 1; for (;;) { int timeout = uwsgi.legion_freq; time_t now = uwsgi_now(); if (now > last_round) { timeout -= (now - last_round); if (timeout < 0) { timeout = 0; } } last_round = now; // wait for event int interesting_fd = -1; if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying) return NULL; int rlen = event_queue_wait(uwsgi.legion_queue, timeout, &interesting_fd); if (rlen < 0 && errno != EINTR) { if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying) return NULL; uwsgi_nuclear_blast(); return NULL; } now = uwsgi_now(); if (timeout == 0 || rlen == 0 || (now - last_round) >= timeout) { struct uwsgi_legion *legions = uwsgi.legions; while (legions) { uwsgi_legion_announce(legions); legions = legions->next; } last_round = now; } // check the nodes legions_check_nodes(); if (rlen > 0) { struct uwsgi_legion *ul = uwsgi_legion_get_by_socket(interesting_fd); if (!ul) continue; // ensure the first 4 bytes are valid ssize_t len = read(ul->socket, crypted_buf, (UMAX16 - EVP_MAX_BLOCK_LENGTH - 4)); if (len < 0) { uwsgi_error("[uwsgi-legion] read()"); continue; } else if (len < 4) { uwsgi_log("[uwsgi-legion] invalid packet size: %d\n", (int) len); continue; } struct uwsgi_header *uh = (struct uwsgi_header *) crypted_buf; if (uh->modifier1 != 109) { uwsgi_log("[uwsgi-legion] invalid modifier1"); continue; } int d_len = 0; int d2_len = 0; // decrypt packet using the secret if (EVP_DecryptInit_ex(ul->decrypt_ctx, NULL, NULL, NULL, NULL) <= 0) { uwsgi_error("[uwsgi-legion] EVP_DecryptInit_ex()"); continue; } if (EVP_DecryptUpdate(ul->decrypt_ctx, clear_buf, &d_len, crypted_buf + 4, len - 4) <= 0) { uwsgi_error("[uwsgi-legion] EVP_DecryptUpdate()"); continue; } if (EVP_DecryptFinal_ex(ul->decrypt_ctx, clear_buf + d_len, &d2_len) <= 0) { ERR_print_errors_fp(stderr); uwsgi_log("[uwsgi-legion] EVP_DecryptFinal_ex()\n"); continue; } d_len += d2_len; if (d_len != uh->pktsize) { uwsgi_log("[uwsgi-legion] invalid packet size\n"); continue; } // parse packet memset(&legion_msg, 0, sizeof(struct uwsgi_legion)); if (uwsgi_hooked_parse((char *) clear_buf, d_len, uwsgi_parse_legion, &legion_msg)) { uwsgi_log("[uwsgi-legion] invalid packet\n"); continue; } if (uwsgi_strncmp(ul->legion, ul->legion_len, legion_msg.legion, legion_msg.legion_len)) { uwsgi_log("[uwsgi-legion] invalid legion name\n"); continue; } // check for loop packets... (expecially when in multicast mode) if (!uwsgi_strncmp(uwsgi.hostname, uwsgi.hostname_len, legion_msg.name, legion_msg.name_len)) { if (legion_msg.pid == ul->pid) { if (legion_msg.valor == ul->valor) { if (!memcmp(legion_msg.uuid, ul->uuid, 36)) { continue; } } } } // check for "tolerable" unix time if (legion_msg.unix_check < (uwsgi_now() - uwsgi.legion_skew_tolerance)) { uwsgi_log("[uwsgi-legion] untolerable packet received for Legion %s , check your clock !!!\n", ul->legion); continue; } // check if the node is already accounted struct uwsgi_legion_node *node = uwsgi_legion_get_node(ul, legion_msg.valor, legion_msg.name, legion_msg.name_len, legion_msg.uuid); if (!node) { // if a lord hook election fails, a node can announce itself as dead for long time... if (legion_msg.dead) continue; // add the new node uwsgi_wlock(ul->lock); node = uwsgi_legion_add_node(ul, legion_msg.valor, legion_msg.name, legion_msg.name_len, legion_msg.uuid); if (!node) continue; if (legion_msg.scroll_len > 0) { node->scroll = uwsgi_malloc(legion_msg.scroll_len); node->scroll_len = legion_msg.scroll_len; memcpy(node->scroll, legion_msg.scroll, node->scroll_len); } // we are still locked (and safe), let's rebuild the scrolls list legion_rebuild_scrolls(ul); uwsgi_rwunlock(ul->lock); uwsgi_log("[uwsgi-legion] %s: %.*s valor: %llu uuid: %.*s joined Legion %s\n", node->valor > 0 ? "node" : "arbiter", node->name_len, node->name, node->valor, 36, node->uuid, ul->legion); // trigger node_joined hooks struct uwsgi_string_list *usl = ul->node_joined_hooks; while (usl) { int ret = uwsgi_legion_action_call("node_joined", ul, usl); if (ret) { uwsgi_log("[uwsgi-legion] ERROR, node_joined hook returned: %d\n", ret); } usl = usl->next; } } // remove node announcing death else if (legion_msg.dead) { uwsgi_log("[uwsgi-legion] %s: %.*s valor: %llu uuid: %.*s announced its death to Legion %s\n", node->valor > 0 ? "node" : "arbiter", node->name_len, node->name, node->valor, 36, node->uuid, ul->legion); uwsgi_wlock(ul->lock); uwsgi_legion_remove_node(ul, node); uwsgi_rwunlock(ul->lock); continue; } node->last_seen = uwsgi_now(); node->lord_valor = legion_msg.lord_valor; node->checksum = legion_msg.checksum; memcpy(node->lord_uuid, legion_msg.lord_uuid, 36); } // skip the first round if i no packet is received if (first_round) { first_round = 0; continue; } legions_check_nodes_step2(); } return NULL; } int uwsgi_legion_action_call(char *phase, struct uwsgi_legion *ul, struct uwsgi_string_list *usl) { struct uwsgi_legion_action *ula = uwsgi_legion_action_get(usl->custom_ptr); if (!ula) { uwsgi_log("[uwsgi-legion] ERROR unable to find legion_action \"%s\"\n", (char *) usl->custom_ptr); return -1; } if (ula->log_msg) { uwsgi_log("[uwsgi-legion] (phase: %s legion: %s) %s\n", phase, ul->legion, ula->log_msg); } else { uwsgi_log("[uwsgi-legion] (phase: %s legion: %s) calling %s\n", phase, ul->legion, usl->value); } return ula->func(ul, usl->value + usl->custom); } static int legion_action_cmd(struct uwsgi_legion *ul, char *arg) { return uwsgi_run_command_and_wait(NULL, arg); } static int legion_action_signal(struct uwsgi_legion *ul, char *arg) { return uwsgi_signal_send(uwsgi.signal_socket, atoi(arg)); } static int legion_action_log(struct uwsgi_legion *ul, char *arg) { char *logline = uwsgi_concat2(arg, "\n"); uwsgi_log(logline); free(logline); return 0; } static int legion_action_alarm(struct uwsgi_legion *ul, char *arg) { char *space = strchr(arg,' '); if (!space) { uwsgi_log("invalid alarm action syntax, must be: \n"); return -1; } *space = 0; uwsgi_alarm_trigger(arg, space+1, strlen(space+1)); *space = ' '; return 0; } void uwsgi_start_legions() { pthread_t legion_loop_t; if (!uwsgi.legions) return; // register embedded actions uwsgi_legion_action_register("cmd", legion_action_cmd); uwsgi_legion_action_register("exec", legion_action_cmd); uwsgi_legion_action_register("signal", legion_action_signal); uwsgi_legion_action_register("log", legion_action_log); uwsgi_legion_action_register("alarm", legion_action_alarm); uwsgi.legion_queue = event_queue_init(); struct uwsgi_legion *legion = uwsgi.legions; while (legion) { char *colon = strchr(legion->addr, ':'); if (colon) { legion->socket = bind_to_udp(legion->addr, 0, 0); } else { legion->socket = bind_to_unix_dgram(legion->addr); } if (legion->socket < 0 || event_queue_add_fd_read(uwsgi.legion_queue, legion->socket)) { uwsgi_log("[uwsgi-legion] unable to activate legion %s\n", legion->legion); exit(1); } uwsgi_socket_nb(legion->socket); legion->pid = uwsgi.mypid; uwsgi_uuid(legion->uuid); struct uwsgi_string_list *usl = legion->setup_hooks; while (usl) { int ret = uwsgi_legion_action_call("setup", legion, usl); if (ret) { uwsgi_log("[uwsgi-legion] ERROR, setup hook returned: %d\n", ret); } usl = usl->next; } legion = legion->next; } #ifndef UWSGI_UUID uwsgi_log("WARNING: you are not using libuuid to generate Legions UUID\n"); #endif if (pthread_create(&legion_loop_t, NULL, legion_loop, NULL)) { uwsgi_error("pthread_create()"); uwsgi_log("unable to run the legion server !!!\n"); } else { uwsgi_log("legion manager thread enabled\n"); } } void uwsgi_legion_add(struct uwsgi_legion *ul) { struct uwsgi_legion *old_legion = NULL, *legion = uwsgi.legions; while (legion) { old_legion = legion; legion = legion->next; } if (old_legion) { old_legion->next = ul; } else { uwsgi.legions = ul; } } int uwsgi_legion_announce(struct uwsgi_legion *ul) { time_t now = uwsgi_now(); if (now <= ul->suspended_til) return 0; ul->suspended_til = 0; struct uwsgi_buffer *ub = uwsgi_buffer_new(4096); unsigned char *encrypted = NULL; if (uwsgi_buffer_append_keyval(ub, "legion", 6, ul->legion, ul->legion_len)) goto err; if (uwsgi_buffer_append_keynum(ub, "valor", 5, ul->valor)) goto err; if (uwsgi_buffer_append_keynum(ub, "unix", 4, now)) goto err; if (uwsgi_buffer_append_keynum(ub, "lord", 4, ul->i_am_the_lord ? ul->i_am_the_lord : 0)) goto err; if (uwsgi_buffer_append_keyval(ub, "name", 4, uwsgi.hostname, uwsgi.hostname_len)) goto err; if (uwsgi_buffer_append_keynum(ub, "pid", 3, ul->pid)) goto err; if (uwsgi_buffer_append_keyval(ub, "uuid", 4, ul->uuid, 36)) goto err; if (uwsgi_buffer_append_keynum(ub, "checksum", 8, ul->checksum)) goto err; if (uwsgi_buffer_append_keynum(ub, "lord_valor", 10, ul->lord_valor)) goto err; if (uwsgi_buffer_append_keyval(ub, "lord_uuid", 9, ul->lord_uuid, 36)) goto err; if (ul->scroll_len > 0) { if (uwsgi_buffer_append_keyval(ub, "scroll", 6, ul->scroll, ul->scroll_len)) goto err; } if (ul->dead) { if (uwsgi_buffer_append_keyval(ub, "dead", 4, "1", 1)) goto err; } encrypted = uwsgi_malloc(ub->pos + 4 + EVP_MAX_BLOCK_LENGTH); if (EVP_EncryptInit_ex(ul->encrypt_ctx, NULL, NULL, NULL, NULL) <= 0) { uwsgi_error("[uwsgi-legion] EVP_EncryptInit_ex()"); goto err; } int e_len = 0; if (EVP_EncryptUpdate(ul->encrypt_ctx, encrypted + 4, &e_len, (unsigned char *) ub->buf, ub->pos) <= 0) { uwsgi_error("[uwsgi-legion] EVP_EncryptUpdate()"); goto err; } int tmplen = 0; if (EVP_EncryptFinal_ex(ul->encrypt_ctx, encrypted + 4 + e_len, &tmplen) <= 0) { uwsgi_error("[uwsgi-legion] EVP_EncryptFinal_ex()"); goto err; } e_len += tmplen; uint16_t pktsize = ub->pos; encrypted[0] = 109; encrypted[1] = (unsigned char) (pktsize & 0xff); encrypted[2] = (unsigned char) ((pktsize >> 8) & 0xff); encrypted[3] = 0; struct uwsgi_string_list *usl = ul->nodes; while (usl) { if (sendto(ul->socket, encrypted, e_len + 4, 0, usl->custom_ptr, usl->custom) != e_len + 4) { uwsgi_error("[uwsgi-legion] sendto()"); } usl = usl->next; } uwsgi_buffer_destroy(ub); free(encrypted); return 0; err: uwsgi_buffer_destroy(ub); free(encrypted); return -1; } void uwsgi_opt_legion_mcast(char *opt, char *value, void *foobar) { uwsgi_opt_legion(opt, value, foobar); char *legion = uwsgi_str(value); char *space = strchr(legion, ' '); // over engineering if (!space) exit(1); *space = 0; struct uwsgi_legion *ul = uwsgi_legion_get_by_name(legion); if (!ul) { uwsgi_log("unknown legion: %s\n", legion); exit(1); } uwsgi_legion_register_node(ul, uwsgi_str(ul->addr)); free(legion); } void uwsgi_opt_legion_node(char *opt, char *value, void *foobar) { char *legion = uwsgi_str(value); char *space = strchr(legion, ' '); if (!space) { uwsgi_log("invalid legion-node syntax, must be \n"); exit(1); } *space = 0; struct uwsgi_legion *ul = uwsgi_legion_get_by_name(legion); if (!ul) { uwsgi_log("unknown legion: %s\n", legion); exit(1); } uwsgi_legion_register_node(ul, space + 1); } void uwsgi_legion_register_node(struct uwsgi_legion *ul, char *addr) { struct uwsgi_string_list *usl = uwsgi_string_new_list(&ul->nodes, addr); char *port = strchr(addr, ':'); if (!port) { uwsgi_log("[uwsgi-legion] invalid udp address: %s\n", addr); exit(1); } // no need to zero the memory, socket_to_in_addr will do that struct sockaddr_in *sin = uwsgi_malloc(sizeof(struct sockaddr_in)); usl->custom = socket_to_in_addr(addr, port, 0, sin); usl->custom_ptr = sin; } void uwsgi_opt_legion_quorum(char *opt, char *value, void *foobar) { char *legion = uwsgi_str(value); char *space = strchr(legion, ' '); if (!space) { uwsgi_log("invalid legion-quorum syntax, must be \n"); exit(1); } *space = 0; struct uwsgi_legion *ul = uwsgi_legion_get_by_name(legion); if (!ul) { uwsgi_log("unknown legion: %s\n", legion); exit(1); } ul->quorum = atoi(space+1); free(legion); } void uwsgi_opt_legion_scroll(char *opt, char *value, void *foobar) { char *legion = uwsgi_str(value); char *space = strchr(legion, ' '); if (!space) { uwsgi_log("invalid legion-scroll syntax, must be \n"); exit(1); } *space = 0; struct uwsgi_legion *ul = uwsgi_legion_get_by_name(legion); if (!ul) { uwsgi_log("unknown legion: %s\n", legion); exit(1); } ul->scroll = space+1; ul->scroll_len = strlen(ul->scroll); // DO NOT FREE IT !!! //free(legion); } void uwsgi_opt_legion_hook(char *opt, char *value, void *foobar) { char *event = strchr(opt, '-'); if (!event) { uwsgi_log("[uwsgi-legion] invalid option name (%s), this should not happen (possible bug)\n", opt); exit(1); } char *legion = uwsgi_str(value); char *space = strchr(legion, ' '); if (!space) { uwsgi_log("[uwsgi-legion] invalid %s syntax, must be \n", opt); exit(1); } *space = 0; struct uwsgi_legion *ul = uwsgi_legion_get_by_name(legion); if (!ul) { uwsgi_log("[uwsgi-legion] unknown legion: %s\n", legion); exit(1); } uwsgi_legion_register_hook(ul, event + 1, space + 1); } void uwsgi_legion_register_hook(struct uwsgi_legion *ul, char *event, char *action) { struct uwsgi_string_list *usl = NULL; if (!strcmp(event, "lord")) { usl = uwsgi_string_new_list(&ul->lord_hooks, action); } else if (!strcmp(event, "unlord")) { usl = uwsgi_string_new_list(&ul->unlord_hooks, action); } else if (!strcmp(event, "setup")) { usl = uwsgi_string_new_list(&ul->setup_hooks, action); } else if (!strcmp(event, "death")) { usl = uwsgi_string_new_list(&ul->death_hooks, action); } else if (!strcmp(event, "join")) { usl = uwsgi_string_new_list(&ul->join_hooks, action); } else if (!strcmp(event, "node-joined")) { usl = uwsgi_string_new_list(&ul->node_joined_hooks, action); } else if (!strcmp(event, "node-left")) { usl = uwsgi_string_new_list(&ul->node_left_hooks, action); } else { uwsgi_log("[uwsgi-legion] invalid event: %s\n", event); exit(1); } if (!usl) return; char *hook = strchr(action, ':'); if (!hook) { uwsgi_log("[uwsgi-legion] invalid %s action: %s\n", event, action); exit(1); } // pointer to action plugin usl->custom_ptr = uwsgi_concat2n(action, hook - action, "", 0);; // add that to check the plugin value usl->custom = hook - action + 1; } void uwsgi_opt_legion(char *opt, char *value, void *foobar) { // legion addr valor algo:secret char *legion = uwsgi_str(value); char *space = strchr(legion, ' '); if (!space) { uwsgi_log("invalid legion syntax, must be \n"); exit(1); } *space = 0; char *addr = space + 1; space = strchr(addr, ' '); if (!space) { uwsgi_log("invalid legion syntax, must be \n"); exit(1); } *space = 0; char *valor = space + 1; space = strchr(valor, ' '); if (!space) { uwsgi_log("invalid legion syntax, must be \n"); exit(1); } *space = 0; char *algo_secret = space + 1; char *colon = strchr(algo_secret, ':'); if (!colon) { uwsgi_log("invalid legion syntax, must be \n"); exit(1); } *colon = 0; char *secret = colon + 1; uwsgi_legion_register(legion, addr, valor, algo_secret, secret); } struct uwsgi_legion *uwsgi_legion_register(char *legion, char *addr, char *valor, char *algo, char *secret) { char *iv = strchr(secret, ' '); if (iv) { *iv = 0; iv++; } if (!uwsgi.ssl_initialized) { uwsgi_ssl_init(); } #if OPENSSL_VERSION_NUMBER < 0x10100000L EVP_CIPHER_CTX *ctx = uwsgi_malloc(sizeof(EVP_CIPHER_CTX)); EVP_CIPHER_CTX_init(ctx); #else EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); #endif const EVP_CIPHER *cipher = EVP_get_cipherbyname(algo); if (!cipher) { uwsgi_log("[uwsgi-legion] unable to find algorithm/cipher %s\n", algo); exit(1); } int cipher_len = EVP_CIPHER_key_length(cipher); size_t s_len = strlen(secret); if ((unsigned int) cipher_len > s_len) { char *secret_tmp = uwsgi_malloc(cipher_len); memcpy(secret_tmp, secret, s_len); memset(secret_tmp + s_len, 0, cipher_len - s_len); secret = secret_tmp; } int iv_len = EVP_CIPHER_iv_length(cipher); size_t s_iv_len = 0; if (iv) { s_iv_len = strlen(iv); } if ((unsigned int) iv_len > s_iv_len) { char *secret_tmp = uwsgi_malloc(iv_len); memcpy(secret_tmp, iv, s_iv_len); memset(secret_tmp + s_iv_len, '0', iv_len - s_iv_len); iv = secret_tmp; } if (EVP_EncryptInit_ex(ctx, cipher, NULL, (const unsigned char *) secret, (const unsigned char *) iv) <= 0) { uwsgi_error("EVP_EncryptInit_ex()"); exit(1); } #if OPENSSL_VERSION_NUMBER < 0x10100000L EVP_CIPHER_CTX *ctx2 = uwsgi_malloc(sizeof(EVP_CIPHER_CTX)); EVP_CIPHER_CTX_init(ctx2); #else EVP_CIPHER_CTX *ctx2 = EVP_CIPHER_CTX_new(); #endif if (EVP_DecryptInit_ex(ctx2, cipher, NULL, (const unsigned char *) secret, (const unsigned char *) iv) <= 0) { uwsgi_error("EVP_DecryptInit_ex()"); exit(1); } // we use shared memory, as we want to export legion status to the api struct uwsgi_legion *ul = uwsgi_calloc_shared(sizeof(struct uwsgi_legion)); ul->legion = legion; ul->legion_len = strlen(ul->legion); ul->valor = strtol(valor, (char **) NULL, 10); ul->addr = addr; ul->encrypt_ctx = ctx; ul->decrypt_ctx = ctx2; if (!uwsgi.legion_scroll_max_size) { uwsgi.legion_scroll_max_size = 4096; } if (!uwsgi.legion_scroll_list_max_size) { uwsgi.legion_scroll_list_max_size = 32768; } ul->lord_scroll_size = uwsgi.legion_scroll_max_size; ul->lord_scroll = uwsgi_calloc_shared(ul->lord_scroll_size); ul->scrolls_max_size = uwsgi.legion_scroll_list_max_size; ul->scrolls = uwsgi_calloc_shared(ul->scrolls_max_size); uwsgi_legion_add(ul); return ul; } struct uwsgi_legion_action *uwsgi_legion_action_get(char *name) { struct uwsgi_legion_action *ula = uwsgi.legion_actions; while (ula) { if (!strcmp(name, ula->name)) { return ula; } ula = ula->next; } return NULL; } struct uwsgi_legion_action *uwsgi_legion_action_register(char *name, int (*func) (struct uwsgi_legion *, char *)) { struct uwsgi_legion_action *found_ula = uwsgi_legion_action_get(name); if (found_ula) { uwsgi_log("[uwsgi-legion] action \"%s\" is already registered !!!\n", name); return found_ula; } struct uwsgi_legion_action *old_ula = NULL, *ula = uwsgi.legion_actions; while (ula) { old_ula = ula; ula = ula->next; } ula = uwsgi_calloc(sizeof(struct uwsgi_legion_action)); ula->name = name; ula->func = func; if (old_ula) { old_ula->next = ula; } else { uwsgi.legion_actions = ula; } return ula; } void uwsgi_legion_announce_death(void) { struct uwsgi_legion *legion = uwsgi.legions; while (legion) { legion->dead = 1; uwsgi_legion_announce(legion); legion = legion->next; } } void uwsgi_legion_atexit(void) { struct uwsgi_legion *legion = uwsgi.legions; while (legion) { if (getpid() != legion->pid) goto next; struct uwsgi_string_list *usl = legion->death_hooks; while (usl) { int ret = uwsgi_legion_action_call("death", legion, usl); if (ret) { uwsgi_log("[uwsgi-legion] ERROR, death hook returned: %d\n", ret); } usl = usl->next; } next: legion = legion->next; } // this must be called only by the master !!! if (!uwsgi.workers) return; if (uwsgi.workers[0].pid != getpid()) return; uwsgi_legion_announce_death(); } int uwsgi_legion_i_am_the_lord(char *name) { struct uwsgi_legion *legion = uwsgi_legion_get_by_name(name); if (!legion) return 0; if (legion->i_am_the_lord) { return 1; } return 0; } char *uwsgi_legion_lord_scroll(char *name, uint16_t *rlen) { char *buf = NULL; struct uwsgi_legion *legion = uwsgi_legion_get_by_name(name); if (!legion) return 0; uwsgi_rlock(legion->lock); if (legion->lord_scroll_len > 0) { buf = uwsgi_malloc(legion->lord_scroll_len); memcpy(buf, legion->lord_scroll, legion->lord_scroll_len); *rlen = legion->lord_scroll_len; } uwsgi_rwunlock(legion->lock); return buf; } char *uwsgi_legion_scrolls(char *name, uint64_t *rlen) { char *buf = NULL; struct uwsgi_legion *legion = uwsgi_legion_get_by_name(name); if (!legion) return NULL; uwsgi_rlock(legion->lock); buf = uwsgi_malloc(legion->scrolls_len); memcpy(buf, legion->scrolls, legion->scrolls_len); *rlen = legion->scrolls_len; uwsgi_rwunlock(legion->lock); return buf; } uwsgi-2.0.29/core/lock.c000066400000000000000000000475341477626554400150270ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; static struct uwsgi_lock_item *uwsgi_register_lock(char *id, int rw) { struct uwsgi_lock_item *uli = uwsgi.registered_locks; if (!uli) { uwsgi.registered_locks = uwsgi_malloc_shared(sizeof(struct uwsgi_lock_item)); uwsgi.registered_locks->id = id; uwsgi.registered_locks->pid = 0; if (rw) { uwsgi.registered_locks->lock_ptr = uwsgi_malloc_shared(uwsgi.rwlock_size); } else { uwsgi.registered_locks->lock_ptr = uwsgi_malloc_shared(uwsgi.lock_size); } uwsgi.registered_locks->rw = rw; uwsgi.registered_locks->next = NULL; return uwsgi.registered_locks; } while (uli) { if (!uli->next) { uli->next = uwsgi_malloc_shared(sizeof(struct uwsgi_lock_item)); if (rw) { uli->next->lock_ptr = uwsgi_malloc_shared(uwsgi.rwlock_size); } else { uli->next->lock_ptr = uwsgi_malloc_shared(uwsgi.lock_size); } uli->next->id = id; uli->next->pid = 0; uli->next->rw = rw; uli->next->next = NULL; return uli->next; } uli = uli->next; } uwsgi_log("*** DANGER: unable to allocate lock %s ***\n", id); exit(1); } #ifdef UWSGI_LOCK_USE_MUTEX #ifdef OBSOLETE_LINUX_KERNEL #undef EOWNERDEAD #endif #ifdef EOWNERDEAD #define UWSGI_LOCK_ENGINE_NAME "pthread robust mutexes" int uwsgi_pthread_robust_mutexes_enabled = 1; #else #define UWSGI_LOCK_ENGINE_NAME "pthread mutexes" #endif #define UWSGI_LOCK_SIZE sizeof(pthread_mutex_t) #ifdef OBSOLETE_LINUX_KERNEL #define UWSGI_RWLOCK_SIZE sizeof(pthread_mutex_t) #else #define UWSGI_RWLOCK_SIZE sizeof(pthread_rwlock_t) #endif #ifndef PTHREAD_PRIO_INHERIT int pthread_mutexattr_setprotocol (pthread_mutexattr_t *__attr, int __protocol); #define PTHREAD_PRIO_INHERIT 1 #endif // REMEMBER lock must contains space for both pthread_mutex_t and pthread_mutexattr_t !!! struct uwsgi_lock_item *uwsgi_lock_fast_init(char *id) { pthread_mutexattr_t attr; struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0); #ifdef EOWNERDEAD retry: #endif if (pthread_mutexattr_init(&attr)) { uwsgi_log("unable to allocate mutexattr structure\n"); exit(1); } if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) { uwsgi_log("unable to share mutex\n"); exit(1); } #ifdef EOWNERDEAD if (uwsgi_pthread_robust_mutexes_enabled) { int ret; if ((ret = pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT)) != 0) { switch (ret) { case ENOTSUP: // PTHREAD_PRIO_INHERIT will only prevent // priority inversion when SCHED_FIFO or // SCHED_RR is used, so this is non-fatal and // also currently unsupported on musl. break; default: uwsgi_log("unable to set PTHREAD_PRIO_INHERIT\n"); exit(1); } } if (pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST)) { uwsgi_log("unable to make the mutex 'robust'\n"); exit(1); } } #endif if (pthread_mutex_init((pthread_mutex_t *) uli->lock_ptr, &attr)) { #ifdef EOWNERDEAD if (uwsgi_pthread_robust_mutexes_enabled) { uwsgi_log("!!! it looks like your kernel does not support pthread robust mutexes !!!\n"); uwsgi_log("!!! falling back to standard pthread mutexes !!!\n"); uwsgi_pthread_robust_mutexes_enabled = 0; pthread_mutexattr_destroy(&attr); goto retry; } #endif uwsgi_log("unable to initialize mutex\n"); exit(1); } pthread_mutexattr_destroy(&attr); #ifdef EOWNERDEAD if (!uwsgi_pthread_robust_mutexes_enabled) { uli->can_deadlock = 1; } #else uli->can_deadlock = 1; #endif return uli; } pid_t uwsgi_lock_fast_check(struct uwsgi_lock_item * uli) { if (pthread_mutex_trylock((pthread_mutex_t *) uli->lock_ptr) == 0) { pthread_mutex_unlock((pthread_mutex_t *) uli->lock_ptr); return 0; } return uli->pid; } pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item * uli) { #ifdef OBSOLETE_LINUX_KERNEL return uwsgi_lock_fast_check(uli); #else if (pthread_rwlock_trywrlock((pthread_rwlock_t *) uli->lock_ptr) == 0) { pthread_rwlock_unlock((pthread_rwlock_t *) uli->lock_ptr); return 0; } return uli->pid; #endif } void uwsgi_lock_fast(struct uwsgi_lock_item *uli) { #ifdef EOWNERDEAD if (pthread_mutex_lock((pthread_mutex_t *) uli->lock_ptr) == EOWNERDEAD) { uwsgi_log("[deadlock-detector] a process holding a robust mutex died. recovering...\n"); pthread_mutex_consistent((pthread_mutex_t *) uli->lock_ptr); } #else pthread_mutex_lock((pthread_mutex_t *) uli->lock_ptr); #endif uli->pid = uwsgi.mypid; } void uwsgi_unlock_fast(struct uwsgi_lock_item *uli) { pthread_mutex_unlock((pthread_mutex_t *) uli->lock_ptr); uli->pid = 0; } void uwsgi_rlock_fast(struct uwsgi_lock_item *uli) { #ifdef OBSOLETE_LINUX_KERNEL uwsgi_lock_fast(uli); #else pthread_rwlock_rdlock((pthread_rwlock_t *) uli->lock_ptr); uli->pid = uwsgi.mypid; #endif } void uwsgi_wlock_fast(struct uwsgi_lock_item *uli) { #ifdef OBSOLETE_LINUX_KERNEL uwsgi_lock_fast(uli); #else pthread_rwlock_wrlock((pthread_rwlock_t *) uli->lock_ptr); uli->pid = uwsgi.mypid; #endif } void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) { #ifdef OBSOLETE_LINUX_KERNEL uwsgi_unlock_fast(uli); #else pthread_rwlock_unlock((pthread_rwlock_t *) uli->lock_ptr); uli->pid = 0; #endif } struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) { #ifdef OBSOLETE_LINUX_KERNEL return uwsgi_lock_fast_init(id); #else pthread_rwlockattr_t attr; struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 1); if (pthread_rwlockattr_init(&attr)) { uwsgi_log("unable to allocate rwlock structure\n"); exit(1); } if (pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) { uwsgi_log("unable to share rwlock\n"); exit(1); } if (pthread_rwlock_init((pthread_rwlock_t *) uli->lock_ptr, &attr)) { uwsgi_log("unable to initialize rwlock\n"); exit(1); } pthread_rwlockattr_destroy(&attr); uli->can_deadlock = 1; return uli; #endif } #elif defined(UWSGI_LOCK_USE_UMTX) /* Warning: FreeBSD is still not ready for process-shared UMTX */ #include #include #define UWSGI_LOCK_SIZE sizeof(struct umtx) #define UWSGI_RWLOCK_SIZE sizeof(struct umtx) #define UWSGI_LOCK_ENGINE_NAME "FreeBSD umtx" struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) { return uwsgi_lock_fast_init(id); } void uwsgi_rlock_fast(struct uwsgi_lock_item *uli) { uwsgi_lock_fast(uli); } void uwsgi_wlock_fast(struct uwsgi_lock_item *uli) { uwsgi_lock_fast(uli); } void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) { uwsgi_unlock_fast(uli); } struct uwsgi_lock_item *uwsgi_lock_fast_init(char *id) { struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0); umtx_init((struct umtx *) uli->lock_ptr); return uli; } void uwsgi_lock_fast(struct uwsgi_lock_item *uli) { umtx_lock((struct umtx *) uli->lock_ptr, (u_long) getpid()); uli->pid = uwsgi.mypid; } void uwsgi_unlock_fast(struct uwsgi_lock_item *uli) { umtx_unlock((struct umtx *) uli->lock_ptr, (u_long) getpid()); uli->pid = 0; } pid_t uwsgi_lock_fast_check(struct uwsgi_lock_item *uli) { if (umtx_trylock((struct umtx *) uli->lock_ptr, (u_long) getpid())) { umtx_unlock((struct umtx *) uli->lock_ptr, (u_long) getpid()); return 0; } return uli->pid; } pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item * uli) { return uwsgi_lock_fast_check(uli); } #elif defined(UWSGI_LOCK_USE_POSIX_SEM) #define UWSGI_LOCK_SIZE sizeof(sem_t) #define UWSGI_RWLOCK_SIZE sizeof(sem_t) #define UWSGI_LOCK_ENGINE_NAME "POSIX semaphores" #include struct uwsgi_lock_item *uwsgi_lock_fast_init(char *id) { struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0); sem_init((sem_t *) uli->lock_ptr, 1, 1); uli->can_deadlock = 1; return uli; } struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) { return uwsgi_lock_fast_init(id); } void uwsgi_lock_fast(struct uwsgi_lock_item *uli) { sem_wait((sem_t *) uli->lock_ptr); uli->pid = uwsgi.mypid; } void uwsgi_unlock_fast(struct uwsgi_lock_item *uli) { sem_post((sem_t *) uli->lock_ptr); uli->pid = 0; } pid_t uwsgi_lock_fast_check(struct uwsgi_lock_item *uli) { if (sem_trywait((sem_t *) uli->lock_ptr) == 0) { sem_post((sem_t *) uli->lock_ptr); return 0; } return uli->pid; } pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item * uli) { return uwsgi_lock_fast_check(uli); } void uwsgi_rlock_fast(struct uwsgi_lock_item *uli) { uwsgi_lock_fast(uli); } void uwsgi_wlock_fast(struct uwsgi_lock_item *uli) { uwsgi_lock_fast(uli); } void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) { uwsgi_unlock_fast(uli); } #elif defined(UWSGI_LOCK_USE_OSX_SPINLOCK) #define UWSGI_LOCK_ENGINE_NAME "OSX spinlocks" #define UWSGI_LOCK_SIZE sizeof(OSSpinLock) #define UWSGI_RWLOCK_SIZE sizeof(OSSpinLock) struct uwsgi_lock_item *uwsgi_lock_fast_init(char *id) { struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0); memset(uli->lock_ptr, 0, UWSGI_LOCK_SIZE); uli->can_deadlock = 1; return uli; } void uwsgi_lock_fast(struct uwsgi_lock_item *uli) { OSSpinLockLock((OSSpinLock *) uli->lock_ptr); uli->pid = uwsgi.mypid; } void uwsgi_unlock_fast(struct uwsgi_lock_item *uli) { OSSpinLockUnlock((OSSpinLock *) uli->lock_ptr); uli->pid = 0; } pid_t uwsgi_lock_fast_check(struct uwsgi_lock_item *uli) { if (OSSpinLockTry((OSSpinLock *) uli->lock_ptr)) { OSSpinLockUnlock((OSSpinLock *) uli->lock_ptr); return 0; } return uli->pid; } struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) { struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 1); memset(uli->lock_ptr, 0, UWSGI_LOCK_SIZE); uli->can_deadlock = 1; return uli; } void uwsgi_rlock_fast(struct uwsgi_lock_item *uli) { uwsgi_lock_fast(uli); } void uwsgi_wlock_fast(struct uwsgi_lock_item *uli) { uwsgi_lock_fast(uli); } pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item *uli) { return uwsgi_lock_fast_check(uli); } void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) { uwsgi_unlock_fast(uli); } #elif defined(UWSGI_LOCK_USE_WINDOWS_MUTEX) #define UWSGI_LOCK_ENGINE_NAME "windows mutexes" #define UWSGI_LOCK_SIZE sizeof(HANDLE) #define UWSGI_RWLOCK_SIZE sizeof(HANDLE) struct uwsgi_lock_item *uwsgi_lock_fast_init(char *id) { struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0); struct _SECURITY_ATTRIBUTES sa; memset(&sa, 0, sizeof(struct _SECURITY_ATTRIBUTES)); sa.bInheritHandle = 1; uli->lock_ptr = CreateMutex(&sa, FALSE, NULL); return uli; } void uwsgi_lock_fast(struct uwsgi_lock_item *uli) { WaitForSingleObject(uli->lock_ptr, INFINITE); uli->pid = uwsgi.mypid; } void uwsgi_unlock_fast(struct uwsgi_lock_item *uli) { ReleaseMutex(uli->lock_ptr); uli->pid = 0; } pid_t uwsgi_lock_fast_check(struct uwsgi_lock_item *uli) { if (WaitForSingleObject(uli->lock_ptr, 0) == WAIT_TIMEOUT) { return 0; } return uli->pid; } struct uwsgi_lock_item *uwsgi_rwlock_fast_init(char *id) { return uwsgi_lock_fast_init(id); } void uwsgi_rlock_fast(struct uwsgi_lock_item *uli) { uwsgi_lock_fast(uli); } void uwsgi_wlock_fast(struct uwsgi_lock_item *uli) { uwsgi_lock_fast(uli); } pid_t uwsgi_rwlock_fast_check(struct uwsgi_lock_item *uli) { return uwsgi_lock_fast_check(uli); } void uwsgi_rwunlock_fast(struct uwsgi_lock_item *uli) { uwsgi_unlock_fast(uli); } #else #define uwsgi_lock_fast_init uwsgi_lock_ipcsem_init #define uwsgi_lock_fast_check uwsgi_lock_ipcsem_check #define uwsgi_lock_fast uwsgi_lock_ipcsem #define uwsgi_unlock_fast uwsgi_unlock_ipcsem #define uwsgi_rwlock_fast_init uwsgi_rwlock_ipcsem_init #define uwsgi_rwlock_fast_check uwsgi_rwlock_ipcsem_check #define uwsgi_rlock_fast uwsgi_rlock_ipcsem #define uwsgi_wlock_fast uwsgi_wlock_ipcsem #define uwsgi_rwunlock_fast uwsgi_rwunlock_ipcsem #define UWSGI_LOCK_SIZE sizeof(int) #define UWSGI_RWLOCK_SIZE sizeof(int) #define UWSGI_LOCK_ENGINE_NAME "ipcsem" #endif struct uwsgi_lock_item *uwsgi_lock_ipcsem_init(char *id) { // used by ftok static int counter = 1; union semun { int val; struct semid_ds *buf; ushort *array; } semu; int semid; key_t myKey; struct uwsgi_lock_item *uli = uwsgi_register_lock(id, 0); if (uwsgi.ftok) { myKey = ftok(uwsgi.ftok, counter); if (myKey < 0) { uwsgi_error("uwsgi_lock_ipcsem_init()/ftok()"); exit(1); } counter++; semid = semget(myKey, 1, IPC_CREAT | 0666); } else { semid = semget(IPC_PRIVATE, 1, IPC_CREAT | IPC_EXCL | 0666); } if (semid < 0) { uwsgi_error("uwsgi_lock_ipcsem_init()/semget()"); exit(1); } // do this now, to allows triggering of atexit hook in case of problems memcpy(uli->lock_ptr, &semid, sizeof(int)); semu.val = 1; if (semctl(semid, 0, SETVAL, semu)) { uwsgi_error("uwsgi_lock_ipcsem_init()/semctl()"); exit(1); } return uli; } void uwsgi_lock_ipcsem(struct uwsgi_lock_item *uli) { int semid; struct sembuf sb; sb.sem_num = 0; sb.sem_op = -1; sb.sem_flg = SEM_UNDO; memcpy(&semid, uli->lock_ptr, sizeof(int)); retry: if (semop(semid, &sb, 1)) { if (errno == EINTR) goto retry; uwsgi_error("uwsgi_lock_ipcsem()/semop()"); #ifdef EIDRM if (errno == EIDRM) { exit(UWSGI_BRUTAL_RELOAD_CODE); } #endif exit(1); } } void uwsgi_unlock_ipcsem(struct uwsgi_lock_item *uli) { int semid; struct sembuf sb; sb.sem_num = 0; sb.sem_op = 1; sb.sem_flg = SEM_UNDO; memcpy(&semid, uli->lock_ptr, sizeof(int)); retry: if (semop(semid, &sb, 1)) { if (errno == EINTR) goto retry; uwsgi_error("uwsgi_unlock_ipcsem()/semop()"); #ifdef EIDRM if (errno == EIDRM) { exit(UWSGI_BRUTAL_RELOAD_CODE); } #endif exit(1); } } struct uwsgi_lock_item *uwsgi_rwlock_ipcsem_init(char *id) { return uwsgi_lock_ipcsem_init(id); } void uwsgi_rlock_ipcsem(struct uwsgi_lock_item *uli) { uwsgi_lock_ipcsem(uli); } void uwsgi_wlock_ipcsem(struct uwsgi_lock_item *uli) { uwsgi_lock_ipcsem(uli); } void uwsgi_rwunlock_ipcsem(struct uwsgi_lock_item *uli) { uwsgi_unlock_ipcsem(uli); } // ipc cannot deadlock pid_t uwsgi_lock_ipcsem_check(struct uwsgi_lock_item *uli) { return 0; } void uwsgi_ipcsem_clear(void) { if (uwsgi.persistent_ipcsem) return; struct uwsgi_lock_item *uli = uwsgi.registered_locks; if (!uwsgi.workers) goto clear; if (uwsgi.mywid == 0) goto clear; if (uwsgi.master_process && getpid() == uwsgi.workers[0].pid) goto clear; if (!uwsgi.master_process && uwsgi.mywid == 1) goto clear; return; clear: #ifdef UWSGI_DEBUG uwsgi_log("removing sysvipc semaphores...\n"); #endif #ifdef GETPID while (uli) { int semid = 0; memcpy(&semid, uli->lock_ptr, sizeof(int)); int ret = semctl(semid, 0, GETPID); if (ret > 0) { if (ret != (int) getpid() && !kill((pid_t) ret, 0)) { uwsgi_log("found ipcsem mapped to alive pid %d. skipping ipcsem removal.\n", ret); return; } } uli = uli->next; } uli = uwsgi.registered_locks; #endif while (uli) { int semid = 0; memcpy(&semid, uli->lock_ptr, sizeof(int)); if (semctl(semid, 0, IPC_RMID)) { uwsgi_error("uwsgi_ipcsem_clear()/semctl()"); } uli = uli->next; } } pid_t uwsgi_rwlock_ipcsem_check(struct uwsgi_lock_item *uli) { return uwsgi_lock_ipcsem_check(uli); } #ifdef UNBIT /* Unbit-specific workaround for robust-mutexes */ void *uwsgi_robust_mutexes_watchdog_loop(void *arg) { for(;;) { uwsgi_lock(uwsgi.the_thunder_lock); uwsgi_unlock(uwsgi.the_thunder_lock); sleep(1); } return NULL; } void uwsgi_robust_mutexes_watchdog() { pthread_t tid; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); // 32K should be more than enough... pthread_attr_setstacksize(&attr, 32 * 1024); if (pthread_create(&tid, &attr, uwsgi_robust_mutexes_watchdog_loop, NULL)) { uwsgi_error("uwsgi_robust_mutexes_watchdog()/pthread_create()"); exit(1); } } #endif void uwsgi_setup_locking() { int i; if (uwsgi.locking_setup) return; // use the fastest available locking if (uwsgi.lock_engine) { if (!strcmp(uwsgi.lock_engine, "ipcsem")) { uwsgi_log_initial("lock engine: ipcsem\n"); atexit(uwsgi_ipcsem_clear); uwsgi.lock_ops.lock_init = uwsgi_lock_ipcsem_init; uwsgi.lock_ops.lock_check = uwsgi_lock_ipcsem_check; uwsgi.lock_ops.lock = uwsgi_lock_ipcsem; uwsgi.lock_ops.unlock = uwsgi_unlock_ipcsem; uwsgi.lock_ops.rwlock_init = uwsgi_rwlock_ipcsem_init; uwsgi.lock_ops.rwlock_check = uwsgi_rwlock_ipcsem_check; uwsgi.lock_ops.rlock = uwsgi_rlock_ipcsem; uwsgi.lock_ops.wlock = uwsgi_wlock_ipcsem; uwsgi.lock_ops.rwunlock = uwsgi_rwunlock_ipcsem; uwsgi.lock_size = 8; uwsgi.rwlock_size = 8; goto ready; } uwsgi_log("unable to find lock engine \"%s\"\n", uwsgi.lock_engine); exit(1); } uwsgi_log_initial("lock engine: %s\n", UWSGI_LOCK_ENGINE_NAME); #ifdef UWSGI_IPCSEM_ATEXIT atexit(uwsgi_ipcsem_clear); #endif uwsgi.lock_ops.lock_init = uwsgi_lock_fast_init; uwsgi.lock_ops.lock_check = uwsgi_lock_fast_check; uwsgi.lock_ops.lock = uwsgi_lock_fast; uwsgi.lock_ops.unlock = uwsgi_unlock_fast; uwsgi.lock_ops.rwlock_init = uwsgi_rwlock_fast_init; uwsgi.lock_ops.rwlock_check = uwsgi_rwlock_fast_check; uwsgi.lock_ops.rlock = uwsgi_rlock_fast; uwsgi.lock_ops.wlock = uwsgi_wlock_fast; uwsgi.lock_ops.rwunlock = uwsgi_rwunlock_fast; uwsgi.lock_size = UWSGI_LOCK_SIZE; uwsgi.rwlock_size = UWSGI_RWLOCK_SIZE; ready: // application generic lock uwsgi.user_lock = uwsgi_malloc(sizeof(void *) * (uwsgi.locks + 1)); for (i = 0; i < uwsgi.locks + 1; i++) { char *num = uwsgi_num2str(i); uwsgi.user_lock[i] = uwsgi_lock_init(uwsgi_concat2("user ", num)); free(num); } // event queue lock (mitigate same event on multiple queues) if (uwsgi.threads > 1) { pthread_mutex_init(&uwsgi.thunder_mutex, NULL); } if (uwsgi.master_process) { // signal table lock uwsgi.signal_table_lock = uwsgi_lock_init("signal"); // fmon table lock uwsgi.fmon_table_lock = uwsgi_lock_init("filemon"); // timer table lock uwsgi.timer_table_lock = uwsgi_lock_init("timer"); // rb_timer table lock uwsgi.rb_timer_table_lock = uwsgi_lock_init("rbtimer"); // cron table lock uwsgi.cron_table_lock = uwsgi_lock_init("cron"); } if (uwsgi.use_thunder_lock) { // process shared thunder lock uwsgi.the_thunder_lock = uwsgi_lock_init("thunder"); #ifdef UNBIT // we have a serious bug on Unbit (and very probably on older libc) // when all of the workers die in the same moment the pthread robust mutes is left // in inconsistent state and we have no way to recover // we span a thread in the master constantly ensuring the lock is ok // for now we apply it only for Unbit (where thunder-lock is automatically enabled) uwsgi_robust_mutexes_watchdog(); #endif } uwsgi.rpc_table_lock = uwsgi_lock_init("rpc"); #ifdef UWSGI_SSL // register locking for legions struct uwsgi_legion *ul = uwsgi.legions; while(ul) { ul->lock = uwsgi_lock_init(uwsgi_concat2("legion_", ul->legion)); ul = ul->next; } #endif uwsgi.locking_setup = 1; } int uwsgi_fcntl_lock(int fd) { struct flock fl; fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_pid = 0; int ret = fcntl(fd, F_SETLKW, &fl); if (ret < 0) uwsgi_error("fcntl()"); return ret; } int uwsgi_fcntl_is_locked(int fd) { struct flock fl; fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_pid = 0; if (fcntl(fd, F_SETLK, &fl)) { return 1; } return 0; } void uwsgi_deadlock_check(pid_t diedpid) { struct uwsgi_lock_item *uli = uwsgi.registered_locks; while (uli) { if (!uli->can_deadlock) goto nextlock; pid_t locked_pid = 0; if (uli->rw) { locked_pid = uwsgi_rwlock_check(uli); } else { locked_pid = uwsgi_lock_check(uli); } if (locked_pid == diedpid) { uwsgi_log("[deadlock-detector] pid %d was holding lock %s (%p)\n", (int) diedpid, uli->id, uli->lock_ptr); if (uli->rw) { uwsgi_rwunlock(uli); } else { uwsgi_unlock(uli); } } nextlock: uli = uli->next; } } int uwsgi_user_lock(int lock_num) { if (lock_num < 0 || lock_num > uwsgi.locks) { return -1; } uwsgi_lock(uwsgi.user_lock[lock_num]); return 0; } int uwsgi_user_unlock(int lock_num) { if (lock_num < 0 || lock_num > uwsgi.locks) { return -1; } uwsgi_unlock(uwsgi.user_lock[lock_num]); return 0; } uwsgi-2.0.29/core/logging.000066400000000000000000000000001477626554400153330ustar00rootroot00000000000000uwsgi-2.0.29/core/logging.c000066400000000000000000001553421477626554400155220ustar00rootroot00000000000000#ifndef __DragonFly__ #include "uwsgi.h" #endif #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) #include #include #include #elif defined(__sun__) /* Terrible Hack !!! */ #ifndef _LP64 #undef _FILE_OFFSET_BITS #endif #include #define _FILE_OFFSET_BITS 64 #endif #ifdef __DragonFly__ #include "uwsgi.h" #endif extern struct uwsgi_server uwsgi; //use this instead of fprintf to avoid buffering mess with udp logging void uwsgi_log(const char *fmt, ...) { va_list ap; char logpkt[4096]; int rlen = 0; int ret; struct timeval tv; char sftime[64]; char ctime_storage[26]; time_t now; if (uwsgi.logdate) { if (uwsgi.log_strftime) { now = uwsgi_now(); rlen = strftime(sftime, 64, uwsgi.log_strftime, localtime(&now)); memcpy(logpkt, sftime, rlen); memcpy(logpkt + rlen, " - ", 3); rlen += 3; } else { gettimeofday(&tv, NULL); #if defined(__sun__) && !defined(__clang__) ctime_r((const time_t *) &tv.tv_sec, ctime_storage, 26); #else ctime_r((const time_t *) &tv.tv_sec, ctime_storage); #endif memcpy(logpkt, ctime_storage, 24); memcpy(logpkt + 24, " - ", 3); rlen = 24 + 3; } } va_start(ap, fmt); ret = vsnprintf(logpkt + rlen, 4096 - rlen, fmt, ap); va_end(ap); if (ret >= 4096) { char *tmp_buf = uwsgi_malloc(rlen + ret + 1); memcpy(tmp_buf, logpkt, rlen); va_start(ap, fmt); ret = vsnprintf(tmp_buf + rlen, ret + 1, fmt, ap); va_end(ap); rlen = write(2, tmp_buf, rlen + ret); free(tmp_buf); return; } rlen += ret; // do not check for errors rlen = write(2, logpkt, rlen); } void uwsgi_log_verbose(const char *fmt, ...) { va_list ap; char logpkt[4096]; int rlen = 0; struct timeval tv; char sftime[64]; time_t now; char ctime_storage[26]; if (uwsgi.log_strftime) { now = uwsgi_now(); rlen = strftime(sftime, 64, uwsgi.log_strftime, localtime(&now)); memcpy(logpkt, sftime, rlen); memcpy(logpkt + rlen, " - ", 3); rlen += 3; } else { gettimeofday(&tv, NULL); #if defined(__sun__) && !defined(__clang__) ctime_r((const time_t *) &tv.tv_sec, ctime_storage, 26); #else ctime_r((const time_t *) &tv.tv_sec, ctime_storage); #endif memcpy(logpkt, ctime_storage, 24); memcpy(logpkt + 24, " - ", 3); rlen = 24 + 3; } va_start(ap, fmt); rlen += vsnprintf(logpkt + rlen, 4096 - rlen, fmt, ap); va_end(ap); // do not check for errors rlen = write(2, logpkt, rlen); } /* commodity function mainly useful in log rotation */ void uwsgi_logfile_write(const char *fmt, ...) { va_list ap; char logpkt[4096]; struct timeval tv; char ctime_storage[26]; gettimeofday(&tv, NULL); #if defined(__sun__) && !defined(__clang__) ctime_r((const time_t *) &tv.tv_sec, ctime_storage, 26); #else ctime_r((const time_t *) &tv.tv_sec, ctime_storage); #endif memcpy(logpkt, ctime_storage, 24); memcpy(logpkt + 24, " - ", 3); int rlen = 24 + 3; va_start(ap, fmt); rlen += vsnprintf(logpkt + rlen, 4096 - rlen, fmt, ap); va_end(ap); // do not check for errors rlen = write(uwsgi.original_log_fd, logpkt, rlen); } static void fix_logpipe_buf(int *fd) { int so_bufsize; socklen_t so_bufsize_len = sizeof(int); if (getsockopt(fd[0], SOL_SOCKET, SO_RCVBUF, &so_bufsize, &so_bufsize_len)) { uwsgi_error("fix_logpipe_buf()/getsockopt()"); return; } if ((size_t)so_bufsize < uwsgi.log_master_bufsize) { so_bufsize = uwsgi.log_master_bufsize; if (setsockopt(fd[0], SOL_SOCKET, SO_RCVBUF, &so_bufsize, so_bufsize_len)) { uwsgi_error("fix_logpipe_buf()/setsockopt()"); } } if (getsockopt(fd[1], SOL_SOCKET, SO_SNDBUF, &so_bufsize, &so_bufsize_len)) { uwsgi_error("fix_logpipe_buf()/getsockopt()"); return; } if ((size_t)so_bufsize < uwsgi.log_master_bufsize) { so_bufsize = uwsgi.log_master_bufsize; if (setsockopt(fd[1], SOL_SOCKET, SO_SNDBUF, &so_bufsize, so_bufsize_len)) { uwsgi_error("fix_logpipe_buf()/setsockopt()"); } } } // create the logpipe void create_logpipe(void) { if (uwsgi.log_master_stream) { if (socketpair(AF_UNIX, SOCK_STREAM, 0, uwsgi.shared->worker_log_pipe)) { uwsgi_error("create_logpipe()/socketpair()\n"); exit(1); } } else { #if defined(SOCK_SEQPACKET) && defined(__linux__) if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, uwsgi.shared->worker_log_pipe)) { #else if (socketpair(AF_UNIX, SOCK_DGRAM, 0, uwsgi.shared->worker_log_pipe)) { #endif uwsgi_error("create_logpipe()/socketpair()\n"); exit(1); } fix_logpipe_buf(uwsgi.shared->worker_log_pipe); } uwsgi_socket_nb(uwsgi.shared->worker_log_pipe[0]); uwsgi_socket_nb(uwsgi.shared->worker_log_pipe[1]); if (uwsgi.shared->worker_log_pipe[1] != 1) { if (dup2(uwsgi.shared->worker_log_pipe[1], 1) < 0) { uwsgi_error("dup2()"); exit(1); } } if (dup2(1, 2) < 0) { uwsgi_error("dup2()"); exit(1); } if (uwsgi.req_log_master) { if (uwsgi.log_master_req_stream) { if (socketpair(AF_UNIX, SOCK_STREAM, 0, uwsgi.shared->worker_req_log_pipe)) { uwsgi_error("create_logpipe()/socketpair()\n"); exit(1); } } else { #if defined(SOCK_SEQPACKET) && defined(__linux__) if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, uwsgi.shared->worker_req_log_pipe)) { #else if (socketpair(AF_UNIX, SOCK_DGRAM, 0, uwsgi.shared->worker_req_log_pipe)) { #endif uwsgi_error("create_logpipe()/socketpair()\n"); exit(1); } fix_logpipe_buf(uwsgi.shared->worker_req_log_pipe); } uwsgi_socket_nb(uwsgi.shared->worker_req_log_pipe[0]); uwsgi_socket_nb(uwsgi.shared->worker_req_log_pipe[1]); uwsgi.req_log_fd = uwsgi.shared->worker_req_log_pipe[1]; } } // log to the specified file or udp address void logto(char *logfile) { int fd; char *udp_port; struct sockaddr_in udp_addr; udp_port = strchr(logfile, ':'); if (udp_port) { udp_port[0] = 0; if (!udp_port[1] || !logfile[0]) { uwsgi_log("invalid udp address\n"); exit(1); } fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { uwsgi_error("socket()"); exit(1); } memset(&udp_addr, 0, sizeof(struct sockaddr_in)); udp_addr.sin_family = AF_INET; udp_addr.sin_port = htons(atoi(udp_port + 1)); char *resolved = uwsgi_resolve_ip(logfile); if (resolved) { udp_addr.sin_addr.s_addr = inet_addr(resolved); } else { udp_addr.sin_addr.s_addr = inet_addr(logfile); } if (connect(fd, (const struct sockaddr *) &udp_addr, sizeof(struct sockaddr_in)) < 0) { uwsgi_error("connect()"); exit(1); } } else { if (uwsgi.log_truncate) { fd = open(logfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP); } else { fd = open(logfile, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP); } if (fd < 0) { uwsgi_error_open(logfile); exit(1); } uwsgi.logfile = logfile; if (uwsgi.chmod_logfile_value) { if (chmod(uwsgi.logfile, uwsgi.chmod_logfile_value)) { uwsgi_error("chmod()"); } } } // if the log-master is already active, just re-set the original_log_fd if (uwsgi.shared->worker_log_pipe[0] == -1) { /* stdout */ if (fd != 1) { if (dup2(fd, 1) < 0) { uwsgi_error("dup2()"); exit(1); } close(fd); } /* stderr */ if (dup2(1, 2) < 0) { uwsgi_error("dup2()"); exit(1); } uwsgi.original_log_fd = 2; } else { uwsgi.original_log_fd = fd; } } void uwsgi_setup_log() { uwsgi_setup_log_encoders(); if (uwsgi.daemonize) { if (uwsgi.has_emperor) { logto(uwsgi.daemonize); } else { if (!uwsgi.is_a_reload) { daemonize(uwsgi.daemonize); } else if (uwsgi.log_reopen) { logto(uwsgi.daemonize); } } } else if (uwsgi.logfile) { if (!uwsgi.is_a_reload || uwsgi.log_reopen) { logto(uwsgi.logfile); } } } static struct uwsgi_logger *setup_choosen_logger(struct uwsgi_string_list *usl) { char *id = NULL; char *name = usl->value; char *space = strchr(name, ' '); if (space) { int is_id = 1; int i; for (i = 0; i < (space - name); i++) { if (!isalnum((int)name[i])) { is_id = 0; break; } } if (is_id) { id = uwsgi_concat2n(name, space - name, "", 0); name = space + 1; } } char *colon = strchr(name, ':'); if (colon) { *colon = 0; } struct uwsgi_logger *choosen_logger = uwsgi_get_logger(name); if (!choosen_logger) { uwsgi_log("unable to find logger %s\n", name); exit(1); } // make a copy of the logger struct uwsgi_logger *copy_of_choosen_logger = uwsgi_malloc(sizeof(struct uwsgi_logger)); memcpy(copy_of_choosen_logger, choosen_logger, sizeof(struct uwsgi_logger)); choosen_logger = copy_of_choosen_logger; choosen_logger->id = id; choosen_logger->next = NULL; if (colon) { choosen_logger->arg = colon + 1; // check for empty string if (*choosen_logger->arg == 0) { choosen_logger->arg = NULL; } *colon = ':'; } return choosen_logger; } void uwsgi_setup_log_master(void) { struct uwsgi_string_list *usl = uwsgi.requested_logger; while (usl) { struct uwsgi_logger *choosen_logger = setup_choosen_logger(usl); uwsgi_append_logger(choosen_logger); usl = usl->next; } usl = uwsgi.requested_req_logger; while (usl) { struct uwsgi_logger *choosen_logger = setup_choosen_logger(usl); uwsgi_append_req_logger(choosen_logger); usl = usl->next; } #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) // set logger by its id struct uwsgi_regexp_list *url = uwsgi.log_route; while (url) { url->custom_ptr = uwsgi_get_logger_from_id(url->custom_str); url = url->next; } url = uwsgi.log_req_route; while (url) { url->custom_ptr = uwsgi_get_logger_from_id(url->custom_str); url = url->next; } #endif uwsgi.original_log_fd = dup(1); create_logpipe(); } struct uwsgi_logvar *uwsgi_logvar_get(struct wsgi_request *wsgi_req, char *key, uint8_t keylen) { struct uwsgi_logvar *lv = wsgi_req->logvars; while (lv) { if (!uwsgi_strncmp(key, keylen, lv->key, lv->keylen)) { return lv; } lv = lv->next; } return NULL; } void uwsgi_logvar_add(struct wsgi_request *wsgi_req, char *key, uint8_t keylen, char *val, uint8_t vallen) { struct uwsgi_logvar *lv = uwsgi_logvar_get(wsgi_req, key, keylen); if (lv) { memcpy(lv->val, val, vallen); lv->vallen = vallen; return; } // add a new log object lv = wsgi_req->logvars; if (lv) { while (lv) { if (!lv->next) { lv->next = uwsgi_malloc(sizeof(struct uwsgi_logvar)); lv = lv->next; break; } lv = lv->next; } } else { lv = uwsgi_malloc(sizeof(struct uwsgi_logvar)); wsgi_req->logvars = lv; } memcpy(lv->key, key, keylen); lv->keylen = keylen; memcpy(lv->val, val, vallen); lv->vallen = vallen; lv->next = NULL; } void uwsgi_check_logrotate(void) { int need_rotation = 0; int need_reopen = 0; off_t logsize; if (uwsgi.log_master) { logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR); } else { logsize = lseek(2, 0, SEEK_CUR); } if (logsize < 0) { uwsgi_error("uwsgi_check_logrotate()/lseek()"); return; } uwsgi.shared->logsize = logsize; if (uwsgi.log_maxsize > 0 && (uint64_t) uwsgi.shared->logsize > uwsgi.log_maxsize) { need_rotation = 1; } if (uwsgi_check_touches(uwsgi.touch_logrotate)) { need_rotation = 1; } if (uwsgi_check_touches(uwsgi.touch_logreopen)) { need_reopen = 1; } if (need_rotation) { uwsgi_log_rotate(); } else if (need_reopen) { uwsgi_log_reopen(); } } void uwsgi_log_do_rotate(char *logfile, char *rotatedfile, off_t logsize, int log_fd) { int need_free = 0; char *rot_name = rotatedfile; if (rot_name == NULL) { char *ts_str = uwsgi_num2str((int) uwsgi_now()); rot_name = uwsgi_concat3(logfile, ".", ts_str); free(ts_str); need_free = 1; } // this will be rawly written to the logfile uwsgi_logfile_write("logsize: %llu, triggering rotation to %s...\n", (unsigned long long) logsize, rot_name); if (rename(logfile, rot_name) == 0) { // reopen logfile and dup'it, on dup2 error, exit(1) int fd = open(logfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP); if (fd < 0) { // this will be written to the original file uwsgi_error_open(logfile); exit(1); } else { if (dup2(fd, log_fd) < 0) { // this could be lost :( uwsgi_error("uwsgi_log_do_rotate()/dup2()"); exit(1); } close(fd); } } else { uwsgi_error("unable to rotate log: rename()"); } if (need_free) free(rot_name); } void uwsgi_log_rotate() { if (!uwsgi.logfile) return; uwsgi_log_do_rotate(uwsgi.logfile, uwsgi.log_backupname, uwsgi.shared->logsize, uwsgi.original_log_fd); } void uwsgi_log_reopen() { char message[1024]; if (!uwsgi.logfile) return; int ret = snprintf(message, 1024, "[%d] logsize: %llu, triggering log-reopen...\n", (int) uwsgi_now(), (unsigned long long) uwsgi.shared->logsize); if (ret > 0 && ret < 1024) { if (write(uwsgi.original_log_fd, message, ret) != ret) { // very probably this will never be printed uwsgi_error("write()"); } } // reopen logfile; close(uwsgi.original_log_fd); uwsgi.original_log_fd = open(uwsgi.logfile, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP); if (uwsgi.original_log_fd < 0) { uwsgi_error_open(uwsgi.logfile); grace_them_all(0); return; } ret = snprintf(message, 1024, "[%d] %s reopened.\n", (int) uwsgi_now(), uwsgi.logfile); if (ret > 0 && ret < 1024) { if (write(uwsgi.original_log_fd, message, ret) != ret) { // very probably this will never be printed uwsgi_error("write()"); } } uwsgi.shared->logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR); } void log_request(struct wsgi_request *wsgi_req) { int log_it = uwsgi.logging_options.enabled; if (wsgi_req->do_not_log) return; if (wsgi_req->log_this) { goto logit; } /* conditional logging */ if (uwsgi.logging_options.zero && wsgi_req->response_size == 0) { goto logit; } if (uwsgi.logging_options.slow && (uint32_t) wsgi_req_time >= uwsgi.logging_options.slow) { goto logit; } if (uwsgi.logging_options._4xx && (wsgi_req->status >= 400 && wsgi_req->status <= 499)) { goto logit; } if (uwsgi.logging_options._5xx && (wsgi_req->status >= 500 && wsgi_req->status <= 599)) { goto logit; } if (uwsgi.logging_options.big && (wsgi_req->response_size >= uwsgi.logging_options.big)) { goto logit; } if (uwsgi.logging_options.sendfile && wsgi_req->via == UWSGI_VIA_SENDFILE) { goto logit; } if (uwsgi.logging_options.ioerror && wsgi_req->read_errors > 0 && wsgi_req->write_errors > 0) { goto logit; } if (!log_it) return; logit: uwsgi.logit(wsgi_req); } void uwsgi_logit_simple(struct wsgi_request *wsgi_req) { // optimize this (please) char time_request[26]; int rlen; int app_req = -1; char *msg2 = " "; char *via = msg2; char mempkt[4096]; char logpkt[4096]; struct iovec logvec[4]; int logvecpos = 0; const char *msecs = "msecs"; const char *micros = "micros"; char *tsize = (char *) msecs; char *msg1 = " via sendfile() "; char *msg3 = " via route() "; char *msg4 = " via offload() "; struct uwsgi_app *wi; if (wsgi_req->app_id >= 0) { wi = &uwsgi_apps[wsgi_req->app_id]; if (wi->requests > 0) { app_req = wi->requests; } } // mark requests via (sendfile, route, offload...) switch(wsgi_req->via) { case UWSGI_VIA_SENDFILE: via = msg1; break; case UWSGI_VIA_ROUTE: via = msg3; break; case UWSGI_VIA_OFFLOAD: via = msg4; break; default: break; } #if defined(__sun__) && !defined(__clang__) ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, time_request, 26); #else ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, time_request); #endif uint64_t rt = 0; // avoid overflow on clock instability (#1489) if (wsgi_req->end_of_request > wsgi_req->start_of_request) rt = wsgi_req->end_of_request - wsgi_req->start_of_request; if (uwsgi.log_micros) { tsize = (char *) micros; } else { rt /= 1000; } if (uwsgi.vhost) { logvec[logvecpos].iov_base = wsgi_req->host; logvec[logvecpos].iov_len = wsgi_req->host_len; logvecpos++; logvec[logvecpos].iov_base = " "; logvec[logvecpos].iov_len = 1; logvecpos++; } if (uwsgi.logging_options.memory_report == 1) { rlen = snprintf(mempkt, 4096, "{address space usage: %llu bytes/%lluMB} {rss usage: %llu bytes/%lluMB} ", (unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size, (unsigned long long) uwsgi.workers[uwsgi.mywid].vsz_size / 1024 / 1024, (unsigned long long) uwsgi.workers[uwsgi.mywid].rss_size, (unsigned long long) uwsgi.workers[uwsgi.mywid].rss_size / 1024 / 1024); logvec[logvecpos].iov_base = mempkt; logvec[logvecpos].iov_len = rlen; logvecpos++; } char *remote_user = wsgi_req->remote_user == NULL ? "" : wsgi_req->remote_user; rlen = snprintf(logpkt, 4096, "[pid: %d|app: %d|req: %d/%llu] %.*s (%.*s) {%d vars in %d bytes} [%.*s] %.*s %.*s => generated %llu bytes in %llu %s%s(%.*s %d) %d headers in %llu bytes (%d switches on core %d)\n", (int) uwsgi.mypid, wsgi_req->app_id, app_req, (unsigned long long) uwsgi.workers[0].requests, wsgi_req->remote_addr_len, wsgi_req->remote_addr, wsgi_req->remote_user_len, remote_user, wsgi_req->var_cnt, wsgi_req->uh->pktsize, 24, time_request, wsgi_req->method_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri, (unsigned long long) wsgi_req->response_size, (unsigned long long) rt, tsize, via, wsgi_req->protocol_len, wsgi_req->protocol, wsgi_req->status, wsgi_req->header_cnt, (unsigned long long) wsgi_req->headers_size, wsgi_req->switches, wsgi_req->async_id); // not enough space for logging the request, just log a (safe) minimal message if (rlen > 4096) { rlen = snprintf(logpkt, 4096, "[pid: %d|app: %d|req: %d/%llu] 0.0.0.0 () {%d vars in %d bytes} [%.*s] - - => generated %llu bytes in %llu %s%s(- %d) %d headers in %llu bytes (%d switches on core %d)\n", (int) uwsgi.mypid, wsgi_req->app_id, app_req, (unsigned long long) uwsgi.workers[0].requests, wsgi_req->var_cnt, wsgi_req->uh->pktsize, 24, time_request, (unsigned long long) wsgi_req->response_size, (unsigned long long) rt, tsize, via, wsgi_req->status, wsgi_req->header_cnt, (unsigned long long) wsgi_req->headers_size, wsgi_req->switches, wsgi_req->async_id); // argh, last resort, truncate it if (rlen > 4096) { rlen = 4096; } } logvec[logvecpos].iov_base = logpkt; logvec[logvecpos].iov_len = rlen; // do not check for errors rlen = writev(uwsgi.req_log_fd, logvec, logvecpos + 1); } void get_memusage(uint64_t * rss, uint64_t * vsz) { #ifdef UNBIT uint64_t ret[2]; ret[0] = 0; ret[1] = 0; syscall(358, ret); *vsz = ret[0]; *rss = ret[1] * uwsgi.page_size; #elif defined(__linux__) FILE *procfile; int i; procfile = fopen("/proc/self/stat", "r"); if (procfile) { i = fscanf(procfile, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %llu %llu", (unsigned long long *) vsz, (unsigned long long *) rss); if (i != 2) { uwsgi_log("warning: invalid record in /proc/self/stat\n"); } else { *rss = *rss * uwsgi.page_size; } fclose(procfile); } #elif defined(__CYGWIN__) // same as Linux but rss is not in pages... FILE *procfile; int i; procfile = fopen("/proc/self/stat", "r"); if (procfile) { i = fscanf(procfile, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %llu %llu", (unsigned long long *) vsz, (unsigned long long *) rss); if (i != 2) { uwsgi_log("warning: invalid record in /proc/self/stat\n"); } fclose(procfile); } #elif defined (__sun__) psinfo_t info; int procfd; procfd = open("/proc/self/psinfo", O_RDONLY); if (procfd >= 0) { if (read(procfd, (char *) &info, sizeof(info)) > 0) { *rss = (uint64_t) info.pr_rssize * 1024; *vsz = (uint64_t) info.pr_size * 1024; } close(procfd); } #elif defined(__APPLE__) /* darwin documentation says that the value are in pages, but they are bytes !!! */ struct task_basic_info t_info; mach_msg_type_number_t t_size = sizeof(struct task_basic_info); if (task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t) & t_info, &t_size) == KERN_SUCCESS) { *rss = t_info.resident_size; *vsz = t_info.virtual_size; } #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) kvm_t *kv; int cnt; #if defined(__FreeBSD__) kv = kvm_open(NULL, "/dev/null", NULL, O_RDONLY, NULL); #elif defined(__NetBSD__) || defined(__OpenBSD__) kv = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, NULL); #else kv = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL); #endif if (kv) { #if defined(__FreeBSD__) || defined(__DragonFly__) struct kinfo_proc *kproc; kproc = kvm_getprocs(kv, KERN_PROC_PID, uwsgi.mypid, &cnt); if (kproc && cnt > 0) { #if defined(__FreeBSD__) *vsz = kproc->ki_size; *rss = kproc->ki_rssize * uwsgi.page_size; #elif defined(__DragonFly__) *vsz = kproc->kp_vm_map_size; *rss = kproc->kp_vm_rssize * uwsgi.page_size; #endif } #elif defined(UWSGI_NEW_OPENBSD) struct kinfo_proc *kproc; kproc = kvm_getprocs(kv, KERN_PROC_PID, uwsgi.mypid, sizeof(struct kinfo_proc), &cnt); if (kproc && cnt > 0) { *vsz = (kproc->p_vm_dsize + kproc->p_vm_ssize + kproc->p_vm_tsize) * uwsgi.page_size; *rss = kproc->p_vm_rssize * uwsgi.page_size; } #elif defined(__NetBSD__) || defined(__OpenBSD__) struct kinfo_proc2 *kproc2; kproc2 = kvm_getproc2(kv, KERN_PROC_PID, uwsgi.mypid, sizeof(struct kinfo_proc2), &cnt); if (kproc2 && cnt > 0) { #ifdef __OpenBSD__ *vsz = (kproc2->p_vm_dsize + kproc2->p_vm_ssize + kproc2->p_vm_tsize) * uwsgi.page_size; #else *vsz = kproc2->p_vm_msize * uwsgi.page_size; #endif *rss = kproc2->p_vm_rssize * uwsgi.page_size; } #endif kvm_close(kv); } #elif defined(__HAIKU__) area_info ai; int32 cookie; *vsz = 0; *rss = 0; while (get_next_area_info(0, &cookie, &ai) == B_OK) { *vsz += ai.ram_size; if ((ai.protection & B_WRITE_AREA) != 0) { *rss += ai.ram_size; } } #endif } void uwsgi_register_logger(char *name, ssize_t(*func) (struct uwsgi_logger *, char *, size_t)) { struct uwsgi_logger *ul = uwsgi.loggers, *old_ul; if (!ul) { uwsgi.loggers = uwsgi_malloc(sizeof(struct uwsgi_logger)); ul = uwsgi.loggers; } else { while (ul) { old_ul = ul; ul = ul->next; } ul = uwsgi_malloc(sizeof(struct uwsgi_logger)); old_ul->next = ul; } ul->name = name; ul->func = func; ul->next = NULL; ul->configured = 0; ul->fd = -1; ul->data = NULL; ul->buf = NULL; #ifdef UWSGI_DEBUG uwsgi_log("[uwsgi-logger] registered \"%s\"\n", ul->name); #endif } void uwsgi_append_logger(struct uwsgi_logger *ul) { if (!uwsgi.choosen_logger) { uwsgi.choosen_logger = ul; return; } struct uwsgi_logger *ucl = uwsgi.choosen_logger; while (ucl) { if (!ucl->next) { ucl->next = ul; return; } ucl = ucl->next; } } void uwsgi_append_req_logger(struct uwsgi_logger *ul) { if (!uwsgi.choosen_req_logger) { uwsgi.choosen_req_logger = ul; return; } struct uwsgi_logger *ucl = uwsgi.choosen_req_logger; while (ucl) { if (!ucl->next) { ucl->next = ul; return; } ucl = ucl->next; } } struct uwsgi_logger *uwsgi_get_logger(char *name) { struct uwsgi_logger *ul = uwsgi.loggers; while (ul) { if (!strcmp(ul->name, name)) { return ul; } ul = ul->next; } return NULL; } struct uwsgi_logger *uwsgi_get_logger_from_id(char *id) { struct uwsgi_logger *ul = uwsgi.choosen_logger; while (ul) { if (ul->id && !strcmp(ul->id, id)) { return ul; } ul = ul->next; } return NULL; } void uwsgi_logit_lf(struct wsgi_request *wsgi_req) { struct uwsgi_logchunk *logchunk = uwsgi.logchunks; ssize_t rlen = 0; const char *empty_var = "-"; while (logchunk) { int pos = logchunk->vec; // raw string if (logchunk->type == 0) { uwsgi.logvectors[wsgi_req->async_id][pos].iov_base = logchunk->ptr; uwsgi.logvectors[wsgi_req->async_id][pos].iov_len = logchunk->len; } // offsetof else if (logchunk->type == 1) { char **var = (char **) (((char *) wsgi_req) + logchunk->pos); uint16_t *varlen = (uint16_t *) (((char *) wsgi_req) + logchunk->pos_len); uwsgi.logvectors[wsgi_req->async_id][pos].iov_base = *var; uwsgi.logvectors[wsgi_req->async_id][pos].iov_len = *varlen; } // logvar else if (logchunk->type == 2) { struct uwsgi_logvar *lv = uwsgi_logvar_get(wsgi_req, logchunk->ptr, logchunk->len); if (lv) { uwsgi.logvectors[wsgi_req->async_id][pos].iov_base = lv->val; uwsgi.logvectors[wsgi_req->async_id][pos].iov_len = lv->vallen; } else { uwsgi.logvectors[wsgi_req->async_id][pos].iov_base = NULL; uwsgi.logvectors[wsgi_req->async_id][pos].iov_len = 0; } } // func else if (logchunk->type == 3) { rlen = logchunk->func(wsgi_req, (char **) &uwsgi.logvectors[wsgi_req->async_id][pos].iov_base); if (rlen > 0) { uwsgi.logvectors[wsgi_req->async_id][pos].iov_len = rlen; } else { uwsgi.logvectors[wsgi_req->async_id][pos].iov_len = 0; } } // var else if (logchunk->type == 5) { uint16_t value_len = 0; char *value = uwsgi_get_var(wsgi_req, logchunk->ptr, logchunk->len, &value_len); // could be NULL uwsgi.logvectors[wsgi_req->async_id][pos].iov_base = value; uwsgi.logvectors[wsgi_req->async_id][pos].iov_len = (size_t) value_len; } // metric else if (logchunk->type == 4) { int64_t metric = uwsgi_metric_get(logchunk->ptr, NULL); uwsgi.logvectors[wsgi_req->async_id][pos].iov_base = uwsgi_64bit2str(metric); uwsgi.logvectors[wsgi_req->async_id][pos].iov_len = strlen(uwsgi.logvectors[wsgi_req->async_id][pos].iov_base); } if (uwsgi.logvectors[wsgi_req->async_id][pos].iov_len == 0 && logchunk->type != 0) { uwsgi.logvectors[wsgi_req->async_id][pos].iov_base = (char *) empty_var; uwsgi.logvectors[wsgi_req->async_id][pos].iov_len = 1; } logchunk = logchunk->next; } // do not check for errors rlen = writev(uwsgi.req_log_fd, uwsgi.logvectors[wsgi_req->async_id], uwsgi.logformat_vectors); // free allocated memory logchunk = uwsgi.logchunks; while (logchunk) { if (logchunk->free) { if (uwsgi.logvectors[wsgi_req->async_id][logchunk->vec].iov_len > 0) { if (uwsgi.logvectors[wsgi_req->async_id][logchunk->vec].iov_base != empty_var) { free(uwsgi.logvectors[wsgi_req->async_id][logchunk->vec].iov_base); } } } logchunk = logchunk->next; } } void uwsgi_build_log_format(char *format) { int state = 0; char *ptr = format; char *current = ptr; char *logvar = NULL; // get the number of required iovec while (*ptr) { if (*ptr == '%') { if (state == 0) { state = 1; } } // start of the variable else if (*ptr == '(') { if (state == 1) { state = 2; } } // end of the variable else if (*ptr == ')') { if (logvar) { uwsgi_add_logchunk(1, uwsgi.logformat_vectors, logvar, ptr - logvar); uwsgi.logformat_vectors++; state = 0; logvar = NULL; current = ptr + 1; } } else { if (state == 2) { uwsgi_add_logchunk(0, uwsgi.logformat_vectors, current, (ptr - current) - 2); uwsgi.logformat_vectors++; logvar = ptr; } state = 0; } ptr++; } if (ptr - current > 0) { uwsgi_add_logchunk(0, uwsgi.logformat_vectors, current, ptr - current); uwsgi.logformat_vectors++; } // +1 for "\n" uwsgi.logformat_vectors++; } static ssize_t uwsgi_lf_status(struct wsgi_request *wsgi_req, char **buf) { *buf = uwsgi_num2str(wsgi_req->status); return strlen(*buf); } static ssize_t uwsgi_lf_rsize(struct wsgi_request *wsgi_req, char **buf) { *buf = uwsgi_size2str(wsgi_req->response_size); return strlen(*buf); } static ssize_t uwsgi_lf_hsize(struct wsgi_request *wsgi_req, char **buf) { *buf = uwsgi_size2str(wsgi_req->headers_size); return strlen(*buf); } static ssize_t uwsgi_lf_size(struct wsgi_request *wsgi_req, char **buf) { *buf = uwsgi_size2str(wsgi_req->headers_size+wsgi_req->response_size); return strlen(*buf); } static ssize_t uwsgi_lf_cl(struct wsgi_request *wsgi_req, char **buf) { *buf = uwsgi_num2str(wsgi_req->post_cl); return strlen(*buf); } static ssize_t uwsgi_lf_epoch(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_num2str(uwsgi_now()); return strlen(*buf); } static ssize_t uwsgi_lf_ctime(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_malloc(26); #if defined(__sun__) && !defined(__clang__) ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, *buf, 26); #else ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, *buf); #endif return 24; } static ssize_t uwsgi_lf_time(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_num2str(wsgi_req->start_of_request / 1000000); return strlen(*buf); } static ssize_t uwsgi_lf_ltime(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_malloc(64); time_t now = wsgi_req->start_of_request / 1000000; size_t ret = strftime(*buf, 64, "%d/%b/%Y:%H:%M:%S %z", localtime(&now)); if (ret == 0) { *buf[0] = 0; return 0; } return ret; } static ssize_t uwsgi_lf_ftime(struct wsgi_request * wsgi_req, char **buf) { if (!uwsgi.logformat_strftime || !uwsgi.log_strftime) { return uwsgi_lf_ltime(wsgi_req, buf); } *buf = uwsgi_malloc(64); time_t now = wsgi_req->start_of_request / 1000000; size_t ret = strftime(*buf, 64, uwsgi.log_strftime, localtime(&now)); if (ret == 0) { *buf[0] = 0; return 0; } return ret; } static ssize_t uwsgi_lf_tmsecs(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_64bit2str(wsgi_req->start_of_request / (int64_t) 1000); return strlen(*buf); } static ssize_t uwsgi_lf_tmicros(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_64bit2str(wsgi_req->start_of_request); return strlen(*buf); } static ssize_t uwsgi_lf_micros(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_num2str(wsgi_req->end_of_request - wsgi_req->start_of_request); return strlen(*buf); } static ssize_t uwsgi_lf_msecs(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_num2str((wsgi_req->end_of_request - wsgi_req->start_of_request) / 1000); return strlen(*buf); } static ssize_t uwsgi_lf_secs(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_float2str((wsgi_req->end_of_request - wsgi_req->start_of_request) / 1000000.0); return strlen(*buf); } static ssize_t uwsgi_lf_pid(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_num2str(uwsgi.mypid); return strlen(*buf); } static ssize_t uwsgi_lf_wid(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_num2str(uwsgi.mywid); return strlen(*buf); } static ssize_t uwsgi_lf_switches(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_num2str(wsgi_req->switches); return strlen(*buf); } static ssize_t uwsgi_lf_vars(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_num2str(wsgi_req->var_cnt); return strlen(*buf); } static ssize_t uwsgi_lf_core(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_num2str(wsgi_req->async_id); return strlen(*buf); } static ssize_t uwsgi_lf_vsz(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_num2str(uwsgi.workers[uwsgi.mywid].vsz_size); return strlen(*buf); } static ssize_t uwsgi_lf_rss(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_num2str(uwsgi.workers[uwsgi.mywid].rss_size); return strlen(*buf); } static ssize_t uwsgi_lf_vszM(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_num2str(uwsgi.workers[uwsgi.mywid].vsz_size / 1024 / 1024); return strlen(*buf); } static ssize_t uwsgi_lf_rssM(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_num2str(uwsgi.workers[uwsgi.mywid].rss_size / 1024 / 1024); return strlen(*buf); } static ssize_t uwsgi_lf_pktsize(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_num2str(wsgi_req->uh->pktsize); return strlen(*buf); } static ssize_t uwsgi_lf_modifier1(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_num2str(wsgi_req->uh->modifier1); return strlen(*buf); } static ssize_t uwsgi_lf_modifier2(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_num2str(wsgi_req->uh->modifier2); return strlen(*buf); } static ssize_t uwsgi_lf_headers(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_num2str(wsgi_req->header_cnt); return strlen(*buf); } static ssize_t uwsgi_lf_werr(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_num2str((int) wsgi_req->write_errors); return strlen(*buf); } static ssize_t uwsgi_lf_rerr(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_num2str((int) wsgi_req->read_errors); return strlen(*buf); } static ssize_t uwsgi_lf_ioerr(struct wsgi_request * wsgi_req, char **buf) { *buf = uwsgi_num2str((int) (wsgi_req->write_errors + wsgi_req->read_errors)); return strlen(*buf); } struct uwsgi_logchunk *uwsgi_register_logchunk(char *name, ssize_t (*func)(struct wsgi_request *, char **), int need_free) { struct uwsgi_logchunk *old_logchunk = NULL, *logchunk = uwsgi.registered_logchunks; while(logchunk) { if (!strcmp(logchunk->name, name)) goto found; old_logchunk = logchunk; logchunk = logchunk->next; } logchunk = uwsgi_calloc(sizeof(struct uwsgi_logchunk)); logchunk->name = name; if (old_logchunk) { old_logchunk->next = logchunk; } else { uwsgi.registered_logchunks = logchunk; } found: logchunk->func = func; logchunk->free = need_free; logchunk->type = 3; return logchunk; } struct uwsgi_logchunk *uwsgi_get_logchunk_by_name(char *name, size_t name_len) { struct uwsgi_logchunk *logchunk = uwsgi.registered_logchunks; while(logchunk) { if (!uwsgi_strncmp(name, name_len, logchunk->name, strlen(logchunk->name))) { return logchunk; } logchunk = logchunk->next; } return NULL; } void uwsgi_add_logchunk(int variable, int pos, char *ptr, size_t len) { struct uwsgi_logchunk *logchunk = uwsgi.logchunks; if (logchunk) { while (logchunk) { if (!logchunk->next) { logchunk->next = uwsgi_calloc(sizeof(struct uwsgi_logchunk)); logchunk = logchunk->next; break; } logchunk = logchunk->next; } } else { uwsgi.logchunks = uwsgi_calloc(sizeof(struct uwsgi_logchunk)); logchunk = uwsgi.logchunks; } /* 0 -> raw text 1 -> offsetof variable 2 -> logvar 3 -> func 4 -> metric 5 -> request variable */ logchunk->type = variable; logchunk->vec = pos; // normal text logchunk->ptr = ptr; logchunk->len = len; // variable if (variable) { struct uwsgi_logchunk *rlc = uwsgi_get_logchunk_by_name(ptr, len); if (rlc) { if (rlc->type == 1) { logchunk->pos = rlc->pos; logchunk->pos_len = rlc->pos_len; } else if (rlc->type == 3) { logchunk->type = 3; logchunk->func = rlc->func; logchunk->free = rlc->free; } } // var else if (!uwsgi_starts_with(ptr, len, "var.", 4)) { logchunk->type = 5; logchunk->ptr = ptr+4; logchunk->len = len-4; logchunk->free = 0; } // metric else if (!uwsgi_starts_with(ptr, len, "metric.", 7)) { logchunk->type = 4; logchunk->ptr = uwsgi_concat2n(ptr+7, len - 7, "", 0); logchunk->free = 1; } // logvar else { logchunk->type = 2; } } } static void uwsgi_log_func_do(struct uwsgi_string_list *encoders, struct uwsgi_logger *ul, char *msg, size_t len) { struct uwsgi_string_list *usl = encoders; // note: msg must not be freed !!! char *new_msg = msg; size_t new_msg_len = len; while(usl) { struct uwsgi_log_encoder *ule = (struct uwsgi_log_encoder *) usl->custom_ptr; if (ule->use_for) { if (ul && ul->id) { if (strcmp(ule->use_for, ul->id)) { goto next; } } else { goto next; } } size_t rlen = 0; char *buf = ule->func(ule, new_msg, new_msg_len, &rlen); if (new_msg != msg) { free(new_msg); } new_msg = buf; new_msg_len = rlen; next: usl = usl->next; } if (ul) { ul->func(ul, new_msg, new_msg_len); } else { new_msg_len = (size_t) write(uwsgi.original_log_fd, new_msg, new_msg_len); } if (new_msg != msg) { free(new_msg); } } int uwsgi_master_log(void) { ssize_t rlen = read(uwsgi.shared->worker_log_pipe[0], uwsgi.log_master_buf, uwsgi.log_master_bufsize); if (rlen > 0) { #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) uwsgi_alarm_log_check(uwsgi.log_master_buf, rlen); struct uwsgi_regexp_list *url = uwsgi.log_drain_rules; while (url) { if (uwsgi_regexp_match(url->pattern, uwsgi.log_master_buf, rlen) >= 0) { return 0; } url = url->next; } if (uwsgi.log_filter_rules) { int show = 0; url = uwsgi.log_filter_rules; while (url) { if (uwsgi_regexp_match(url->pattern, uwsgi.log_master_buf, rlen) >= 0) { show = 1; break; } url = url->next; } if (!show) return 0; } url = uwsgi.log_route; int finish = 0; while (url) { if (uwsgi_regexp_match(url->pattern, uwsgi.log_master_buf, rlen) >= 0) { struct uwsgi_logger *ul_route = (struct uwsgi_logger *) url->custom_ptr; if (ul_route) { uwsgi_log_func_do(uwsgi.requested_log_encoders, ul_route, uwsgi.log_master_buf, rlen); finish = 1; } } url = url->next; } if (finish) return 0; #endif int raw_log = 1; struct uwsgi_logger *ul = uwsgi.choosen_logger; while (ul) { // check for named logger if (ul->id) { goto next; } uwsgi_log_func_do(uwsgi.requested_log_encoders, ul, uwsgi.log_master_buf, rlen); raw_log = 0; next: ul = ul->next; } if (raw_log) { uwsgi_log_func_do(uwsgi.requested_log_encoders, NULL, uwsgi.log_master_buf, rlen); } return 0; } return -1; } int uwsgi_master_req_log(void) { ssize_t rlen = read(uwsgi.shared->worker_req_log_pipe[0], uwsgi.log_master_buf, uwsgi.log_master_bufsize); if (rlen > 0) { #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) struct uwsgi_regexp_list *url = uwsgi.log_req_route; int finish = 0; while (url) { if (uwsgi_regexp_match(url->pattern, uwsgi.log_master_buf, rlen) >= 0) { struct uwsgi_logger *ul_route = (struct uwsgi_logger *) url->custom_ptr; if (ul_route) { uwsgi_log_func_do(uwsgi.requested_log_req_encoders, ul_route, uwsgi.log_master_buf, rlen); finish = 1; } } url = url->next; } if (finish) return 0; #endif int raw_log = 1; struct uwsgi_logger *ul = uwsgi.choosen_req_logger; while (ul) { // check for named logger if (ul->id) { goto next; } uwsgi_log_func_do(uwsgi.requested_log_req_encoders, ul, uwsgi.log_master_buf, rlen); raw_log = 0; next: ul = ul->next; } if (raw_log) { uwsgi_log_func_do(uwsgi.requested_log_req_encoders, NULL, uwsgi.log_master_buf, rlen); } return 0; } return -1; } static void *logger_thread_loop(void *noarg) { struct pollfd logpoll[2]; // block all signals sigset_t smask; sigfillset(&smask); pthread_sigmask(SIG_BLOCK, &smask, NULL); logpoll[0].events = POLLIN; logpoll[0].fd = uwsgi.shared->worker_log_pipe[0]; int logpolls = 1; if (uwsgi.req_log_master) { logpoll[1].events = POLLIN; logpoll[1].fd = uwsgi.shared->worker_req_log_pipe[0]; logpolls++; } for (;;) { int ret = poll(logpoll, logpolls, -1); if (ret > 0) { if (logpoll[0].revents & POLLIN) { pthread_mutex_lock(&uwsgi.threaded_logger_lock); uwsgi_master_log(); pthread_mutex_unlock(&uwsgi.threaded_logger_lock); } else if (logpolls > 1 && logpoll[1].revents & POLLIN) { pthread_mutex_lock(&uwsgi.threaded_logger_lock); uwsgi_master_req_log(); pthread_mutex_unlock(&uwsgi.threaded_logger_lock); } } } return NULL; } void uwsgi_threaded_logger_spawn() { pthread_t logger_thread; if (pthread_create(&logger_thread, NULL, logger_thread_loop, NULL)) { uwsgi_error("pthread_create()"); uwsgi_log("falling back to non-threaded logger...\n"); event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_log_pipe[0]); if (uwsgi.req_log_master) { event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_req_log_pipe[0]); } uwsgi.threaded_logger = 0; } } void uwsgi_register_log_encoder(char *name, char *(*func)(struct uwsgi_log_encoder *, char *, size_t, size_t *)) { struct uwsgi_log_encoder *old_ule = NULL, *ule = uwsgi.log_encoders; while(ule) { if (!strcmp(ule->name, name)) { ule->func = func; return; } old_ule = ule; ule = ule->next; } ule = uwsgi_calloc(sizeof(struct uwsgi_log_encoder)); ule->name = name; ule->func = func; if (old_ule) { old_ule->next = ule; } else { uwsgi.log_encoders = ule; } } struct uwsgi_log_encoder *uwsgi_log_encoder_by_name(char *name) { struct uwsgi_log_encoder *ule = uwsgi.log_encoders; while(ule) { if (!strcmp(name, ule->name)) return ule; ule = ule->next; } return NULL; } void uwsgi_setup_log_encoders() { struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, uwsgi.requested_log_encoders) { char *space = strchr(usl->value, ' '); if (space) *space = 0; char *use_for = strchr(usl->value, ':'); if (use_for) *use_for = 0; struct uwsgi_log_encoder *ule = uwsgi_log_encoder_by_name(usl->value); if (!ule) { uwsgi_log("log encoder \"%s\" not found\n", usl->value); exit(1); } struct uwsgi_log_encoder *ule2 = uwsgi_malloc(sizeof(struct uwsgi_log_encoder)); memcpy(ule2, ule, sizeof(struct uwsgi_log_encoder)); if (use_for) { ule2->use_for = uwsgi_str(use_for+1); *use_for = ':'; } // we use a copy if (space) { *space = ' '; ule2->args = uwsgi_str(space+1); } else { ule2->args = uwsgi_str(""); } usl->custom_ptr = ule2; uwsgi_log("[log-encoder] registered %s\n", usl->value); } uwsgi_foreach(usl, uwsgi.requested_log_req_encoders) { char *space = strchr(usl->value, ' '); if (space) *space = 0; char *use_for = strchr(usl->value, ':'); if (use_for) *use_for = 0; struct uwsgi_log_encoder *ule = uwsgi_log_encoder_by_name(usl->value); if (!ule) { uwsgi_log("log encoder \"%s\" not found\n", usl->value); exit(1); } struct uwsgi_log_encoder *ule2 = uwsgi_malloc(sizeof(struct uwsgi_log_encoder)); memcpy(ule2, ule, sizeof(struct uwsgi_log_encoder)); if (use_for) { ule2->use_for = uwsgi_str(use_for+1); *use_for = ':'; } // we use a copy if (space) { *space = ' '; ule2->args = uwsgi_str(space+1); } else { ule2->args = uwsgi_str(""); } usl->custom_ptr = ule2; uwsgi_log("[log-req-encoder] registered %s\n", usl->value); } } #ifdef UWSGI_ZLIB static char *uwsgi_log_encoder_gzip(struct uwsgi_log_encoder *ule, char *msg, size_t len, size_t *rlen) { struct uwsgi_buffer *ub = uwsgi_gzip(msg, len); if (!ub) return NULL; *rlen = ub->pos; // avoid destruction char *buf = ub->buf; ub->buf = NULL; uwsgi_buffer_destroy(ub); return buf; } static char *uwsgi_log_encoder_compress(struct uwsgi_log_encoder *ule, char *msg, size_t len, size_t *rlen) { size_t c_len = (size_t) compressBound(len); uLongf destLen = c_len; char *buf = uwsgi_malloc(c_len); if (compress((Bytef *) buf, &destLen, (Bytef *)msg, (uLong) len) == Z_OK) { *rlen = destLen; return buf; } free(buf); return NULL; } #endif /* really fast encoder adding only a prefix */ static char *uwsgi_log_encoder_prefix(struct uwsgi_log_encoder *ule, char *msg, size_t len, size_t *rlen) { char *buf = NULL; struct uwsgi_buffer *ub = uwsgi_buffer_new(len + strlen(ule->args)); if (uwsgi_buffer_append(ub, ule->args, strlen(ule->args))) goto end; if (uwsgi_buffer_append(ub, msg, len)) goto end; *rlen = ub->pos; buf = ub->buf; ub->buf = NULL; end: uwsgi_buffer_destroy(ub); return buf; } /* really fast encoder adding only a newline */ static char *uwsgi_log_encoder_nl(struct uwsgi_log_encoder *ule, char *msg, size_t len, size_t *rlen) { char *buf = NULL; struct uwsgi_buffer *ub = uwsgi_buffer_new(len + 1); if (uwsgi_buffer_append(ub, msg, len)) goto end; if (uwsgi_buffer_byte(ub, '\n')) goto end; *rlen = ub->pos; buf = ub->buf; ub->buf = NULL; end: uwsgi_buffer_destroy(ub); return buf; } /* really fast encoder adding only a suffix */ static char *uwsgi_log_encoder_suffix(struct uwsgi_log_encoder *ule, char *msg, size_t len, size_t *rlen) { char *buf = NULL; struct uwsgi_buffer *ub = uwsgi_buffer_new(len + strlen(ule->args)); if (uwsgi_buffer_append(ub, msg, len)) goto end; if (uwsgi_buffer_append(ub, ule->args, strlen(ule->args))) goto end; *rlen = ub->pos; buf = ub->buf; ub->buf = NULL; end: uwsgi_buffer_destroy(ub); return buf; } void uwsgi_log_encoder_parse_vars(struct uwsgi_log_encoder *ule) { char *ptr = ule->args; size_t remains = strlen(ptr); char *base = ptr; size_t base_len = 0; char *var = NULL; size_t var_len = 0; int status = 0; // 1 -> $ 2-> { end -> } while(remains--) { char b = *ptr++; if (status == 1) { if (b == '{') { status = 2; continue; } base_len+=2; status = 0; continue; } else if (status == 2) { if (b == '}') { status = 0; uwsgi_string_new_list((struct uwsgi_string_list **) &ule->data, uwsgi_concat2n(base, base_len, "", 0)); struct uwsgi_string_list *usl = uwsgi_string_new_list((struct uwsgi_string_list **) &ule->data, uwsgi_concat2n(var, var_len, "", 0)); usl->custom = 1; var = NULL; var_len = 0; base = NULL; base_len = 0; continue; } if (!var) var = (ptr-1); var_len++; continue; } // status == 0 if (b == '$') { status = 1; } else { if (!base) base = (ptr-1); base_len++; } } if (base) { if (status == 1) { base_len+=2; } else if (status == 2) { base_len+=3; } uwsgi_string_new_list((struct uwsgi_string_list **) &ule->data, uwsgi_concat2n(base, base_len, "", 0)); } } /* // format: foo ${var} bar msg (the logline) msgnl (the logline with newline) unix (the time_t value) micros (current microseconds) strftime (strftime) */ static char *uwsgi_log_encoder_format(struct uwsgi_log_encoder *ule, char *msg, size_t len, size_t *rlen) { if (!ule->configured) { uwsgi_log_encoder_parse_vars(ule); ule->configured = 1; } struct uwsgi_buffer *ub = uwsgi_buffer_new(strlen(ule->args) + len); struct uwsgi_string_list *usl = (struct uwsgi_string_list *) ule->data; char *buf = NULL; while(usl) { if (usl->custom) { if (!uwsgi_strncmp(usl->value, usl->len, "msg", 3)) { if (msg[len-1] == '\n') { if (uwsgi_buffer_append(ub, msg, len-1)) goto end; } else { if (uwsgi_buffer_append(ub, msg, len)) goto end; } } else if (!uwsgi_strncmp(usl->value, usl->len, "msgnl", 5)) { if (uwsgi_buffer_append(ub, msg, len)) goto end; } else if (!uwsgi_strncmp(usl->value, usl->len, "unix", 4)) { if (uwsgi_buffer_num64(ub, uwsgi_now())) goto end; } else if (!uwsgi_strncmp(usl->value, usl->len, "micros", 6)) { if (uwsgi_buffer_num64(ub, uwsgi_micros())) goto end; } else if (!uwsgi_strncmp(usl->value, usl->len, "millis", 6)) { if (uwsgi_buffer_num64(ub, uwsgi_millis())) goto end; } else if (!uwsgi_starts_with(usl->value, usl->len, "strftime:", 9)) { char sftime[64]; time_t now = uwsgi_now(); char *buf = uwsgi_concat2n(usl->value+9, usl->len-9,"", 0); int strftime_len = strftime(sftime, 64, buf, localtime(&now)); free(buf); if (strftime_len > 0) { if (uwsgi_buffer_append(ub, sftime, strftime_len)) goto end; } } } else { if (uwsgi_buffer_append(ub, usl->value, usl->len)) goto end; } usl = usl->next; } buf = ub->buf; *rlen = ub->pos; ub->buf = NULL; end: uwsgi_buffer_destroy(ub); return buf; } static char *uwsgi_log_encoder_json(struct uwsgi_log_encoder *ule, char *msg, size_t len, size_t *rlen) { if (!ule->configured) { uwsgi_log_encoder_parse_vars(ule); ule->configured = 1; } struct uwsgi_buffer *ub = uwsgi_buffer_new(strlen(ule->args) + len); struct uwsgi_string_list *usl = (struct uwsgi_string_list *) ule->data; char *buf = NULL; while(usl) { if (usl->custom) { if (!uwsgi_strncmp(usl->value, usl->len, "msg", 3)) { size_t msg_len = len; if (msg[len-1] == '\n') msg_len--; char *e_json = uwsgi_malloc((msg_len * 2)+1); escape_json(msg, msg_len, e_json); if (uwsgi_buffer_append(ub, e_json, strlen(e_json))){ free(e_json); goto end; } free(e_json); } else if (!uwsgi_strncmp(usl->value, usl->len, "msgnl", 5)) { char *e_json = uwsgi_malloc((len * 2)+1); escape_json(msg, len, e_json); if (uwsgi_buffer_append(ub, e_json, strlen(e_json))){ free(e_json); goto end; } free(e_json); } else if (!uwsgi_strncmp(usl->value, usl->len, "unix", 4)) { if (uwsgi_buffer_num64(ub, uwsgi_now())) goto end; } else if (!uwsgi_strncmp(usl->value, usl->len, "micros", 6)) { if (uwsgi_buffer_num64(ub, uwsgi_micros())) goto end; } else if (!uwsgi_strncmp(usl->value, usl->len, "millis", 6)) { if (uwsgi_buffer_num64(ub, uwsgi_millis())) goto end; } else if (!uwsgi_starts_with(usl->value, usl->len, "strftime:", 9)) { char sftime[64]; time_t now = uwsgi_now(); char *buf = uwsgi_concat2n(usl->value+9, usl->len-9, "", 0); int strftime_len = strftime(sftime, 64, buf, localtime(&now)); free(buf); if (strftime_len > 0) { char *e_json = uwsgi_malloc((strftime_len * 2)+1); escape_json(sftime, strftime_len, e_json); if (uwsgi_buffer_append(ub, e_json, strlen(e_json))){ free(e_json); goto end; } free(e_json); } } } else { if (uwsgi_buffer_append(ub, usl->value, usl->len)) goto end; } usl = usl->next; } buf = ub->buf; *rlen = ub->pos; ub->buf = NULL; end: uwsgi_buffer_destroy(ub); return buf; } #define r_logchunk(x) uwsgi_register_logchunk(#x, uwsgi_lf_ ## x, 1) #define r_logchunk_offset(x, y) { struct uwsgi_logchunk *lc = uwsgi_register_logchunk(#x, NULL, 0); lc->pos = offsetof(struct wsgi_request, y); lc->pos_len = offsetof(struct wsgi_request, y ## _len); lc->type = 1; lc->free=0;} void uwsgi_register_logchunks() { // offsets r_logchunk_offset(uri, uri); r_logchunk_offset(method, method); r_logchunk_offset(user, remote_user); r_logchunk_offset(addr, remote_addr); r_logchunk_offset(host, host); r_logchunk_offset(proto, protocol); r_logchunk_offset(uagent, user_agent); r_logchunk_offset(referer, referer); // funcs r_logchunk(status); r_logchunk(rsize); r_logchunk(hsize); r_logchunk(size); r_logchunk(cl); r_logchunk(micros); r_logchunk(msecs); r_logchunk(secs); r_logchunk(tmsecs); r_logchunk(tmicros); r_logchunk(time); r_logchunk(ltime); r_logchunk(ftime); r_logchunk(ctime); r_logchunk(epoch); r_logchunk(pid); r_logchunk(wid); r_logchunk(switches); r_logchunk(vars); r_logchunk(core); r_logchunk(vsz); r_logchunk(rss); r_logchunk(vszM); r_logchunk(rssM); r_logchunk(pktsize); r_logchunk(modifier1); r_logchunk(modifier2); r_logchunk(headers); r_logchunk(werr); r_logchunk(rerr); r_logchunk(ioerr); } void uwsgi_log_encoders_register_embedded() { uwsgi_register_log_encoder("prefix", uwsgi_log_encoder_prefix); uwsgi_register_log_encoder("suffix", uwsgi_log_encoder_suffix); uwsgi_register_log_encoder("nl", uwsgi_log_encoder_nl); uwsgi_register_log_encoder("format", uwsgi_log_encoder_format); uwsgi_register_log_encoder("json", uwsgi_log_encoder_json); #ifdef UWSGI_ZLIB uwsgi_register_log_encoder("gzip", uwsgi_log_encoder_gzip); uwsgi_register_log_encoder("compress", uwsgi_log_encoder_compress); #endif } uwsgi-2.0.29/core/loop.c000066400000000000000000000070411477626554400150350ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; struct wsgi_request *threaded_current_wsgi_req() { return pthread_getspecific(uwsgi.tur_key); } struct wsgi_request *simple_current_wsgi_req() { return uwsgi.wsgi_req; } void uwsgi_register_loop(char *name, void (*func) (void)) { struct uwsgi_loop *old_loop = NULL, *loop = uwsgi.loops; while (loop) { // check if the loop engine is already registered if (!strcmp(name, loop->name)) return; old_loop = loop; loop = loop->next; } loop = uwsgi_calloc(sizeof(struct uwsgi_loop)); loop->name = name; loop->loop = func; if (old_loop) { old_loop->next = loop; } else { uwsgi.loops = loop; } } void *uwsgi_get_loop(char *name) { struct uwsgi_loop *loop = uwsgi.loops; while (loop) { if (!strcmp(name, loop->name)) { return loop->loop; } loop = loop->next; } return NULL; } /* this is the default (simple) loop. it will run simple_loop_run function for each spawned thread simple_loop_run monitors sockets and signals descriptors and manages them. */ void simple_loop() { uwsgi_loop_cores_run(simple_loop_run); // Other threads may still run. Make sure they will stop. uwsgi.workers[uwsgi.mywid].manage_next_request = 0; if (uwsgi.workers[uwsgi.mywid].shutdown_sockets) uwsgi_shutdown_all_sockets(); } void uwsgi_loop_cores_run(void *(*func) (void *)) { int i; for (i = 1; i < uwsgi.threads; i++) { long j = i; pthread_create(&uwsgi.workers[uwsgi.mywid].cores[i].thread_id, &uwsgi.threads_attr, func, (void *) j); } long y = 0; func((void *) y); } void uwsgi_setup_thread_req(long core_id, struct wsgi_request *wsgi_req) { int i; sigset_t smask; pthread_setspecific(uwsgi.tur_key, (void *) wsgi_req); if (core_id > 0) { // block all signals on new threads sigfillset(&smask); #ifdef UWSGI_DEBUG sigdelset(&smask, SIGSEGV); #endif pthread_sigmask(SIG_BLOCK, &smask, NULL); // run per-thread socket hook struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->proto_thread_fixup) { uwsgi_sock->proto_thread_fixup(uwsgi_sock, core_id); } uwsgi_sock = uwsgi_sock->next; } for (i = 0; i < 256; i++) { if (uwsgi.p[i]->init_thread) { uwsgi.p[i]->init_thread(core_id); } } } } void simple_loop_run_int(int core_id) { long y = core_id; simple_loop_run((void *) y); } void *simple_loop_run(void *arg1) { long core_id = (long) arg1; struct wsgi_request *wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[core_id].req; if (uwsgi.threads > 1) { uwsgi_setup_thread_req(core_id, wsgi_req); } // initialize the main event queue to monitor sockets int main_queue = event_queue_init(); uwsgi_add_sockets_to_queue(main_queue, core_id); event_queue_add_fd_read(main_queue, uwsgi.loop_stop_pipe[0]); if (uwsgi.signal_socket > -1) { event_queue_add_fd_read(main_queue, uwsgi.signal_socket); event_queue_add_fd_read(main_queue, uwsgi.my_signal_socket); } // ok we are ready, let's start managing requests and signals while (uwsgi.workers[uwsgi.mywid].manage_next_request) { wsgi_req_setup(wsgi_req, core_id, NULL); if (wsgi_req_accept(main_queue, wsgi_req)) { continue; } if (wsgi_req_recv(main_queue, wsgi_req)) { uwsgi_destroy_request(wsgi_req); continue; } uwsgi_close_request(wsgi_req); } // end of the loop if (uwsgi.workers[uwsgi.mywid].destroy && uwsgi.workers[0].pid > 0) { #ifdef __APPLE__ kill(uwsgi.workers[0].pid, SIGTERM); #else if (uwsgi.propagate_touch) { kill(uwsgi.workers[0].pid, SIGHUP); } else { gracefully_kill(0); } #endif } return NULL; } uwsgi-2.0.29/core/master.c000066400000000000000000001000401477626554400153500ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; void uwsgi_update_load_counters() { int i; uint64_t busy_workers = 0; uint64_t idle_workers = 0; static time_t last_sos = 0; for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) { if (uwsgi_worker_is_busy(i) == 0) { idle_workers++; } else { busy_workers++; } } } if (busy_workers >= (uint64_t) uwsgi.numproc) { ushared->overloaded++; if (uwsgi.vassal_sos) { if (uwsgi.current_time - last_sos > uwsgi.vassal_sos) { uwsgi_log_verbose("asking Emperor for reinforcements (overload: %llu)...\n", (unsigned long long) ushared->overloaded); vassal_sos(); last_sos = uwsgi.current_time; } } } ushared->busy_workers = busy_workers; ushared->idle_workers = idle_workers; } void uwsgi_block_signal(int signum) { sigset_t smask; sigemptyset(&smask); sigaddset(&smask, signum); if (sigprocmask(SIG_BLOCK, &smask, NULL)) { uwsgi_error("sigprocmask()"); } } void uwsgi_unblock_signal(int signum) { sigset_t smask; sigemptyset(&smask); sigaddset(&smask, signum); if (sigprocmask(SIG_UNBLOCK, &smask, NULL)) { uwsgi_error("sigprocmask()"); } } void uwsgi_master_manage_udp(int udp_fd) { char buf[4096]; struct sockaddr_in udp_client; char udp_client_addr[16]; int i; socklen_t udp_len = sizeof(udp_client); ssize_t rlen = recvfrom(udp_fd, buf, 4096, 0, (struct sockaddr *) &udp_client, &udp_len); if (rlen < 0) { uwsgi_error("uwsgi_master_manage_udp()/recvfrom()"); } else if (rlen > 0) { memset(udp_client_addr, 0, 16); if (inet_ntop(AF_INET, &udp_client.sin_addr.s_addr, udp_client_addr, 16)) { if (buf[0] == UWSGI_MODIFIER_MULTICAST_ANNOUNCE) { } else if (buf[0] == 0x30 && uwsgi.snmp) { manage_snmp(udp_fd, (uint8_t *) buf, rlen, &udp_client); } else { // loop the various udp manager until one returns true int udp_managed = 0; for (i = 0; i < 256; i++) { if (uwsgi.p[i]->manage_udp) { if (uwsgi.p[i]->manage_udp(udp_client_addr, udp_client.sin_port, buf, rlen)) { udp_managed = 1; break; } } } // else a simple udp logger if (!udp_managed) { uwsgi_log("[udp:%s:%d] %.*s", udp_client_addr, ntohs(udp_client.sin_port), (int) rlen, buf); } } } else { uwsgi_error("uwsgi_master_manage_udp()/inet_ntop()"); } } } void suspend_resume_them_all(int signum) { int i; int suspend = 0; if (uwsgi.workers[0].suspended == 1) { uwsgi_log_verbose("*** (SIGTSTP received) resuming workers ***\n"); uwsgi.workers[0].suspended = 0; } else { uwsgi_log_verbose("*** PAUSE (press start to resume, if you do not have a joypad send SIGTSTP) ***\n"); suspend = 1; uwsgi.workers[0].suspended = 1; } // subscribe/unsubscribe if needed uwsgi_subscribe_all(suspend, 1); for (i = 1; i <= uwsgi.numproc; i++) { uwsgi.workers[i].suspended = suspend; if (uwsgi.workers[i].pid > 0) { if (kill(uwsgi.workers[i].pid, SIGTSTP)) { uwsgi_error("kill()"); } } } } void uwsgi_master_check_mercy() { int i; for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cursed_at) { if (uwsgi_now() > uwsgi.workers[i].no_mercy_at) { uwsgi_log_verbose("worker %d (pid: %d) is taking too much time to die...NO MERCY !!!\n", i, uwsgi.workers[i].pid); // yes that look strangem but we avoid callign it again if we skip waitpid() call below uwsgi_curse(i, SIGKILL); } } } for (i = 0; i < uwsgi.mules_cnt; i++) { if (uwsgi.mules[i].pid > 0 && uwsgi.mules[i].cursed_at) { if (uwsgi_now() > uwsgi.mules[i].no_mercy_at) { uwsgi_log_verbose("mule %d (pid: %d) is taking too much time to die...NO MERCY !!!\n", i + 1, uwsgi.mules[i].pid); uwsgi_curse_mule(i, SIGKILL); } } } struct uwsgi_spooler *us; for (us = uwsgi.spoolers; us; us = us->next) { if (us->pid > 0 && us->cursed_at && uwsgi_now() > us->no_mercy_at) { uwsgi_log_verbose("spooler %d (pid: %d) is taking too much time to die...NO MERCY !!!\n", i + 1, us->pid); kill(us->pid, SIGKILL); } } } void expire_rb_timeouts(struct uwsgi_rbtree *tree) { uint64_t current = (uint64_t) uwsgi_now(); struct uwsgi_rb_timer *urbt; struct uwsgi_signal_rb_timer *usrbt; for (;;) { urbt = uwsgi_min_rb_timer(tree, NULL); if (urbt == NULL) return; if (urbt->value <= current) { // remove the timeout and add another usrbt = (struct uwsgi_signal_rb_timer *) urbt->data; uwsgi_del_rb_timer(tree, urbt); free(urbt); usrbt->iterations_done++; uwsgi_route_signal(usrbt->sig); if (!usrbt->iterations || usrbt->iterations_done < usrbt->iterations) { usrbt->uwsgi_rb_timer = uwsgi_add_rb_timer(tree, uwsgi_now() + usrbt->value, usrbt); } continue; } break; } } static void get_tcp_info(struct uwsgi_socket *uwsgi_sock) { #if defined(__linux__) || defined(__FreeBSD__) int fd = uwsgi_sock->fd; struct tcp_info ti; socklen_t tis = sizeof(struct tcp_info); if (!getsockopt(fd, IPPROTO_TCP, TCP_INFO, &ti, &tis)) { // checks for older kernels #if defined(__linux__) if (!ti.tcpi_sacked) { #elif defined(__FreeBSD__) if (!ti.__tcpi_sacked) { #endif return; } #if defined(__linux__) uwsgi_sock->queue = (uint64_t) ti.tcpi_unacked; uwsgi_sock->max_queue = (uint64_t) ti.tcpi_sacked; #elif defined(__FreeBSD__) uwsgi_sock->queue = (uint64_t) ti.__tcpi_unacked; uwsgi_sock->max_queue = (uint64_t) ti.__tcpi_sacked; #endif } #endif } #ifdef __linux__ #include #ifdef UNBIT #define SIOBKLGQ 0x8908 #endif #ifdef SIOBKLGQ static void get_linux_unbit_SIOBKLGQ(struct uwsgi_socket *uwsgi_sock) { int fd = uwsgi_sock->fd; int queue = 0; if (ioctl(fd, SIOBKLGQ, &queue) >= 0) { uwsgi_sock->queue = (uint64_t) queue; uwsgi_sock->max_queue = (uint64_t) uwsgi.listen_queue; } } #endif #endif static void master_check_listen_queue() { uint64_t backlog = 0; struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while(uwsgi_sock) { if (uwsgi_sock->family == AF_INET || uwsgi_sock->family == AF_INET6) { get_tcp_info(uwsgi_sock); } #ifdef __linux__ #ifdef SIOBKLGQ else if (uwsgi_sock->family == AF_UNIX) { get_linux_unbit_SIOBKLGQ(uwsgi_sock); } #endif #endif if (uwsgi_sock->queue > backlog) { backlog = uwsgi_sock->queue; } if (uwsgi_sock->queue > 0 && uwsgi_sock->queue >= uwsgi_sock->max_queue) { uwsgi_log_verbose("*** uWSGI listen queue of socket \"%s\" (fd: %d) full !!! (%llu/%llu) ***\n", uwsgi_sock->name, uwsgi_sock->fd, (unsigned long long) uwsgi_sock->queue, (unsigned long long) uwsgi_sock->max_queue); if (uwsgi.alarm_backlog) { char buf[1024]; int ret = snprintf(buf, 1024, "listen queue of socket \"%s\" (fd: %d) full !!! (%llu/%llu)", uwsgi_sock->name, uwsgi_sock->fd, (unsigned long long) uwsgi_sock->queue, (unsigned long long) uwsgi_sock->max_queue); if (ret > 0 && ret < 1024) { struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, uwsgi.alarm_backlog) { uwsgi_alarm_trigger(usl->value, buf, ret); } } } } uwsgi_sock = uwsgi_sock->next; } // TODO load should be something more advanced based on different values uwsgi.shared->load = backlog; uwsgi.shared->backlog = backlog; if (uwsgi.vassal_sos_backlog > 0 && uwsgi.has_emperor) { if (uwsgi.shared->backlog >= (uint64_t) uwsgi.vassal_sos_backlog) { // ask emperor for help uwsgi_log_verbose("asking Emperor for reinforcements (backlog: %llu)...\n", (unsigned long long) uwsgi.shared->backlog); vassal_sos(); } } } void vassal_sos() { if (!uwsgi.has_emperor) { uwsgi_log("[broodlord] instance not governed by an Emperor !!!\n"); return; } char byte = 30; if (write(uwsgi.emperor_fd, &byte, 1) != 1) { uwsgi_error("vassal_sos()/write()"); } } int master_loop(char **argv, char **environ) { struct timeval last_respawn; int last_respawn_rate = 0; pid_t diedpid; int waitpid_status; time_t now = 0; int i = 0; int rlen; int check_interval = 1; struct uwsgi_rb_timer *min_timeout; struct uwsgi_rbtree *rb_timers = uwsgi_init_rb_timer(); if (uwsgi.procname_master) { uwsgi_set_processname(uwsgi.procname_master); } else if (uwsgi.procname) { uwsgi_set_processname(uwsgi.procname); } else if (uwsgi.auto_procname) { uwsgi_set_processname("uWSGI master"); } uwsgi.current_time = uwsgi_now(); uwsgi_unix_signal(SIGTSTP, suspend_resume_them_all); uwsgi_unix_signal(SIGHUP, grace_them_all); if (uwsgi.die_on_term) { uwsgi_unix_signal(SIGTERM, kill_them_all); uwsgi_unix_signal(SIGQUIT, reap_them_all); } else { uwsgi_unix_signal(SIGTERM, reap_them_all); uwsgi_unix_signal(SIGQUIT, kill_them_all); } uwsgi_unix_signal(SIGINT, kill_them_all); uwsgi_unix_signal(SIGUSR1, stats); atexit(uwsgi_master_cleanup_hooks); uwsgi.master_queue = event_queue_init(); /* route signals to workers... */ #ifdef UWSGI_DEBUG uwsgi_log("adding %d to signal poll\n", uwsgi.shared->worker_signal_pipe[0]); #endif event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_signal_pipe[0]); if (uwsgi.master_fifo) { uwsgi.master_fifo_fd = uwsgi_master_fifo(); event_queue_add_fd_read(uwsgi.master_queue, uwsgi.master_fifo_fd); } if (uwsgi.notify_socket) { uwsgi.notify_socket_fd = bind_to_unix_dgram(uwsgi.notify_socket); uwsgi_log("notification socket enabled on %s (fd: %d)\n", uwsgi.notify_socket, uwsgi.notify_socket_fd); event_queue_add_fd_read(uwsgi.master_queue, uwsgi.notify_socket_fd); } if (uwsgi.spoolers) { event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->spooler_signal_pipe[0]); } if (uwsgi.mules_cnt > 0) { event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->mule_signal_pipe[0]); } if (uwsgi.log_master) { uwsgi.log_master_buf = uwsgi_malloc(uwsgi.log_master_bufsize); if (!uwsgi.threaded_logger) { #ifdef UWSGI_DEBUG uwsgi_log("adding %d to master logging\n", uwsgi.shared->worker_log_pipe[0]); #endif event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_log_pipe[0]); if (uwsgi.req_log_master) { event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_req_log_pipe[0]); } } else { uwsgi_threaded_logger_spawn(); } } #ifdef UWSGI_SSL uwsgi_start_legions(); #endif uwsgi_metrics_start_collector(); uwsgi_add_reload_fds(); uwsgi_cache_start_sweepers(); uwsgi_cache_start_sync_servers(); uwsgi.wsgi_req->buffer = uwsgi.workers[0].cores[0].buffer; if (uwsgi.has_emperor) { if (uwsgi.emperor_proxy) { uwsgi.emperor_fd_proxy = bind_to_unix(uwsgi.emperor_proxy, uwsgi.listen_queue, 0, 0); if (uwsgi.emperor_fd_proxy < 0) exit(1); if (chmod(uwsgi.emperor_proxy, S_IRUSR|S_IWUSR)) { uwsgi_error("[emperor-proxy] chmod()"); exit(1); } event_queue_add_fd_read(uwsgi.master_queue, uwsgi.emperor_fd_proxy); } else { event_queue_add_fd_read(uwsgi.master_queue, uwsgi.emperor_fd); } } #ifdef __linux__ if (uwsgi.setns_socket) { uwsgi.setns_socket_fd = bind_to_unix(uwsgi.setns_socket, uwsgi.listen_queue, 0, 0); if (uwsgi.setns_socket_fd < 0) exit(1); if (chmod(uwsgi.setns_socket, S_IRUSR|S_IWUSR)) { uwsgi_error("[setns-socket] chmod()"); exit(1); } event_queue_add_fd_read(uwsgi.master_queue, uwsgi.setns_socket_fd); } #endif if (uwsgi.zerg_server) { uwsgi.zerg_server_fd = bind_to_unix(uwsgi.zerg_server, uwsgi.listen_queue, 0, 0); event_queue_add_fd_read(uwsgi.master_queue, uwsgi.zerg_server_fd); uwsgi_log("*** Zerg server enabled on %s ***\n", uwsgi.zerg_server); } if (uwsgi.stats) { char *tcp_port = strrchr(uwsgi.stats, ':'); if (tcp_port) { // disable deferred accept for this socket int current_defer_accept = uwsgi.no_defer_accept; uwsgi.no_defer_accept = 1; uwsgi.stats_fd = bind_to_tcp(uwsgi.stats, uwsgi.listen_queue, tcp_port); uwsgi.no_defer_accept = current_defer_accept; } else { uwsgi.stats_fd = bind_to_unix(uwsgi.stats, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); } event_queue_add_fd_read(uwsgi.master_queue, uwsgi.stats_fd); uwsgi_log("*** Stats server enabled on %s fd: %d ***\n", uwsgi.stats, uwsgi.stats_fd); } if (uwsgi.stats_pusher_instances) { if (!uwsgi_thread_new(uwsgi_stats_pusher_loop)) { uwsgi_log("!!! unable to spawn stats pusher thread !!!\n"); exit(1); } } if (uwsgi.udp_socket) { uwsgi.udp_fd = bind_to_udp(uwsgi.udp_socket, 0, 0); if (uwsgi.udp_fd < 0) { uwsgi_log("unable to bind to udp socket. SNMP services will be disabled.\n"); } else { uwsgi_log("UDP server enabled.\n"); event_queue_add_fd_read(uwsgi.master_queue, uwsgi.udp_fd); } } uwsgi.snmp_fd = uwsgi_setup_snmp(); if (uwsgi.status.is_cheap) { uwsgi_add_sockets_to_queue(uwsgi.master_queue, -1); for (i = 1; i <= uwsgi.numproc; i++) { uwsgi.workers[i].cheaped = 1; } uwsgi_log("cheap mode enabled: waiting for socket connection...\n"); } // spawn mules for (i = 0; i < uwsgi.mules_cnt; i++) { size_t mule_patch_size = 0; uwsgi.mules[i].patch = uwsgi_string_get_list(&uwsgi.mules_patches, i, &mule_patch_size); uwsgi_mule(i + 1); } // spawn gateways for (i = 0; i < ushared->gateways_cnt; i++) { if (ushared->gateways[i].pid == 0) { gateway_respawn(i); } } // spawn daemons uwsgi_daemons_spawn_all(); // first subscription uwsgi_subscribe_all(0, 1); // sync the cache store if needed uwsgi_cache_sync_all(); if (uwsgi.queue_store && uwsgi.queue_filesize) { if (msync(uwsgi.queue_header, uwsgi.queue_filesize, MS_ASYNC)) { uwsgi_error("msync()"); } } // update touches timestamps uwsgi_check_touches(uwsgi.touch_reload); uwsgi_check_touches(uwsgi.touch_logrotate); uwsgi_check_touches(uwsgi.touch_logreopen); uwsgi_check_touches(uwsgi.touch_chain_reload); uwsgi_check_touches(uwsgi.touch_workers_reload); uwsgi_check_touches(uwsgi.touch_gracefully_stop); // update exec touches struct uwsgi_string_list *usl = uwsgi.touch_exec; while (usl) { char *space = strchr(usl->value, ' '); if (space) { *space = 0; usl->len = strlen(usl->value); usl->custom_ptr = space + 1; } usl = usl->next; } uwsgi_check_touches(uwsgi.touch_exec); // update signal touches usl = uwsgi.touch_signal; while (usl) { char *space = strchr(usl->value, ' '); if (space) { *space = 0; usl->len = strlen(usl->value); usl->custom_ptr = space + 1; } usl = usl->next; } uwsgi_check_touches(uwsgi.touch_signal); // daemon touches struct uwsgi_daemon *ud = uwsgi.daemons; while (ud) { if (ud->touch) { uwsgi_check_touches(ud->touch); } ud = ud->next; } // hook touches uwsgi_foreach(usl, uwsgi.hook_touch) { char *space = strchr(usl->value, ' '); if (space) { *space = 0; usl->len = strlen(usl->value); uwsgi_string_new_list((struct uwsgi_string_list **)&usl->custom_ptr, space+1); } } uwsgi_check_touches(uwsgi.hook_touch); // fsmon uwsgi_fsmon_setup(); uwsgi_foreach(usl, uwsgi.signal_timers) { char *space = strchr(usl->value, ' '); if (!space) { uwsgi_log("invalid signal timer syntax, must be: \n"); exit(1); } *space = 0; uwsgi_add_timer(atoi(usl->value), atoi(space+1)); *space = ' '; } uwsgi_foreach(usl, uwsgi.rb_signal_timers) { char *space = strchr(usl->value, ' '); if (!space) { uwsgi_log("invalid redblack signal timer syntax, must be: \n"); exit(1); } *space = 0; uwsgi_signal_add_rb_timer(atoi(usl->value), atoi(space+1), 0); *space = ' '; } // setup cheaper algos (can be stacked) uwsgi.cheaper_algo = uwsgi_cheaper_algo_spare; if (uwsgi.requested_cheaper_algo) { uwsgi.cheaper_algo = NULL; struct uwsgi_cheaper_algo *uca = uwsgi.cheaper_algos; while (uca) { if (!strcmp(uca->name, uwsgi.requested_cheaper_algo)) { uwsgi.cheaper_algo = uca->func; break; } uca = uca->next; } if (!uwsgi.cheaper_algo) { uwsgi_log("unable to find requested cheaper algorithm, falling back to spare\n"); uwsgi.cheaper_algo = uwsgi_cheaper_algo_spare; } } // here really starts the master loop uwsgi_hooks_run(uwsgi.hook_master_start, "master-start", 1); for (;;) { //uwsgi_log("uwsgi.ready_to_reload %d %d\n", uwsgi.ready_to_reload, uwsgi.numproc); // run master_cycle hook for every plugin for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->master_cycle) { uwsgi.gp[i]->master_cycle(); } } for (i = 0; i < 256; i++) { if (uwsgi.p[i]->master_cycle) { uwsgi.p[i]->master_cycle(); } } // check for death (before reload !!!) uwsgi_master_check_death(); // check for realod if (uwsgi_master_check_reload(argv)) { return -1; } // check chain reload uwsgi_master_check_chain(); // check if some worker is taking too much to die... uwsgi_master_check_mercy(); // check for daemons (smart and dumb) uwsgi_daemons_smart_check(); // cheaper management if (uwsgi.cheaper && !uwsgi.status.is_cheap && !uwsgi_instance_is_reloading && !uwsgi_instance_is_dying && !uwsgi.workers[0].suspended) { if (!uwsgi_calc_cheaper()) return 0; } // check if someone is dead diedpid = waitpid(WAIT_ANY, &waitpid_status, WNOHANG); if (diedpid == -1) { if (errno == ECHILD) { // something did not work as expected, just assume all has been cleared uwsgi_master_commit_status(); diedpid = 0; } else { uwsgi_error("waitpid()"); /* here is better to reload all the uWSGI stack */ uwsgi_log("something horrible happened...\n"); reap_them_all(0); exit(1); } } // no one died just run all of the standard master tasks if (diedpid == 0) { /* all processes ok, doing status scan after N seconds */ check_interval = uwsgi.master_interval; if (!check_interval) { check_interval = 1; uwsgi.master_interval = 1; } // add unregistered file monitors // locking is not needed as monitors can only increase for (i = 0; i < ushared->files_monitored_cnt; i++) { if (!ushared->files_monitored[i].registered) { ushared->files_monitored[i].fd = event_queue_add_file_monitor(uwsgi.master_queue, ushared->files_monitored[i].filename, &ushared->files_monitored[i].id); ushared->files_monitored[i].registered = 1; } } // add unregistered timers // locking is not needed as timers can only increase for (i = 0; i < ushared->timers_cnt; i++) { if (!ushared->timers[i].registered) { ushared->timers[i].fd = event_queue_add_timer(uwsgi.master_queue, &ushared->timers[i].id, ushared->timers[i].value); ushared->timers[i].registered = 1; } } // add unregistered rb_timers // locking is not needed as rb_timers can only increase for (i = 0; i < ushared->rb_timers_cnt; i++) { if (!ushared->rb_timers[i].registered) { ushared->rb_timers[i].uwsgi_rb_timer = uwsgi_add_rb_timer(rb_timers, uwsgi_now() + ushared->rb_timers[i].value, &ushared->rb_timers[i]); ushared->rb_timers[i].registered = 1; } } int interesting_fd = -1; if (ushared->rb_timers_cnt > 0) { min_timeout = uwsgi_min_rb_timer(rb_timers, NULL); if (min_timeout) { int delta = min_timeout->value - uwsgi_now(); if (delta <= 0) { expire_rb_timeouts(rb_timers); } // if the timer expires before the check_interval, override it else if (delta < check_interval) { check_interval = delta; } } } // wait for event rlen = event_queue_wait(uwsgi.master_queue, check_interval, &interesting_fd); if (rlen == 0) { if (ushared->rb_timers_cnt > 0) { expire_rb_timeouts(rb_timers); } } // update load counter uwsgi_update_load_counters(); // check uwsgi-cron table if (ushared->cron_cnt) { uwsgi_manage_signal_cron(uwsgi_now()); } if (uwsgi.crons) { uwsgi_manage_command_cron(uwsgi_now()); } // some event returned if (rlen > 0) { // if the following function returns -1, a new worker has just spawned if (uwsgi_master_manage_events(interesting_fd)) { return 0; } } now = uwsgi_now(); if (now - uwsgi.current_time < 1) { continue; } uwsgi.current_time = now; // checking logsize if (uwsgi.logfile) { uwsgi_check_logrotate(); } // this will be incremented at (more or less) regular intervals uwsgi.master_cycles++; // recalculate requests counter on race conditions risky configurations // a bit of inaccuracy is better than locking;) uwsgi_master_fix_request_counters(); // check for idle uwsgi_master_check_idle(); check_interval = uwsgi.master_interval; if (!check_interval) { check_interval = 1; uwsgi.master_interval = 1; } // check listen_queue status master_check_listen_queue(); int someone_killed = 0; // check if some worker has to die (harakiri, evil checks...) if (uwsgi_master_check_workers_deadline()) someone_killed++; if (uwsgi_master_check_gateways_deadline()) someone_killed++; if (uwsgi_master_check_mules_deadline()) someone_killed++; if (uwsgi_master_check_spoolers_deadline()) someone_killed++; if (uwsgi_master_check_crons_deadline()) someone_killed++; // this could trigger a complete exit... uwsgi_master_check_mountpoints(); #ifdef __linux__ #ifdef MADV_MERGEABLE if (uwsgi.linux_ksm > 0 && (uwsgi.master_cycles % uwsgi.linux_ksm) == 0) { uwsgi_linux_ksm_map(); } #endif #endif // resubscribe every 10 cycles by default if (((uwsgi.subscriptions || uwsgi.subscriptions2) && ((uwsgi.master_cycles % uwsgi.subscribe_freq) == 0 || uwsgi.master_cycles == 1)) && !uwsgi_instance_is_reloading && !uwsgi_instance_is_dying && !uwsgi.workers[0].suspended) { uwsgi_subscribe_all(0, 0); } uwsgi_cache_sync_all(); if (uwsgi.queue_store && uwsgi.queue_filesize && uwsgi.queue_store_sync && ((uwsgi.master_cycles % uwsgi.queue_store_sync) == 0)) { if (msync(uwsgi.queue_header, uwsgi.queue_filesize, MS_ASYNC)) { uwsgi_error("msync()"); } } // check touch_reload if (!uwsgi_instance_is_reloading && !uwsgi_instance_is_dying) { char *touched = uwsgi_check_touches(uwsgi.touch_reload); if (touched) { uwsgi_log_verbose("*** %s has been touched... grace them all !!! ***\n", touched); uwsgi_block_signal(SIGHUP); grace_them_all(0); uwsgi_unblock_signal(SIGHUP); continue; } touched = uwsgi_check_touches(uwsgi.touch_workers_reload); if (touched) { uwsgi_log_verbose("*** %s has been touched... workers reload !!! ***\n", touched); uwsgi_reload_workers(); continue; } touched = uwsgi_check_touches(uwsgi.touch_mules_reload); if (touched) { uwsgi_log_verbose("*** %s has been touched... mules reload !!! ***\n", touched); uwsgi_reload_mules(); continue; } touched = uwsgi_check_touches(uwsgi.touch_spoolers_reload); if (touched) { uwsgi_log_verbose("*** %s has been touched... spoolers reload !!! ***\n", touched); uwsgi_reload_spoolers(); continue; } touched = uwsgi_check_touches(uwsgi.touch_chain_reload); if (touched) { if (uwsgi.status.chain_reloading == 0) { uwsgi_log_verbose("*** %s has been touched... chain reload !!! ***\n", touched); uwsgi.status.chain_reloading = 1; } else { uwsgi_log_verbose("*** %s has been touched... but chain reload is already running ***\n", touched); } } // be sure to run it as the last touch check touched = uwsgi_check_touches(uwsgi.touch_exec); if (touched) { if (uwsgi_run_command(touched, NULL, -1) >= 0) { uwsgi_log_verbose("[uwsgi-touch-exec] running %s\n", touched); } } touched = uwsgi_check_touches(uwsgi.touch_signal); if (touched) { uint8_t signum = atoi(touched); uwsgi_route_signal(signum); uwsgi_log_verbose("[uwsgi-touch-signal] raising %u\n", signum); } // daemon touches struct uwsgi_daemon *ud = uwsgi.daemons; while (ud) { if (ud->pid > 0 && ud->touch) { touched = uwsgi_check_touches(ud->touch); if (touched) { uwsgi_log_verbose("*** %s has been touched... reloading daemon \"%s\" (pid: %d) !!! ***\n", touched, ud->command, (int) ud->pid); if (kill(-ud->pid, ud->stop_signal)) { // killing process group failed, try to kill by process id if (kill(ud->pid, ud->stop_signal)) { uwsgi_error("[uwsgi-daemon/touch] kill()"); } } } } ud = ud->next; } // hook touches touched = uwsgi_check_touches(uwsgi.hook_touch); if (touched) { uwsgi_hooks_run((struct uwsgi_string_list *) touched, "touch", 0); } } // allows the KILL signal to be delivered; if (someone_killed > 0) sleep(1); continue; } // no one died if (diedpid <= 0) continue; // check for deadlocks first uwsgi_deadlock_check(diedpid); // reload gateways and daemons only on normal workflow (+outworld status) if (!uwsgi_instance_is_reloading && !uwsgi_instance_is_dying) { if (uwsgi_master_check_emperor_death(diedpid)) continue; if (uwsgi_master_check_spoolers_death(diedpid)) continue; if (uwsgi_master_check_mules_death(diedpid)) continue; if (uwsgi_master_check_gateways_death(diedpid)) continue; if (uwsgi_master_check_daemons_death(diedpid)) continue; if (uwsgi_master_check_cron_death(diedpid)) continue; } /* What happens here ? case 1) the diedpid is not a worker, report it and continue case 2) the diedpid is a worker and we are not in a reload procedure -> reload it case 3) the diedpid is a worker and we are in graceful reload -> uwsgi.ready_to_reload++ and continue case 3) the diedpid is a worker and we are in brutal reload -> uwsgi.ready_to_die++ and continue */ int thewid = find_worker_id(diedpid); if (thewid <= 0) { // check spooler, mules, gateways and daemons struct uwsgi_spooler *uspool = uwsgi.spoolers; while (uspool) { if (uspool->pid > 0 && diedpid == uspool->pid) { uwsgi_log("spooler (pid: %d) annihilated\n", (int) diedpid); goto next; } uspool = uspool->next; } for (i = 0; i < uwsgi.mules_cnt; i++) { if (uwsgi.mules[i].pid == diedpid) { uwsgi_log("mule %d (pid: %d) annihilated\n", i + 1, (int) diedpid); uwsgi.mules[i].pid = 0; goto next; } } for (i = 0; i < ushared->gateways_cnt; i++) { if (ushared->gateways[i].pid == diedpid) { uwsgi_log("gateway %d (%s, pid: %d) annihilated\n", i + 1, ushared->gateways[i].fullname, (int) diedpid); goto next; } } if (uwsgi_daemon_check_pid_death(diedpid)) goto next; if (WIFEXITED(waitpid_status)) { uwsgi_log("subprocess %d exited with code %d\n", (int) diedpid, WEXITSTATUS(waitpid_status)); } else if (WIFSIGNALED(waitpid_status)) { uwsgi_log("subprocess %d exited by signal %d\n", (int) diedpid, WTERMSIG(waitpid_status)); } else if (WIFSTOPPED(waitpid_status)) { uwsgi_log("subprocess %d stopped\n", (int) diedpid); } next: continue; } // ok a worker died... uwsgi.workers[thewid].pid = 0; // only to be safe :P uwsgi.workers[thewid].harakiri = 0; // first check failed app loading in need-app mode if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_FAILED_APP_CODE) { if (uwsgi.lazy_apps && uwsgi.need_app) { uwsgi_log("OOPS ! failed loading app in worker %d (pid %d)\n", thewid, (int) diedpid); uwsgi_log_verbose("need-app requested, destroying the instance...\n"); uwsgi.status.dying_for_need_app = 1; kill_them_all(0); continue; } else { uwsgi_log("OOPS ! failed loading app in worker %d (pid %d) :( trying again...\n", thewid, (int) diedpid); } } // ok, if we are reloading or dying, just continue the master loop // as soon as all of the workers have pid == 0, the action (exit, or reload) is triggered if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying) { if (!uwsgi.workers[thewid].cursed_at) uwsgi.workers[thewid].cursed_at = uwsgi_now(); uwsgi_log("worker %d buried after %d seconds\n", thewid, (int) (uwsgi_now() - uwsgi.workers[thewid].cursed_at)); uwsgi.workers[thewid].cursed_at = 0; // if we are stopping workers, just end here continue; } if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_DE_HIJACKED_CODE) { uwsgi_log("...restoring worker %d (pid: %d)...\n", thewid, (int) diedpid); } else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_EXCEPTION_CODE) { uwsgi_log("... monitored exception detected, respawning worker %d (pid: %d)...\n", thewid, (int) diedpid); } else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_QUIET_CODE) { // noop } else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_BRUTAL_RELOAD_CODE) { uwsgi_log("!!! inconsistent state reported by worker %d (pid: %d) !!!\n", thewid, (int) diedpid); reap_them_all(0); continue; } else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_GO_CHEAP_CODE) { uwsgi_log("worker %d asked for cheap mode (pid: %d)...\n", thewid, (int) diedpid); uwsgi.workers[thewid].cheaped = 1; } else if (uwsgi.workers[thewid].manage_next_request) { if (WIFSIGNALED(waitpid_status)) { uwsgi_log("DAMN ! worker %d (pid: %d) died, killed by signal %d :( trying respawn ...\n", thewid, (int) diedpid, (int) WTERMSIG(waitpid_status)); } else { uwsgi_log("DAMN ! worker %d (pid: %d) died :( trying respawn ...\n", thewid, (int) diedpid); } } else if (uwsgi.workers[thewid].cursed_at > 0) { uwsgi_log("worker %d killed successfully (pid: %d)\n", thewid, (int) diedpid); } // manage_next_request is zero, but killed by signal... else if (WIFSIGNALED(waitpid_status)) { uwsgi_log("DAMN ! worker %d (pid: %d) MISTERIOUSLY killed by signal %d :( trying respawn ...\n", thewid, (int) diedpid, (int) WTERMSIG(waitpid_status)); } if (uwsgi.workers[thewid].cheaped == 1) { uwsgi_log("uWSGI worker %d cheaped.\n", thewid); continue; } // avoid fork bombing gettimeofday(&last_respawn, NULL); if (last_respawn.tv_sec <= uwsgi.respawn_delta + check_interval) { last_respawn_rate++; if (last_respawn_rate > uwsgi.numproc) { if (uwsgi.forkbomb_delay > 0) { uwsgi_log("worker respawning too fast !!! i have to sleep a bit (%d seconds)...\n", uwsgi.forkbomb_delay); /* use --forkbomb-delay 0 to disable sleeping */ sleep(uwsgi.forkbomb_delay); } last_respawn_rate = 0; } } else { last_respawn_rate = 0; } gettimeofday(&last_respawn, NULL); uwsgi.respawn_delta = last_respawn.tv_sec; // are we chain reloading it ? if (uwsgi.status.chain_reloading == thewid) { uwsgi.status.chain_reloading++; } // respawn the worker (if needed) if (uwsgi_respawn_worker(thewid)) return 0; // end of the loop } // never here } void uwsgi_reload_workers() { int i; uwsgi_block_signal(SIGHUP); for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].pid > 0) { uwsgi_curse(i, SIGHUP); } } uwsgi_unblock_signal(SIGHUP); } void uwsgi_reload_mules() { int i; uwsgi_block_signal(SIGHUP); for (i = 0; i <= uwsgi.mules_cnt; i++) { if (uwsgi.mules[i].pid > 0) { uwsgi_curse_mule(i, SIGHUP); } } uwsgi_unblock_signal(SIGHUP); } void uwsgi_reload_spoolers() { struct uwsgi_spooler *us; uwsgi_block_signal(SIGHUP); for (us = uwsgi.spoolers; us; us = us->next) { if (us->pid > 0) { kill(us->pid, SIGHUP); us->cursed_at = uwsgi_now(); us->no_mercy_at = us->cursed_at + uwsgi.spooler_reload_mercy; } } uwsgi_unblock_signal(SIGHUP); } void uwsgi_chain_reload() { if (!uwsgi.status.chain_reloading) { uwsgi_log_verbose("chain reload starting...\n"); uwsgi.status.chain_reloading = 1; } else { uwsgi_log_verbose("chain reload already running...\n"); } } void uwsgi_brutally_reload_workers() { int i; for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].pid > 0) { uwsgi_log_verbose("killing worker %d (pid: %d)\n", i, (int) uwsgi.workers[i].pid); uwsgi_curse(i, SIGINT); } } } uwsgi-2.0.29/core/master_checks.c000066400000000000000000000315661477626554400167100ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; // check if all of the workers are dead and exit uWSGI void uwsgi_master_check_death() { if (uwsgi_instance_is_dying) { int i; for(i=1;i<=uwsgi.numproc;i++) { if (uwsgi.workers[i].pid > 0) { return; } } for(i=0;i 0) { return; } } uwsgi_log("goodbye to uWSGI.\n"); exit(uwsgi.status.dying_for_need_app ? UWSGI_FAILED_APP_CODE : 0); } } // check if all of the workers are dead, and trigger a reload int uwsgi_master_check_reload(char **argv) { if (uwsgi_instance_is_reloading) { int i; for(i=1;i<=uwsgi.numproc;i++) { if (uwsgi.workers[i].pid > 0) { return 0; } } for(i=0;i 0) { return 0; } } uwsgi_reload(argv); // never here (unless in shared library mode) return -1; } return 0; } // check for chain reload void uwsgi_master_check_chain() { static time_t last_check = 0; if (!uwsgi.status.chain_reloading) return; // we need to ensure the previous worker (if alive) is accepting new requests // before going on if (uwsgi.status.chain_reloading > 1) { struct uwsgi_worker *previous_worker = &uwsgi.workers[uwsgi.status.chain_reloading-1]; // is the previous worker alive ? if (previous_worker->pid > 0 && !previous_worker->cheaped) { // the worker has been respawned but it is still not ready if (previous_worker->accepting == 0) { time_t now = uwsgi_now(); if (now != last_check) { uwsgi_log_verbose("chain is still waiting for worker %d...\n", uwsgi.status.chain_reloading-1); last_check = now; } return; } } } // if all the processes are recycled, the chain is over if (uwsgi.status.chain_reloading > uwsgi.numproc) { uwsgi.status.chain_reloading = 0; uwsgi_log_verbose("chain reloading complete\n"); return; } uwsgi_block_signal(SIGHUP); int i; for(i=uwsgi.status.chain_reloading;i<=uwsgi.numproc;i++) { struct uwsgi_worker *uw = &uwsgi.workers[i]; if (uw->pid > 0 && !uw->cheaped && uw->accepting) { // the worker could have been already cursed if (uw->cursed_at == 0) { uwsgi_log_verbose("chain next victim is worker %d\n", i); uwsgi_curse(i, SIGHUP); } break; } else { uwsgi.status.chain_reloading++; } } uwsgi_unblock_signal(SIGHUP); } // special function for assuming all of the workers are dead void uwsgi_master_commit_status() { int i; for(i=1;i<=uwsgi.numproc;i++) { uwsgi.workers[i].pid = 0; } } void uwsgi_master_check_idle() { static time_t last_request_timecheck = 0; static uint64_t last_request_count = 0; int i; int waitpid_status; if (!uwsgi.idle || uwsgi.status.is_cheap) return; uwsgi.current_time = uwsgi_now(); if (!last_request_timecheck) last_request_timecheck = uwsgi.current_time; // security check, stop the check if there are busy workers for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) { if (uwsgi_worker_is_busy(i)) { return; } } } if (last_request_count != uwsgi.workers[0].requests) { last_request_timecheck = uwsgi.current_time; last_request_count = uwsgi.workers[0].requests; } // a bit of over-engeneering to avoid clock skews else if (last_request_timecheck < uwsgi.current_time && (uwsgi.current_time - last_request_timecheck > uwsgi.idle)) { uwsgi_log("workers have been inactive for more than %d seconds (%llu-%llu)\n", uwsgi.idle, (unsigned long long) uwsgi.current_time, (unsigned long long) last_request_timecheck); uwsgi.status.is_cheap = 1; if (uwsgi.die_on_idle) { if (uwsgi.has_emperor) { char byte = 22; if (write(uwsgi.emperor_fd, &byte, 1) != 1) { uwsgi_error("write()"); kill_them_all(0); } } else { kill_them_all(0); } return; } for (i = 1; i <= uwsgi.numproc; i++) { uwsgi.workers[i].cheaped = 1; if (uwsgi.workers[i].pid == 0) continue; // first send SIGINT kill(uwsgi.workers[i].pid, SIGINT); // and start waiting upto 3 seconds int j; for(j=0;j<3;j++) { sleep(1); int ret = waitpid(uwsgi.workers[i].pid, &waitpid_status, WNOHANG); if (ret == 0) continue; if (ret == (int) uwsgi.workers[i].pid) goto done; // on error, directly send SIGKILL break; } kill(uwsgi.workers[i].pid, SIGKILL); if (waitpid(uwsgi.workers[i].pid, &waitpid_status, 0) < 0) { if (errno != ECHILD) uwsgi_error("uwsgi_master_check_idle()/waitpid()"); } else { done: uwsgi.workers[i].pid = 0; uwsgi.workers[i].rss_size = 0; uwsgi.workers[i].vsz_size = 0; } } uwsgi_add_sockets_to_queue(uwsgi.master_queue, -1); uwsgi_log("cheap mode enabled: waiting for socket connection...\n"); last_request_timecheck = 0; } } int uwsgi_master_check_harakiri(int w, int c, time_t harakiri) { /** * Triggers a harakiri when the following conditions are met: * - harakiri timeout > current time * - listen queue pressure (ie backlog > harakiri_queue_threshold) * * The first harakiri attempt on a worker will be graceful if harakiri_graceful_timeout > 0, * then the worker has harakiri_graceful_timeout seconds to shutdown cleanly, otherwise * a second harakiri will trigger a SIGKILL * */ #ifdef __linux__ int backlog = uwsgi.shared->backlog; #else int backlog = 0; #endif if (harakiri == 0 || harakiri > (time_t) uwsgi.current_time) { return 0; } // no pending harakiri for the worker and no backlog pressure, safe to skip if (uwsgi.workers[w].pending_harakiri == 0 && backlog < uwsgi.harakiri_queue_threshold) { uwsgi_log_verbose("HARAKIRI: Skipping harakiri on worker %d. Listen queue is smaller than the threshold (%d < %d)\n", w, backlog, uwsgi.harakiri_queue_threshold); return 0; } trigger_harakiri(w); if (uwsgi.harakiri_graceful_timeout > 0) { uwsgi.workers[w].harakiri = harakiri + uwsgi.harakiri_graceful_timeout; uwsgi_log_verbose("HARAKIRI: graceful termination attempt on worker %d with signal %d. Next harakiri: %d\n", w, uwsgi.harakiri_graceful_signal, uwsgi.workers[w].harakiri); } return 1; } int uwsgi_master_check_workers_deadline() { int i,j; int ret = 0; for (i = 1; i <= uwsgi.numproc; i++) { for(j=0;j= uwsgi.evil_reload_on_as) { uwsgi_log("*** EVIL RELOAD ON WORKER %d ADDRESS SPACE: %lld (pid: %d) ***\n", i, (long long) uwsgi.workers[i].vsz_size, uwsgi.workers[i].pid); kill(uwsgi.workers[i].pid, SIGKILL); uwsgi.workers[i].vsz_size = 0; ret = 1; } } if (uwsgi.evil_reload_on_rss) { if ((rlim_t) uwsgi.workers[i].rss_size >= uwsgi.evil_reload_on_rss) { uwsgi_log("*** EVIL RELOAD ON WORKER %d RSS: %lld (pid: %d) ***\n", i, (long long) uwsgi.workers[i].rss_size, uwsgi.workers[i].pid); kill(uwsgi.workers[i].pid, SIGKILL); uwsgi.workers[i].rss_size = 0; ret = 1; } } // check if worker was running longer than allowed lifetime if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cheaped == 0 && uwsgi.max_worker_lifetime > 0) { uint64_t lifetime = uwsgi_now() - uwsgi.workers[i].last_spawn; if (lifetime > (uwsgi.max_worker_lifetime + (i-1) * uwsgi.max_worker_lifetime_delta) && uwsgi.workers[i].manage_next_request == 1) { uwsgi_log("worker %d lifetime reached, it was running for %llu second(s)\n", i, (unsigned long long) lifetime); uwsgi.workers[i].manage_next_request = 0; kill(uwsgi.workers[i].pid, SIGWINCH); ret = 1; } } // need to find a better way //uwsgi.workers[i].last_running_time = uwsgi.workers[i].running_time; } return ret; } int uwsgi_master_check_gateways_deadline() { int i; int ret = 0; for (i = 0; i < ushared->gateways_cnt; i++) { if (ushared->gateways_harakiri[i] > 0) { if (ushared->gateways_harakiri[i] < (time_t) uwsgi.current_time) { if (ushared->gateways[i].pid > 0) { uwsgi_log("*** HARAKIRI ON GATEWAY %s %d (pid: %d) ***\n", ushared->gateways[i].name, ushared->gateways[i].num, ushared->gateways[i].pid); kill(ushared->gateways[i].pid, SIGKILL); ret = 1; } ushared->gateways_harakiri[i] = 0; } } } return ret; } int uwsgi_master_check_mules_deadline() { int i; int ret = 0; for (i = 0; i < uwsgi.mules_cnt; i++) { if (uwsgi.mules[i].harakiri > 0) { if (uwsgi.mules[i].harakiri < (time_t) uwsgi.current_time) { uwsgi_log("*** HARAKIRI ON MULE %d HANDLING SIGNAL %d (pid: %d) ***\n", i + 1, uwsgi.mules[i].signum, uwsgi.mules[i].pid); kill(uwsgi.mules[i].pid, SIGKILL); uwsgi.mules[i].harakiri = 0; ret = 1; } } // user harakiri if (uwsgi.mules[i].user_harakiri > 0) { if (uwsgi.mules[i].user_harakiri < (time_t) uwsgi.current_time) { uwsgi_log("*** HARAKIRI ON MULE %d (pid: %d) ***\n", i + 1, uwsgi.mules[i].pid); kill(uwsgi.mules[i].pid, SIGKILL); uwsgi.mules[i].user_harakiri = 0; ret = 1; } } } return ret; } int uwsgi_master_check_spoolers_deadline() { int ret = 0; struct uwsgi_spooler *uspool = uwsgi.spoolers; while (uspool) { if (uspool->harakiri > 0 && uspool->harakiri < (time_t) uwsgi.current_time) { uwsgi_log("*** HARAKIRI ON THE SPOOLER (pid: %d) ***\n", uspool->pid); kill(uspool->pid, SIGKILL); uspool->harakiri = 0; ret = 1; } if (uspool->user_harakiri > 0 && uspool->user_harakiri < (time_t) uwsgi.current_time) { uwsgi_log("*** HARAKIRI ON THE SPOOLER (pid: %d) ***\n", uspool->pid); kill(uspool->pid, SIGKILL); uspool->user_harakiri = 0; ret = 1; } uspool = uspool->next; } return ret; } int uwsgi_master_check_spoolers_death(int diedpid) { struct uwsgi_spooler *uspool = uwsgi.spoolers; while (uspool) { if (uspool->pid > 0 && diedpid == uspool->pid) { if (uspool->cursed_at) { uspool->pid = 0; uspool->cursed_at = 0; uspool->no_mercy_at = 0; } uwsgi_log("OOOPS the spooler is no more...trying respawn...\n"); uspool->respawned++; uspool->pid = spooler_start(uspool); return -1; } uspool = uspool->next; } return 0; } int uwsgi_master_check_emperor_death(int diedpid) { if (uwsgi.emperor_pid >= 0 && diedpid == uwsgi.emperor_pid) { uwsgi_log_verbose("!!! Emperor died !!!\n"); uwsgi_emperor_start(); return -1; } return 0; } int uwsgi_master_check_mules_death(int diedpid) { int i; for (i = 0; i < uwsgi.mules_cnt; i++) { if (!(uwsgi.mules[i].pid == diedpid)) continue; if (!uwsgi.mules[i].cursed_at) { uwsgi_log("OOOPS mule %d (pid: %d) crippled...trying respawn...\n", i + 1, uwsgi.mules[i].pid); } uwsgi.mules[i].no_mercy_at = 0; uwsgi.mules[i].cursed_at = 0; uwsgi_mule(i + 1); return -1; } return 0; } int uwsgi_master_check_gateways_death(int diedpid) { int i; for (i = 0; i < ushared->gateways_cnt; i++) { if (ushared->gateways[i].pid == diedpid) { gateway_respawn(i); return -1; } } return 0; } int uwsgi_master_check_daemons_death(int diedpid) { /* reload the daemons */ if (uwsgi_daemon_check_pid_reload(diedpid)) { return -1; } return 0; } int uwsgi_worker_is_busy(int wid) { int i; if (uwsgi.workers[wid].sig) return 1; for(i=0;ipid == (pid_t) diedpid) { uwsgi_log("[uwsgi-cron] command \"%s\" running with pid %d exited after %d second(s)\n", uc->command, uc->pid, uwsgi_now() - uc->started_at); uc->pid = -1; uc->started_at = 0; return -1; } uc = uc->next; } return 0; } int uwsgi_master_check_crons_deadline() { int ret = 0; struct uwsgi_cron *uc = uwsgi.crons; while (uc) { if (uc->pid >= 0 && uc->harakiri > 0 && uc->harakiri < (time_t) uwsgi.current_time) { uwsgi_log("*** HARAKIRI ON CRON \"%s\" (pid: %d) ***\n", uc->command, uc->pid); kill(-uc->pid, SIGKILL); ret = 1; } uc = uc->next; } return ret; } void uwsgi_master_check_mountpoints() { struct uwsgi_string_list *usl; uwsgi_foreach(usl, uwsgi.mountpoints_check) { if (uwsgi_check_mountpoint(usl->value)) { uwsgi_log_verbose("mountpoint %s failed, triggering detonation...\n", usl->value); uwsgi_nuclear_blast(); //never here exit(1); } } } uwsgi-2.0.29/core/master_events.c000066400000000000000000000167001477626554400167450ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; int uwsgi_master_manage_events(int interesting_fd) { // is a logline ? if (uwsgi.log_master && !uwsgi.threaded_logger) { // stderr log ? if (interesting_fd == uwsgi.shared->worker_log_pipe[0]) { uwsgi_master_log(); return 0; } // req log ? if (uwsgi.req_log_master && interesting_fd == uwsgi.shared->worker_req_log_pipe[0]) { uwsgi_master_req_log(); return 0; } } if (uwsgi.master_fifo_fd > -1 && interesting_fd == uwsgi.master_fifo_fd) { return uwsgi_master_fifo_manage(uwsgi.master_fifo_fd); } if (uwsgi.notify_socket_fd > -1 && interesting_fd == uwsgi.notify_socket_fd) { return uwsgi_notify_socket_manage(interesting_fd); } // stats server ? if (uwsgi.stats && uwsgi.stats_fd > -1) { if (interesting_fd == uwsgi.stats_fd) { uwsgi_send_stats(uwsgi.stats_fd, uwsgi_master_generate_stats); return 0; } } // a zerg connection ? if (uwsgi.zerg_server) { if (interesting_fd == uwsgi.zerg_server_fd) { uwsgi_manage_zerg(uwsgi.zerg_server_fd, 0, NULL); return 0; } } // emperor event ? if (uwsgi.has_emperor) { if (uwsgi.emperor_fd_proxy > -1 && interesting_fd == uwsgi.emperor_fd_proxy) { uwsgi_master_manage_emperor_proxy(); return 0; } if (interesting_fd == uwsgi.emperor_fd) { uwsgi_master_manage_emperor(); return 0; } } #ifdef __linux__ if (uwsgi.setns_socket && uwsgi.setns_socket_fd > -1 && interesting_fd == uwsgi.setns_socket_fd) { uwsgi_master_manage_setns(uwsgi.setns_socket_fd); } #endif if (uwsgi_fsmon_event(interesting_fd)) { return 0; } // reload on fd if (uwsgi.reload_on_fd) { // custom -> fd // custom2 -> len (optional, default 1) // custom_ptr -> log message (optional) struct uwsgi_string_list *usl = uwsgi.reload_on_fd; while(usl) { if (interesting_fd == (int) usl->custom) { char stack_tmp[8]; char *tmp = stack_tmp; if (usl->custom2 > 8) { tmp = uwsgi_malloc(usl->custom2); } if (read(interesting_fd, tmp, usl->custom2) <= 0) { uwsgi_error("[reload-on-fd] read()"); } if (usl->custom_ptr) { uwsgi_log_verbose("*** fd %d ready: %s ***\n", interesting_fd, usl->custom_ptr); } else { uwsgi_log_verbose("*** fd %d ready !!! ***\n", interesting_fd); } uwsgi_block_signal(SIGHUP); grace_them_all(0); uwsgi_unblock_signal(SIGHUP); return 0; } usl = usl->next; } } // brutal reload on fd if (uwsgi.brutal_reload_on_fd) { // custom -> fd // custom2 -> len (optional, default 1) // custom_ptr -> log message (optional) struct uwsgi_string_list *usl = uwsgi.brutal_reload_on_fd; while(usl) { if (interesting_fd == (int) usl->custom) { char stack_tmp[8]; char *tmp = stack_tmp; if (usl->custom2 > 8) { tmp = uwsgi_malloc(usl->custom2); } if (read(interesting_fd, tmp, usl->custom2) <= 0) { uwsgi_error("[brutal-reload-on-fd] read()"); } if (usl->custom_ptr) { uwsgi_log_verbose("*** fd %d ready: %s ***\n", interesting_fd, usl->custom_ptr); } else { uwsgi_log_verbose("*** fd %d ready !!! ***\n", interesting_fd); } if (uwsgi.die_on_term) { uwsgi_block_signal(SIGQUIT); reap_them_all(0); uwsgi_unblock_signal(SIGQUIT); } else { uwsgi_block_signal(SIGTERM); reap_them_all(0); uwsgi_unblock_signal(SIGTERM); } if (usl->custom2 > 8) free(tmp); return 0; } usl = usl->next; } } // wakeup from cheap mode ? if (uwsgi.status.is_cheap) { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (interesting_fd == uwsgi_sock->fd) { uwsgi.status.is_cheap = 0; uwsgi_del_sockets_from_queue(uwsgi.master_queue); // how many worker we need to respawn ? int needed = uwsgi.numproc; // if in cheaper mode, just respawn the minimal amount if (uwsgi.cheaper) { needed = uwsgi.cheaper_count; } int i; for (i = 1; i <= needed; i++) { if (uwsgi_respawn_worker(i)) return -1; } // here we continue instead of returning break; } uwsgi_sock = uwsgi_sock->next; } } // an SNMP request ? if (uwsgi.snmp_addr && interesting_fd == uwsgi.snmp_fd) { uwsgi_master_manage_snmp(uwsgi.snmp_fd); return 0; } // a UDP request ? if (uwsgi.udp_socket && interesting_fd == uwsgi.udp_fd) { uwsgi_master_manage_udp(uwsgi.udp_fd); return 0; } // check if some file monitor is ready // no need to lock as we are only getting registered items (and only the master can register them) int i; for (i = 0; i < ushared->files_monitored_cnt; i++) { if (ushared->files_monitored[i].registered) { if (interesting_fd == ushared->files_monitored[i].fd) { struct uwsgi_fmon *uf = event_queue_ack_file_monitor(uwsgi.master_queue, interesting_fd); // now call the file_monitor handler if (uf) uwsgi_route_signal(uf->sig); return 0; } } } // check if some timer elapsed // no need to lock again for (i = 0; i < ushared->timers_cnt; i++) { if (ushared->timers[i].registered) { if (interesting_fd == ushared->timers[i].fd) { struct uwsgi_timer *ut = event_queue_ack_timer(interesting_fd); // now call the timer handler if (ut) uwsgi_route_signal(ut->sig); return 0; } } } uint8_t uwsgi_signal; // check for worker signal if (interesting_fd == uwsgi.shared->worker_signal_pipe[0]) { ssize_t rlen = read(interesting_fd, &uwsgi_signal, 1); if (rlen < 0) { uwsgi_error("uwsgi_master_manage_events()/read()"); } else if (rlen > 0) { uwsgi_route_signal(uwsgi_signal); } else { // TODO restart workers here uwsgi_log_verbose("lost connection with workers !!!\n"); close(interesting_fd); } return 0; } // check for spooler signal if (uwsgi.spoolers) { if (interesting_fd == uwsgi.shared->spooler_signal_pipe[0]) { ssize_t rlen = read(interesting_fd, &uwsgi_signal, 1); if (rlen < 0) { uwsgi_error("uwsgi_master_manage_events()/read()"); } else if (rlen > 0) { uwsgi_route_signal(uwsgi_signal); } else { // TODO restart spoolers here uwsgi_log_verbose("lost connection with spoolers\n"); close(interesting_fd); } return 0; } } // check for mules signal if (uwsgi.mules_cnt > 0) { if (interesting_fd == uwsgi.shared->mule_signal_pipe[0]) { ssize_t rlen = read(interesting_fd, &uwsgi_signal, 1); if (rlen < 0) { uwsgi_error("uwsgi_master_manage_events()/read()"); } else if (rlen > 0) { uwsgi_route_signal(uwsgi_signal); } else { // TODO respawn mules here uwsgi_log_verbose("lost connection with mules\n"); close(interesting_fd); } // return 0; } } return 0; } uwsgi-2.0.29/core/master_utils.c000066400000000000000000001426101477626554400166010ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; void worker_wakeup(int sig) { } uint64_t uwsgi_worker_exceptions(int wid) { uint64_t total = 0; int i; for(i=0;ipid > 0) { kill(uspool->pid, signum); uwsgi_log("killing the spooler with pid %d\n", uspool->pid); } uspool = uspool->next; } } void uwsgi_destroy_processes() { int i; int waitpid_status; uwsgi_signal_spoolers(SIGKILL); uwsgi_detach_daemons(); for (i = 0; i < ushared->gateways_cnt; i++) { if (ushared->gateways[i].pid > 0) { kill(ushared->gateways[i].pid, SIGKILL); waitpid(ushared->gateways[i].pid, &waitpid_status, 0); uwsgi_log("gateway \"%s %d\" has been buried (pid: %d)\n", ushared->gateways[i].name, ushared->gateways[i].num, (int) ushared->gateways[i].pid); } } if (uwsgi.emperor_pid > 0) { kill(uwsgi.emperor_pid, SIGINT); time_t timeout = uwsgi_now() + (uwsgi.reload_mercy ? uwsgi.reload_mercy : 3); // increase timeout for being more tolerant timeout+=2; int waitpid_status; while (uwsgi_now() < timeout) { pid_t diedpid = waitpid(uwsgi.emperor_pid, &waitpid_status, WNOHANG); if (diedpid == uwsgi.emperor_pid) { goto nomoremperor; } uwsgi_log("waiting for Emperor death...\n"); sleep(1); } kill(uwsgi.emperor_pid, SIGKILL); waitpid(uwsgi.emperor_pid, &waitpid_status, 0); nomoremperor: uwsgi_log("The Emperor has been buried (pid: %d)\n", (int) uwsgi.emperor_pid); } } void uwsgi_master_cleanup_hooks(void) { int j; // could be an inherited atexit hook if (uwsgi.mypid != uwsgi.workers[0].pid) return; uwsgi.status.is_cleaning = 1; for (j = 0; j < uwsgi.gp_cnt; j++) { if (uwsgi.gp[j]->master_cleanup) { uwsgi.gp[j]->master_cleanup(); } } for (j = 0; j < 256; j++) { if (uwsgi.p[j]->master_cleanup) { uwsgi.p[j]->master_cleanup(); } } } int uwsgi_calc_cheaper(void) { int i; static time_t last_check = 0; int check_interval = uwsgi.master_interval; if (!last_check) last_check = uwsgi_now(); time_t now = uwsgi_now(); if (!check_interval) check_interval = 1; if ((now - last_check) < check_interval) return 1; last_check = now; int ignore_algo = 0; int needed_workers = 0; // first check if memory usage is not exceeded if (uwsgi.cheaper_rss_limit_soft) { unsigned long long total_rss = 0; int i; int active_workers = 0; for(i=1;i<=uwsgi.numproc;i++) { if (!uwsgi.workers[i].cheaped) { total_rss += uwsgi.workers[i].rss_size; active_workers++; } } if (uwsgi.cheaper_rss_limit_hard && active_workers > 1 && total_rss >= uwsgi.cheaper_rss_limit_hard) { uwsgi_log("cheaper hard rss memory limit exceeded, cheap one of %d workers\n", active_workers); needed_workers = -1; ignore_algo = 1; } else if (total_rss >= uwsgi.cheaper_rss_limit_soft) { #ifdef UWSGI_DEBUG uwsgi_log("cheaper soft rss memory limit exceeded, can't spawn more workers\n"); #endif ignore_algo = 1; } } // then check for fifo if (uwsgi.cheaper_fifo_delta != 0) { if (!ignore_algo) { needed_workers = uwsgi.cheaper_fifo_delta; ignore_algo = 1; } uwsgi.cheaper_fifo_delta = 0; goto safe; } // if cheaper limits wants to change worker count, then skip cheaper algo if (!needed_workers) needed_workers = uwsgi.cheaper_algo(!ignore_algo); // safe check to verify if cheaper algo obeyed ignore_algo value if (ignore_algo && needed_workers > 0) { uwsgi_log("BUG! cheaper algo returned %d but it cannot spawn any worker at this time!\n", needed_workers); needed_workers = 0; } safe: if (needed_workers > 0) { for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].cheaped == 1 && uwsgi.workers[i].pid == 0) { if (uwsgi_respawn_worker(i)) { uwsgi.cheaper_fifo_delta += needed_workers; return 0; } needed_workers--; } if (needed_workers == 0) break; } } else if (needed_workers < 0) { while (needed_workers < 0) { int oldest_worker = 0; time_t oldest_worker_spawn = INT_MAX; for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) { if (uwsgi_worker_is_busy(i) == 0) { if (uwsgi.workers[i].last_spawn < oldest_worker_spawn) { oldest_worker_spawn = uwsgi.workers[i].last_spawn; oldest_worker = i; } } } } if (oldest_worker > 0) { #ifdef UWSGI_DEBUG uwsgi_log("worker %d should die...\n", oldest_worker); #endif uwsgi.workers[oldest_worker].cheaped = 1; uwsgi.workers[oldest_worker].rss_size = 0; uwsgi.workers[oldest_worker].vsz_size = 0; uwsgi.workers[oldest_worker].manage_next_request = 0; uwsgi_curse(oldest_worker, SIGWINCH); } else { // Return it to the pool uwsgi.cheaper_fifo_delta--; } needed_workers++; } } return 1; } // fake algo to allow control with the fifo int uwsgi_cheaper_algo_manual(int can_spawn) { return 0; } /* -- Cheaper, spare algorithm, adapted from old-fashioned spare system -- when all of the workers are busy, the overload_count is incremented. as soon as overload_count is higher than uwsgi.cheaper_overload (--cheaper-overload options) at most cheaper_step (default to 1) new workers are spawned. when at least one worker is free, the overload_count is decremented and the idle_count is incremented. If overload_count reaches 0, the system will count active workers (the ones uncheaped) and busy workers (the ones running a request) if there is exacly 1 free worker we are in "stable state" (1 spare worker available). no worker will be touched. if the number of active workers is higher than uwsgi.cheaper_count and at least uwsgi.cheaper_overload cycles are passed from the last "cheap it" procedure, then cheap a worker. Example: 10 processes 2 cheaper 2 cheaper step 3 cheaper_overload 1 second master cycle there are 7 workers running (triggered by some kind of spike activity). Of this, 6 are busy, 1 is free. We are in stable state. After a bit the spike disappear and idle_count start to increase. After 3 seconds (uwsgi.cheaper_overload cycles) the oldest worker will be cheaped. This will happens every seconds (uwsgi.cheaper_overload cycles) til the number of workers is == uwsgi.cheaper_count. If during the "cheap them all" procedure, an overload condition come again (another spike) the "cheap them all" will be interrupted. */ int uwsgi_cheaper_algo_spare(int can_spawn) { int i; static uint64_t overload_count = 0; static uint64_t idle_count = 0; // step 1 -> count the number of busy workers for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) { // if a non-busy worker is found, the overload_count is decremented and stop the cycle if (uwsgi_worker_is_busy(i) == 0) { if (overload_count > 0) overload_count--; goto healthy; } } } overload_count++; idle_count = 0; healthy: // are we overloaded ? if (can_spawn && overload_count > uwsgi.cheaper_overload) { #ifdef UWSGI_DEBUG uwsgi_log("overloaded !!!\n"); #endif // activate the first available worker (taking step into account) int decheaped = 0; // search for cheaped workers for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].cheaped == 1 && uwsgi.workers[i].pid == 0) { decheaped++; if (decheaped >= uwsgi.cheaper_step) break; } } // reset overload overload_count = 0; // return the maximum number of workers to spawn return decheaped; } // we are no more overloaded else if (overload_count == 0) { // how many active workers ? int active_workers = 0; int busy_workers = 0; for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) { active_workers++; if (uwsgi_worker_is_busy(i) == 1) busy_workers++; } } #ifdef UWSGI_DEBUG uwsgi_log("active workers %d busy_workers %d\n", active_workers, busy_workers); #endif // special condition: uwsgi.cheaper running workers and 1 free if (active_workers > busy_workers && active_workers - busy_workers == 1) { #ifdef UWSGI_DEBUG uwsgi_log("stable status: 1 spare worker\n"); #endif return 0; } idle_count++; if (active_workers > uwsgi.cheaper_count && idle_count % uwsgi.cheaper_overload == 0) { // we are in "cheap them all" return -1; } } return 0; } /* -- Cheaper, backlog algorithm (supported only on Linux) -- increse the number of workers when the listen queue is higher than uwsgi.cheaper_overload. Decrese when lower. */ int uwsgi_cheaper_algo_backlog(int can_spawn) { int i; #ifdef __linux__ int backlog = uwsgi.shared->backlog; #else int backlog = 0; #endif if (can_spawn && backlog > (int) uwsgi.cheaper_overload) { // activate the first available worker (taking step into account) int decheaped = 0; // search for cheaped workers for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].cheaped == 1 && uwsgi.workers[i].pid == 0) { decheaped++; if (decheaped >= uwsgi.cheaper_step) break; } } // return the maximum number of workers to spawn return decheaped; } else if (backlog < (int) uwsgi.cheaper_overload) { int active_workers = 0; for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) { active_workers++; } } if (active_workers > uwsgi.cheaper_count) { return -1; } } return 0; } // reload uWSGI, close unneded file descriptor, restore the original environment and re-exec the binary void uwsgi_reload(char **argv) { int i; int waitpid_status; // hack for removing garbage generated by embedded loaders (like pyuwsgi) if (uwsgi.new_argc) { char **tmp_argv = argv; for(;;) { char *arg = *tmp_argv; if (!arg) break; if (strlen(arg) == 0) { *tmp_argv = NULL; } tmp_argv++; } } if (!uwsgi.master_is_reforked) { // call a series of waitpid to ensure all processes (gateways, mules and daemons) are dead for (i = 0; i < (ushared->gateways_cnt + uwsgi.daemons_cnt + uwsgi.mules_cnt); i++) { waitpid(WAIT_ANY, &waitpid_status, WNOHANG); } // call master cleanup hooks uwsgi_master_cleanup_hooks(); if (uwsgi.exit_on_reload) { uwsgi_log("uWSGI: GAME OVER (insert coin)\n"); exit(0); } // call atexit user exec uwsgi_exec_atexit(); uwsgi_log("binary reloading uWSGI...\n"); } else { uwsgi_log("fork()'ing uWSGI...\n"); } // ask for configuration (if needed) if (uwsgi.has_emperor && uwsgi.emperor_fd_config > -1) { char byte = 2; if (write(uwsgi.emperor_fd, &byte, 1) != 1) { uwsgi_error("uwsgi_reload()/write()"); } } uwsgi_log("chdir() to %s\n", uwsgi.cwd); if (chdir(uwsgi.cwd)) { uwsgi_error("uwsgi_reload()/chdir()"); } /* check fd table (a module can obviosly open some fd on initialization...) */ uwsgi_log("closing all non-uwsgi socket fds > 2 (max_fd = %d)...\n", (int) uwsgi.max_fd); for (i = 3; i < (int) uwsgi.max_fd; i++) { if (uwsgi.close_on_exec2) fcntl(i, F_SETFD, 0); if (uwsgi_fd_is_safe(i)) continue; int found = 0; struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (i == uwsgi_sock->fd) { uwsgi_log("found fd %d mapped to socket %d (%s)\n", i, uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name); found = 1; break; } uwsgi_sock = uwsgi_sock->next; } uwsgi_sock = uwsgi.shared_sockets; while (uwsgi_sock) { if (i == uwsgi_sock->fd) { uwsgi_log("found fd %d mapped to shared socket %d (%s)\n", i, uwsgi_get_shared_socket_num(uwsgi_sock), uwsgi_sock->name); found = 1; break; } uwsgi_sock = uwsgi_sock->next; } if (found) continue; if (uwsgi.has_emperor) { if (i == uwsgi.emperor_fd) { continue; } if (i == uwsgi.emperor_fd_config) { continue; } } if (uwsgi.alarm_thread) { if (i == uwsgi.alarm_thread->queue) continue; if (i == uwsgi.alarm_thread->pipe[0]) continue; if (i == uwsgi.alarm_thread->pipe[1]) continue; } if (uwsgi.log_master) { if (uwsgi.original_log_fd > -1) { if (i == uwsgi.original_log_fd) { continue; } } if (uwsgi.shared->worker_log_pipe[0] > -1) { if (i == uwsgi.shared->worker_log_pipe[0]) { continue; } } if (uwsgi.shared->worker_log_pipe[1] > -1) { if (i == uwsgi.shared->worker_log_pipe[1]) { continue; } } } #ifdef __APPLE__ fcntl(i, F_SETFD, FD_CLOEXEC); #else close(i); #endif } #ifndef UWSGI_IPCSEM_ATEXIT // free ipc semaphores if in use if (uwsgi.lock_engine && !strcmp(uwsgi.lock_engine, "ipcsem")) { uwsgi_ipcsem_clear(); } #endif uwsgi_log("running %s\n", uwsgi.binary_path); uwsgi_flush_logs(); argv[0] = uwsgi.binary_path; //strcpy (argv[0], uwsgi.binary_path); if (uwsgi.log_master) { if (uwsgi.original_log_fd > -1) { dup2(uwsgi.original_log_fd, 1); dup2(1, 2); } if (uwsgi.shared->worker_log_pipe[0] > -1) { close(uwsgi.shared->worker_log_pipe[0]); } if (uwsgi.shared->worker_log_pipe[1] > -1) { close(uwsgi.shared->worker_log_pipe[1]); } } execvp(uwsgi.binary_path, argv); uwsgi_error("execvp()"); // never here exit(1); } void uwsgi_fixup_fds(int wid, int muleid, struct uwsgi_gateway *ug) { int i; if (uwsgi.master_process) { if (uwsgi.master_queue > -1) close(uwsgi.master_queue); // close gateways if (!ug) { for (i = 0; i < ushared->gateways_cnt; i++) { close(ushared->gateways[i].internal_subscription_pipe[0]); close(ushared->gateways[i].internal_subscription_pipe[1]); } } struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets; while (ugs) { if (ug && !strcmp(ug->name, ugs->owner)) { ugs = ugs->next; continue; } // do not close shared sockets !!! if (!ugs->shared) { close(ugs->fd); } ugs = ugs->next; } // fix the communication pipe close(uwsgi.shared->worker_signal_pipe[0]); for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].signal_pipe[0] != -1) close(uwsgi.workers[i].signal_pipe[0]); if (i != wid) { if (uwsgi.workers[i].signal_pipe[1] != -1) close(uwsgi.workers[i].signal_pipe[1]); } } if (uwsgi.shared->spooler_signal_pipe[0] != -1) close(uwsgi.shared->spooler_signal_pipe[0]); if (uwsgi.i_am_a_spooler && uwsgi.i_am_a_spooler->pid != getpid()) { if (uwsgi.shared->spooler_signal_pipe[1] != -1) close(uwsgi.shared->spooler_signal_pipe[1]); } if (uwsgi.shared->mule_signal_pipe[0] != -1) close(uwsgi.shared->mule_signal_pipe[0]); if (muleid == 0) { if (uwsgi.shared->mule_signal_pipe[1] != -1) close(uwsgi.shared->mule_signal_pipe[1]); if (uwsgi.shared->mule_queue_pipe[1] != -1) close(uwsgi.shared->mule_queue_pipe[1]); } for (i = 0; i < uwsgi.mules_cnt; i++) { if (uwsgi.mules[i].signal_pipe[0] != -1) close(uwsgi.mules[i].signal_pipe[0]); if (muleid != i + 1) { if (uwsgi.mules[i].signal_pipe[1] != -1) close(uwsgi.mules[i].signal_pipe[1]); if (uwsgi.mules[i].queue_pipe[1] != -1) close(uwsgi.mules[i].queue_pipe[1]); } } for (i = 0; i < uwsgi.farms_cnt; i++) { if (uwsgi.farms[i].signal_pipe[0] != -1) close(uwsgi.farms[i].signal_pipe[0]); if (muleid == 0) { if (uwsgi.farms[i].signal_pipe[1] != -1) close(uwsgi.farms[i].signal_pipe[1]); if (uwsgi.farms[i].queue_pipe[1] != -1) close(uwsgi.farms[i].queue_pipe[1]); } } if (uwsgi.master_fifo_fd > -1) close(uwsgi.master_fifo_fd); if (uwsgi.notify_socket_fd > -1) close(uwsgi.notify_socket_fd); #ifdef __linux__ for(i=0;ifd); uafd = uafd->next; } } } int uwsgi_respawn_worker(int wid) { int respawns = uwsgi.workers[wid].respawn_count; // the workers is not accepting (obviously) uwsgi.workers[wid].accepting = 0; // we count the respawns before errors... uwsgi.workers[wid].respawn_count++; // ... same for update time uwsgi.workers[wid].last_spawn = uwsgi.current_time; // ... and memory/harakiri uwsgi.workers[wid].harakiri = 0; uwsgi.workers[wid].user_harakiri = 0; uwsgi.workers[wid].pending_harakiri = 0; uwsgi.workers[wid].rss_size = 0; uwsgi.workers[wid].vsz_size = 0; // ... reset stopped_at uwsgi.workers[wid].cursed_at = 0; uwsgi.workers[wid].no_mercy_at = 0; // internal statuses should be reset too uwsgi.workers[wid].cheaped = 0; // SUSPENSION is managed by the user, not the master... //uwsgi.workers[wid].suspended = 0; uwsgi.workers[wid].sig = 0; // this is required for various checks uwsgi.workers[wid].delta_requests = 0; int i; if (uwsgi.threaded_logger) { pthread_mutex_lock(&uwsgi.threaded_logger_lock); } for (i = 0; i < 256; i++) { if (uwsgi.p[i]->pre_uwsgi_fork) { uwsgi.p[i]->pre_uwsgi_fork(); } } pid_t pid = uwsgi_fork(uwsgi.workers[wid].name); if (pid == 0) { for (i = 0; i < 256; i++) { if (uwsgi.p[i]->post_uwsgi_fork) { uwsgi.p[i]->post_uwsgi_fork(1); } } signal(SIGWINCH, worker_wakeup); signal(SIGTSTP, worker_wakeup); uwsgi.mywid = wid; uwsgi.mypid = getpid(); // pid is updated by the master //uwsgi.workers[uwsgi.mywid].pid = uwsgi.mypid; // OVERENGINEERING (just to be safe) uwsgi.workers[uwsgi.mywid].id = uwsgi.mywid; /* uwsgi.workers[uwsgi.mywid].harakiri = 0; uwsgi.workers[uwsgi.mywid].user_harakiri = 0; uwsgi.workers[uwsgi.mywid].rss_size = 0; uwsgi.workers[uwsgi.mywid].vsz_size = 0; */ // do not reset worker counters on reload !!! //uwsgi.workers[uwsgi.mywid].requests = 0; // ...but maintain a delta counter (yes this is racy in multithread) //uwsgi.workers[uwsgi.mywid].delta_requests = 0; //uwsgi.workers[uwsgi.mywid].failed_requests = 0; //uwsgi.workers[uwsgi.mywid].respawn_count++; //uwsgi.workers[uwsgi.mywid].last_spawn = uwsgi.current_time; uwsgi.workers[uwsgi.mywid].manage_next_request = 1; /* uwsgi.workers[uwsgi.mywid].cheaped = 0; uwsgi.workers[uwsgi.mywid].suspended = 0; uwsgi.workers[uwsgi.mywid].sig = 0; */ // reset the apps count with a copy from the master uwsgi.workers[uwsgi.mywid].apps_cnt = uwsgi.workers[0].apps_cnt; // reset wsgi_request structures for(i=0;imaster_fixup) { uwsgi.p[i]->master_fixup(1); } } } } return 1; } else if (pid < 1) { uwsgi_error("fork()"); } else { for (i = 0; i < 256; i++) { if (uwsgi.p[i]->post_uwsgi_fork) { uwsgi.p[i]->post_uwsgi_fork(0); } } // the pid is set only in the master, as the worker should never use it uwsgi.workers[wid].pid = pid; if (respawns > 0) { uwsgi_log("Respawned uWSGI worker %d (new pid: %d)\n", wid, (int) pid); } else { uwsgi_log("spawned uWSGI worker %d (pid: %d, cores: %d)\n", wid, pid, uwsgi.cores); } } if (uwsgi.threaded_logger) { pthread_mutex_unlock(&uwsgi.threaded_logger_lock); } return 0; } struct uwsgi_stats *uwsgi_master_generate_stats() { int i; struct uwsgi_stats *us = uwsgi_stats_new(8192); if (uwsgi_stats_keyval_comma(us, "version", UWSGI_VERSION)) goto end; #ifdef __linux__ if (uwsgi_stats_keylong_comma(us, "listen_queue", (unsigned long long) uwsgi.shared->backlog)) goto end; if (uwsgi_stats_keylong_comma(us, "listen_queue_errors", (unsigned long long) uwsgi.shared->backlog_errors)) goto end; #endif int signal_queue = 0; if (ioctl(uwsgi.shared->worker_signal_pipe[1], FIONREAD, &signal_queue)) { uwsgi_error("uwsgi_master_generate_stats() -> ioctl()\n"); } if (uwsgi_stats_keylong_comma(us, "signal_queue", (unsigned long long) signal_queue)) goto end; if (uwsgi_stats_keylong_comma(us, "load", (unsigned long long) uwsgi.shared->load)) goto end; if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) getpid())) goto end; if (uwsgi_stats_keylong_comma(us, "uid", (unsigned long long) getuid())) goto end; if (uwsgi_stats_keylong_comma(us, "gid", (unsigned long long) getgid())) goto end; char *cwd = uwsgi_get_cwd(); if (uwsgi_stats_keyval_comma(us, "cwd", cwd)) { free(cwd); goto end; } free(cwd); if (uwsgi.daemons) { if (uwsgi_stats_key(us, "daemons")) goto end; if (uwsgi_stats_list_open(us)) goto end; struct uwsgi_daemon *ud = uwsgi.daemons; while (ud) { if (uwsgi_stats_object_open(us)) goto end; // allocate 2x the size of original command // in case we need to escape all chars char *cmd = uwsgi_malloc((strlen(ud->command)*2)+1); escape_json(ud->command, strlen(ud->command), cmd); if (uwsgi_stats_keyval_comma(us, "cmd", cmd)) { free(cmd); goto end; } free(cmd); if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) (ud->pid < 0) ? 0 : ud->pid)) goto end; if (uwsgi_stats_keylong(us, "respawns", (unsigned long long) ud->respawns ? 0 : ud->respawns)) goto end; if (uwsgi_stats_object_close(us)) goto end; if (ud->next) { if (uwsgi_stats_comma(us)) goto end; } ud = ud->next; } if (uwsgi_stats_list_close(us)) goto end; if (uwsgi_stats_comma(us)) goto end; } if (uwsgi_stats_key(us, "locks")) goto end; if (uwsgi_stats_list_open(us)) goto end; struct uwsgi_lock_item *uli = uwsgi.registered_locks; while (uli) { if (uwsgi_stats_object_open(us)) goto end; if (uwsgi_stats_keylong(us, uli->id, (unsigned long long) uli->pid)) goto end; if (uwsgi_stats_object_close(us)) goto end; if (uli->next) { if (uwsgi_stats_comma(us)) goto end; } uli = uli->next; } if (uwsgi_stats_list_close(us)) goto end; if (uwsgi_stats_comma(us)) goto end; if (uwsgi.caches) { if (uwsgi_stats_key(us, "caches")) goto end; if (uwsgi_stats_list_open(us)) goto end; struct uwsgi_cache *uc = uwsgi.caches; while(uc) { if (uwsgi_stats_object_open(us)) goto end; if (uwsgi_stats_keyval_comma(us, "name", uc->name ? uc->name : "default")) goto end; if (uwsgi_stats_keyval_comma(us, "hash", uc->hash->name)) goto end; if (uwsgi_stats_keylong_comma(us, "hashsize", (unsigned long long) uc->hashsize)) goto end; if (uwsgi_stats_keylong_comma(us, "keysize", (unsigned long long) uc->keysize)) goto end; if (uwsgi_stats_keylong_comma(us, "max_items", (unsigned long long) uc->max_items)) goto end; if (uwsgi_stats_keylong_comma(us, "blocks", (unsigned long long) uc->blocks)) goto end; if (uwsgi_stats_keylong_comma(us, "blocksize", (unsigned long long) uc->blocksize)) goto end; if (uwsgi_stats_keylong_comma(us, "items", (unsigned long long) uc->n_items)) goto end; if (uwsgi_stats_keylong_comma(us, "hits", (unsigned long long) uc->hits)) goto end; if (uwsgi_stats_keylong_comma(us, "miss", (unsigned long long) uc->miss)) goto end; if (uwsgi_stats_keylong_comma(us, "full", (unsigned long long) uc->full)) goto end; if (uwsgi_stats_keylong(us, "last_modified_at", (unsigned long long) uc->last_modified_at)) goto end; if (uwsgi_stats_object_close(us)) goto end; if (uc->next) { if (uwsgi_stats_comma(us)) goto end; } uc = uc->next; } if (uwsgi_stats_list_close(us)) goto end; if (uwsgi_stats_comma(us)) goto end; } if (uwsgi.has_metrics && !uwsgi.stats_no_metrics) { if (uwsgi_stats_key(us, "metrics")) goto end; if (uwsgi_stats_object_open(us)) goto end; uwsgi_rlock(uwsgi.metrics_lock); struct uwsgi_metric *um = uwsgi.metrics; while(um) { int64_t um_val = *um->value; if (uwsgi_stats_key(us, um->name)) { uwsgi_rwunlock(uwsgi.metrics_lock); goto end; } if (uwsgi_stats_object_open(us)) { uwsgi_rwunlock(uwsgi.metrics_lock); goto end; } if (uwsgi_stats_keylong(us, "type", (long long) um->type)) { uwsgi_rwunlock(uwsgi.metrics_lock); goto end; } if (uwsgi_stats_comma(us)) { uwsgi_rwunlock(uwsgi.metrics_lock); goto end; } if (uwsgi_stats_keyval_comma(us, "oid", um->oid ? um->oid : "")) { uwsgi_rwunlock(uwsgi.metrics_lock); goto end; } if (uwsgi_stats_keyslong(us, "value", (long long) um_val)) { uwsgi_rwunlock(uwsgi.metrics_lock); goto end; } if (uwsgi_stats_object_close(us)) { uwsgi_rwunlock(uwsgi.metrics_lock); goto end; } um = um->next; if (um) { if (uwsgi_stats_comma(us)) { uwsgi_rwunlock(uwsgi.metrics_lock); goto end; } } } uwsgi_rwunlock(uwsgi.metrics_lock); if (uwsgi_stats_object_close(us)) goto end; if (uwsgi_stats_comma(us)) goto end; } if (uwsgi_stats_key(us, "sockets")) goto end; if (uwsgi_stats_list_open(us)) goto end; struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_stats_object_open(us)) goto end; if (uwsgi_stats_keyval_comma(us, "name", uwsgi_sock->name)) goto end; if (uwsgi_stats_keyval_comma(us, "proto", uwsgi_sock->proto_name ? uwsgi_sock->proto_name : "uwsgi")) goto end; if (uwsgi_stats_keylong_comma(us, "queue", (unsigned long long) uwsgi_sock->queue)) goto end; if (uwsgi_stats_keylong_comma(us, "max_queue", (unsigned long long) uwsgi_sock->max_queue)) goto end; if (uwsgi_stats_keylong_comma(us, "shared", (unsigned long long) uwsgi_sock->shared)) goto end; if (uwsgi_stats_keylong(us, "can_offload", (unsigned long long) uwsgi_sock->can_offload)) goto end; if (uwsgi_stats_object_close(us)) goto end; uwsgi_sock = uwsgi_sock->next; if (uwsgi_sock) { if (uwsgi_stats_comma(us)) goto end; } } if (uwsgi_stats_list_close(us)) goto end; if (uwsgi_stats_comma(us)) goto end; if (uwsgi_stats_key(us, "workers")) goto end; if (uwsgi_stats_list_open(us)) goto end; for (i = 0; i < uwsgi.numproc; i++) { if (uwsgi_stats_object_open(us)) goto end; if (uwsgi_stats_keylong_comma(us, "id", (unsigned long long) uwsgi.workers[i + 1].id)) goto end; if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) uwsgi.workers[i + 1].pid)) goto end; if (uwsgi_stats_keylong_comma(us, "accepting", (unsigned long long) uwsgi.workers[i + 1].accepting)) goto end; if (uwsgi_stats_keylong_comma(us, "requests", (unsigned long long) uwsgi.workers[i + 1].requests)) goto end; if (uwsgi_stats_keylong_comma(us, "delta_requests", (unsigned long long) uwsgi.workers[i + 1].delta_requests)) goto end; if (uwsgi_stats_keylong_comma(us, "exceptions", (unsigned long long) uwsgi_worker_exceptions(i + 1))) goto end; if (uwsgi_stats_keylong_comma(us, "harakiri_count", (unsigned long long) uwsgi.workers[i + 1].harakiri_count)) goto end; if (uwsgi_stats_keylong_comma(us, "signals", (unsigned long long) uwsgi.workers[i + 1].signals)) goto end; if (ioctl(uwsgi.workers[i + 1].signal_pipe[1], FIONREAD, &signal_queue)) { uwsgi_error("uwsgi_master_generate_stats() -> ioctl()\n"); } if (uwsgi_stats_keylong_comma(us, "signal_queue", (unsigned long long) signal_queue)) goto end; if (uwsgi.workers[i + 1].cheaped) { if (uwsgi_stats_keyval_comma(us, "status", "cheap")) goto end; } else if (uwsgi.workers[i + 1].suspended && !uwsgi_worker_is_busy(i+1)) { if (uwsgi_stats_keyval_comma(us, "status", "pause")) goto end; } else { if (uwsgi.workers[i + 1].sig) { if (uwsgi_stats_keyvalnum_comma(us, "status", "sig", (unsigned long long) uwsgi.workers[i + 1].signum)) goto end; } else if (uwsgi_worker_is_busy(i+1)) { if (uwsgi_stats_keyval_comma(us, "status", "busy")) goto end; } else { if (uwsgi_stats_keyval_comma(us, "status", "idle")) goto end; } } if (uwsgi_stats_keylong_comma(us, "rss", (unsigned long long) uwsgi.workers[i + 1].rss_size)) goto end; if (uwsgi_stats_keylong_comma(us, "vsz", (unsigned long long) uwsgi.workers[i + 1].vsz_size)) goto end; if (uwsgi_stats_keylong_comma(us, "running_time", (unsigned long long) uwsgi.workers[i + 1].running_time)) goto end; if (uwsgi_stats_keylong_comma(us, "last_spawn", (unsigned long long) uwsgi.workers[i + 1].last_spawn)) goto end; if (uwsgi_stats_keylong_comma(us, "respawn_count", (unsigned long long) uwsgi.workers[i + 1].respawn_count)) goto end; if (uwsgi_stats_keylong_comma(us, "tx", (unsigned long long) uwsgi.workers[i + 1].tx)) goto end; if (uwsgi_stats_keylong_comma(us, "avg_rt", (unsigned long long) uwsgi.workers[i + 1].avg_response_time)) goto end; // applications list if (uwsgi_stats_key(us, "apps")) goto end; if (uwsgi_stats_list_open(us)) goto end; int j; for (j = 0; j < uwsgi.workers[i + 1].apps_cnt; j++) { struct uwsgi_app *ua = &uwsgi.workers[i + 1].apps[j]; if (uwsgi_stats_object_open(us)) goto end; if (uwsgi_stats_keylong_comma(us, "id", (unsigned long long) j)) goto end; if (uwsgi_stats_keylong_comma(us, "modifier1", (unsigned long long) ua->modifier1)) goto end; if (uwsgi_stats_keyvaln_comma(us, "mountpoint", ua->mountpoint, ua->mountpoint_len)) goto end; if (uwsgi_stats_keylong_comma(us, "startup_time", ua->startup_time)) goto end; if (uwsgi_stats_keylong_comma(us, "requests", ua->requests)) goto end; if (uwsgi_stats_keylong_comma(us, "exceptions", ua->exceptions)) goto end; if (*ua->chdir) { if (uwsgi_stats_keyval(us, "chdir", ua->chdir)) goto end; } else { if (uwsgi_stats_keyval(us, "chdir", "")) goto end; } if (uwsgi_stats_object_close(us)) goto end; if (j < uwsgi.workers[i + 1].apps_cnt - 1) { if (uwsgi_stats_comma(us)) goto end; } } if (uwsgi_stats_list_close(us)) goto end; if (uwsgi.stats_no_cores) goto nocores; if (uwsgi_stats_comma(us)) goto end; // cores list if (uwsgi_stats_key(us, "cores")) goto end; if (uwsgi_stats_list_open(us)) goto end; for (j = 0; j < uwsgi.cores; j++) { struct uwsgi_core *uc = &uwsgi.workers[i + 1].cores[j]; if (uwsgi_stats_object_open(us)) goto end; if (uwsgi_stats_keylong_comma(us, "id", (unsigned long long) j)) goto end; if (uwsgi_stats_keylong_comma(us, "requests", (unsigned long long) uc->requests)) goto end; if (uwsgi_stats_keylong_comma(us, "static_requests", (unsigned long long) uc->static_requests)) goto end; if (uwsgi_stats_keylong_comma(us, "routed_requests", (unsigned long long) uc->routed_requests)) goto end; if (uwsgi_stats_keylong_comma(us, "offloaded_requests", (unsigned long long) uc->offloaded_requests)) goto end; if (uwsgi_stats_keylong_comma(us, "write_errors", (unsigned long long) uc->write_errors)) goto end; if (uwsgi_stats_keylong_comma(us, "read_errors", (unsigned long long) uc->read_errors)) goto end; if (uwsgi_stats_keylong_comma(us, "in_request", (unsigned long long) uc->in_request)) goto end; if (uwsgi_stats_key(us, "vars")) goto end; if (uwsgi_stats_list_open(us)) goto end; if (uwsgi_stats_dump_vars(us, uc)) goto end; if (uwsgi_stats_list_close(us)) goto end; if (uwsgi_stats_comma(us)) goto end; if (uwsgi_stats_key(us, "req_info")) goto end; if (uwsgi_stats_object_open(us)) goto end; if (uwsgi_stats_dump_request(us, uc)) goto end; if (uwsgi_stats_object_close(us)) goto end; if (uwsgi_stats_object_close(us)) goto end; if (j < uwsgi.cores - 1) { if (uwsgi_stats_comma(us)) goto end; } } if (uwsgi_stats_list_close(us)) goto end; nocores: if (uwsgi_stats_object_close(us)) goto end; if (i < uwsgi.numproc - 1) { if (uwsgi_stats_comma(us)) goto end; } } if (uwsgi_stats_list_close(us)) goto end; struct uwsgi_spooler *uspool = uwsgi.spoolers; if (uspool) { if (uwsgi_stats_comma(us)) goto end; if (uwsgi_stats_key(us, "spoolers")) goto end; if (uwsgi_stats_list_open(us)) goto end; while (uspool) { if (uwsgi_stats_object_open(us)) goto end; if (uwsgi_stats_keyval_comma(us, "dir", uspool->dir)) goto end; if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) uspool->pid)) goto end; if (uwsgi_stats_keylong_comma(us, "tasks", (unsigned long long) uspool->tasks)) goto end; if (uwsgi_stats_keylong_comma(us, "respawns", (unsigned long long) uspool->respawned)) goto end; if (uwsgi_stats_keylong(us, "running", (unsigned long long) uspool->running)) goto end; if (uwsgi_stats_object_close(us)) goto end; uspool = uspool->next; if (uspool) { if (uwsgi_stats_comma(us)) goto end; } } if (uwsgi_stats_list_close(us)) goto end; } struct uwsgi_cron *ucron = uwsgi.crons; if (ucron) { if (uwsgi_stats_comma(us)) goto end; if (uwsgi_stats_key(us, "crons")) goto end; if (uwsgi_stats_list_open(us)) goto end; while (ucron) { if (uwsgi_stats_object_open(us)) goto end; if (uwsgi_stats_keyslong_comma(us, "minute", (long long) ucron->minute)) goto end; if (uwsgi_stats_keyslong_comma(us, "hour", (long long) ucron->hour)) goto end; if (uwsgi_stats_keyslong_comma(us, "day", (long long) ucron->day)) goto end; if (uwsgi_stats_keyslong_comma(us, "month", (long long) ucron->month)) goto end; if (uwsgi_stats_keyslong_comma(us, "week", (long long) ucron->week)) goto end; char *cmd = uwsgi_malloc((strlen(ucron->command)*2)+1); escape_json(ucron->command, strlen(ucron->command), cmd); if (uwsgi_stats_keyval_comma(us, "command", cmd)) { free(cmd); goto end; } free(cmd); if (uwsgi_stats_keylong_comma(us, "unique", (unsigned long long) ucron->unique)) goto end; #ifdef UWSGI_SSL if (uwsgi_stats_keyval_comma(us, "legion", ucron->legion ? ucron->legion : "")) goto end; #endif if (uwsgi_stats_keyslong_comma(us, "pid", (long long) ucron->pid)) goto end; if (uwsgi_stats_keylong(us, "started_at", (unsigned long long) ucron->started_at)) goto end; if (uwsgi_stats_object_close(us)) goto end; ucron = ucron->next; if (ucron) { if (uwsgi_stats_comma(us)) goto end; } } if (uwsgi_stats_list_close(us)) goto end; } #ifdef UWSGI_SSL struct uwsgi_legion *legion = NULL; if (uwsgi.legions) { if (uwsgi_stats_comma(us)) goto end; if (uwsgi_stats_key(us, "legions")) goto end; if (uwsgi_stats_list_open(us)) goto end; legion = uwsgi.legions; while (legion) { if (uwsgi_stats_object_open(us)) goto end; if (uwsgi_stats_keyval_comma(us, "legion", legion->legion)) goto end; if (uwsgi_stats_keyval_comma(us, "addr", legion->addr)) goto end; if (uwsgi_stats_keyval_comma(us, "uuid", legion->uuid)) goto end; if (uwsgi_stats_keylong_comma(us, "valor", (unsigned long long) legion->valor)) goto end; if (uwsgi_stats_keylong_comma(us, "checksum", (unsigned long long) legion->checksum)) goto end; if (uwsgi_stats_keylong_comma(us, "quorum", (unsigned long long) legion->quorum)) goto end; if (uwsgi_stats_keylong_comma(us, "i_am_the_lord", (unsigned long long) legion->i_am_the_lord)) goto end; if (uwsgi_stats_keylong_comma(us, "lord_valor", (unsigned long long) legion->lord_valor)) goto end; if (uwsgi_stats_keyvaln_comma(us, "lord_uuid", legion->lord_uuid, 36)) goto end; // legion nodes start if (uwsgi_stats_key(us, "nodes")) goto end; if (uwsgi_stats_list_open(us)) goto end; struct uwsgi_string_list *nodes = legion->nodes; while (nodes) { if (uwsgi_stats_str(us, nodes->value)) goto end; nodes = nodes->next; if (nodes) { if (uwsgi_stats_comma(us)) goto end; } } if (uwsgi_stats_list_close(us)) goto end; if (uwsgi_stats_comma(us)) goto end; // legion members start if (uwsgi_stats_key(us, "members")) goto end; if (uwsgi_stats_list_open(us)) goto end; uwsgi_rlock(legion->lock); struct uwsgi_legion_node *node = legion->nodes_head; while (node) { if (uwsgi_stats_object_open(us)) goto unlock_legion_mutex; if (uwsgi_stats_keyvaln_comma(us, "name", node->name, node->name_len)) goto unlock_legion_mutex; if (uwsgi_stats_keyval_comma(us, "uuid", node->uuid)) goto unlock_legion_mutex; if (uwsgi_stats_keylong_comma(us, "valor", (unsigned long long) node->valor)) goto unlock_legion_mutex; if (uwsgi_stats_keylong_comma(us, "checksum", (unsigned long long) node->checksum)) goto unlock_legion_mutex; if (uwsgi_stats_keylong(us, "last_seen", (unsigned long long) node->last_seen)) goto unlock_legion_mutex; if (uwsgi_stats_object_close(us)) goto unlock_legion_mutex; node = node->next; if (node) { if (uwsgi_stats_comma(us)) goto unlock_legion_mutex; } } uwsgi_rwunlock(legion->lock); if (uwsgi_stats_list_close(us)) goto end; // legion nodes end if (uwsgi_stats_object_close(us)) goto end; legion = legion->next; if (legion) { if (uwsgi_stats_comma(us)) goto end; } } if (uwsgi_stats_list_close(us)) goto end; } #endif if (uwsgi_stats_object_close(us)) goto end; return us; #ifdef UWSGI_SSL unlock_legion_mutex: if (legion) uwsgi_rwunlock(legion->lock); #endif end: free(us->base); free(us); return NULL; } void uwsgi_register_cheaper_algo(char *name, int (*func) (int)) { struct uwsgi_cheaper_algo *uca = uwsgi.cheaper_algos; if (!uca) { uwsgi.cheaper_algos = uwsgi_malloc(sizeof(struct uwsgi_cheaper_algo)); uca = uwsgi.cheaper_algos; } else { while (uca) { if (!uca->next) { uca->next = uwsgi_malloc(sizeof(struct uwsgi_cheaper_algo)); uca = uca->next; break; } uca = uca->next; } } uca->name = name; uca->func = func; uca->next = NULL; #ifdef UWSGI_DEBUG uwsgi_log("[uwsgi-cheaper-algo] registered \"%s\"\n", uca->name); #endif } void trigger_harakiri(int i) { int j; uwsgi_log_verbose("*** HARAKIRI ON WORKER %d (pid: %d, try: %d, graceful: %s) ***\n", i, uwsgi.workers[i].pid, uwsgi.workers[i].pending_harakiri + 1, uwsgi.workers[i].pending_harakiri > 0 ? "no": "yes"); if (uwsgi.harakiri_verbose) { #ifdef __linux__ int proc_file; char proc_buf[4096]; char proc_name[64]; ssize_t proc_len; if (snprintf(proc_name, 64, "/proc/%d/syscall", uwsgi.workers[i].pid) > 0) { memset(proc_buf, 0, 4096); proc_file = open(proc_name, O_RDONLY); if (proc_file >= 0) { proc_len = read(proc_file, proc_buf, 4096); if (proc_len > 0) { uwsgi_log("HARAKIRI: -- syscall> %s", proc_buf); } close(proc_file); } } if (snprintf(proc_name, 64, "/proc/%d/wchan", uwsgi.workers[i].pid) > 0) { memset(proc_buf, 0, 4096); proc_file = open(proc_name, O_RDONLY); if (proc_file >= 0) { proc_len = read(proc_file, proc_buf, 4096); if (proc_len > 0) { uwsgi_log("HARAKIRI: -- wchan> %s\n", proc_buf); } close(proc_file); } } #endif } if (uwsgi.workers[i].pid > 0) { for (j = 0; j < uwsgi.gp_cnt; j++) { if (uwsgi.gp[j]->harakiri) { uwsgi.gp[j]->harakiri(i); } } for (j = 0; j < 256; j++) { if (uwsgi.p[j]->harakiri) { uwsgi.p[j]->harakiri(i); } } uwsgi_dump_worker(i, "HARAKIRI"); if (uwsgi.workers[i].pending_harakiri == 0 && uwsgi.harakiri_graceful_timeout > 0) { kill(uwsgi.workers[i].pid, uwsgi.harakiri_graceful_signal); } else { kill(uwsgi.workers[i].pid, SIGKILL); } if (!uwsgi.workers[i].pending_harakiri) uwsgi.workers[i].harakiri_count++; uwsgi.workers[i].pending_harakiri++; } } void uwsgi_master_fix_request_counters() { int i; uint64_t total_counter = 0; for (i = 1; i <= uwsgi.numproc;i++) { uint64_t tmp_counter = 0; int j; for(j=0;jtm_min % abs(minute)) == 0) { uc_minute = uwsgi_cron_delta->tm_min; } } if (hour < 0) { if ((uwsgi_cron_delta->tm_hour % abs(hour)) == 0) { uc_hour = uwsgi_cron_delta->tm_hour; } } if (month < 0) { if ((uwsgi_cron_delta->tm_mon % abs(month)) == 0) { uc_month = uwsgi_cron_delta->tm_mon; } } if (day < 0) { if ((uwsgi_cron_delta->tm_mday % abs(day)) == 0) { uc_day = uwsgi_cron_delta->tm_mday; } } if (week < 0) { if ((uwsgi_cron_delta->tm_wday % abs(week)) == 0) { uc_week = uwsgi_cron_delta->tm_wday; } } int run_task = 0; // mday and wday are ORed if (day >= 0 && week >= 0) { if (uwsgi_cron_delta->tm_min == uc_minute && uwsgi_cron_delta->tm_hour == uc_hour && uwsgi_cron_delta->tm_mon == uc_month && (uwsgi_cron_delta->tm_mday == uc_day || uwsgi_cron_delta->tm_wday == uc_week)) { run_task = 1; } } else { if (uwsgi_cron_delta->tm_min == uc_minute && uwsgi_cron_delta->tm_hour == uc_hour && uwsgi_cron_delta->tm_mon == uc_month && uwsgi_cron_delta->tm_mday == uc_day && uwsgi_cron_delta->tm_wday == uc_week) { run_task = 1; } } return run_task; } static void add_reload_fds(struct uwsgi_string_list *list, char *type) { struct uwsgi_string_list *usl = list; while(usl) { char *strc = uwsgi_str(usl->value); char *space = strchr(strc, ' '); if (space) { *space = 0; usl->custom_ptr = space+1; } char *colon = strchr(strc, ':'); if (colon) { *colon = 0; usl->custom2 = strtoul(colon+1, NULL, 10); } usl->custom = strtoul(strc, NULL, 10); if (!usl->custom2) usl->custom2 = 1; event_queue_add_fd_read(uwsgi.master_queue, usl->custom); uwsgi_add_safe_fd(usl->custom); uwsgi_log("added %s reload monitor for fd %d (read size: %llu)\n", type, (int) usl->custom, usl->custom2); usl = usl->next; } } void uwsgi_add_reload_fds() { add_reload_fds(uwsgi.reload_on_fd, "graceful"); add_reload_fds(uwsgi.brutal_reload_on_fd, "brutal"); } void uwsgi_refork_master() { pid_t pid = fork(); if (pid < 0) { uwsgi_error("uwsgi_refork_master()/fork()"); return; } if (pid > 0) { uwsgi_log_verbose("new master copy spawned with pid %d\n", (int) pid); return; } // detach from the old master setsid(); uwsgi.master_is_reforked = 1; uwsgi_reload(uwsgi.argv); // never here exit(1); } void uwsgi_cheaper_increase() { uwsgi.cheaper_fifo_delta++; } void uwsgi_cheaper_decrease() { uwsgi.cheaper_fifo_delta--; } void uwsgi_go_cheap() { int i; int waitpid_status; if (uwsgi.status.is_cheap) return; uwsgi_log_verbose("going cheap...\n"); uwsgi.status.is_cheap = 1; for (i = 1; i <= uwsgi.numproc; i++) { uwsgi.workers[i].cheaped = 1; uwsgi.workers[i].rss_size = 0; uwsgi.workers[i].vsz_size = 0; if (uwsgi.workers[i].pid == 0) continue; uwsgi_log("killing worker %d (pid: %d)\n", i, (int) uwsgi.workers[i].pid); kill(uwsgi.workers[i].pid, SIGKILL); if (waitpid(uwsgi.workers[i].pid, &waitpid_status, 0) < 0) { if (errno != ECHILD) uwsgi_error("uwsgi_go_cheap()/waitpid()"); } } uwsgi_add_sockets_to_queue(uwsgi.master_queue, -1); uwsgi_log("cheap mode enabled: waiting for socket connection...\n"); } #ifdef __linux__ void uwsgi_setns_preopen() { struct dirent *de; DIR *ns = opendir("/proc/self/ns"); if (!ns) { uwsgi_error("uwsgi_setns_preopen()/opendir()"); exit(1); } while ((de = readdir(ns)) != NULL) { if (strlen(de->d_name) > 0 && de->d_name[0] == '.') continue; if (!strcmp(de->d_name, "user")) continue; struct uwsgi_string_list *usl = NULL; int found = 0; uwsgi_foreach(usl, uwsgi.setns_socket_skip) { if (!strcmp(de->d_name, usl->value)) { found = 1; break; } } if (found) continue; char *filename = uwsgi_concat2("/proc/self/ns/", de->d_name); uwsgi.setns_fds[uwsgi.setns_fds_count] = open(filename, O_RDONLY); if (uwsgi.setns_fds[uwsgi.setns_fds_count] < 0) { uwsgi_error_open(filename); free(filename); exit(1); } free(filename); uwsgi.setns_fds_count++; } closedir(ns); } void uwsgi_master_manage_setns(int fd) { struct sockaddr_un snsun; socklen_t snsun_len = sizeof(struct sockaddr_un); int setns_client = accept(fd, (struct sockaddr *) &snsun, &snsun_len); if (setns_client < 0) { uwsgi_error("uwsgi_master_manage_setns()/accept()"); return; } int i; int tmp_fds[64]; int *fds = tmp_fds; int num_fds = 0; struct msghdr sn_msg; void *sn_msg_control; struct iovec sn_iov[2]; struct cmsghdr *cmsg; DIR *ns = NULL; if (uwsgi.setns_fds_count) { fds = uwsgi.setns_fds; num_fds = uwsgi.setns_fds_count; goto send; } struct dirent *de; ns = opendir("/proc/self/ns"); if (!ns) { close(setns_client); uwsgi_error("uwsgi_master_manage_setns()/opendir()"); return; } while ((de = readdir(ns)) != NULL) { if (strlen(de->d_name) > 0 && de->d_name[0] == '.') continue; if (!strcmp(de->d_name, "user")) continue; struct uwsgi_string_list *usl = NULL; int found = 0; uwsgi_foreach(usl, uwsgi.setns_socket_skip) { if (!strcmp(de->d_name, usl->value)) { found = 1; break; } } if (found) continue; char *filename = uwsgi_concat2("/proc/self/ns/", de->d_name); fds[num_fds] = open(filename, O_RDONLY); if (fds[num_fds] < 0) { uwsgi_error_open(filename); free(filename); goto clear; } free(filename); num_fds++; } send: sn_msg_control = uwsgi_malloc(CMSG_SPACE(sizeof(int) * num_fds)); sn_iov[0].iov_base = "uwsgi-setns"; sn_iov[0].iov_len = 11; sn_iov[1].iov_base = &num_fds; sn_iov[1].iov_len = sizeof(int); sn_msg.msg_name = NULL; sn_msg.msg_namelen = 0; sn_msg.msg_iov = sn_iov; sn_msg.msg_iovlen = 2; sn_msg.msg_flags = 0; sn_msg.msg_control = sn_msg_control; sn_msg.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds); cmsg = CMSG_FIRSTHDR(&sn_msg); cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; int *sn_fd_ptr = (int *) CMSG_DATA(cmsg); for(i=0;ireq; if (uc->in_request) { uwsgi_log_verbose("%s [core %d] %.*s - %.*s %.*s since %llu\n", msg, i, wsgi_req->remote_addr_len, wsgi_req->remote_addr, wsgi_req->method_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri, (unsigned long long) (wsgi_req->start_of_request/(1000*1000))); } } uwsgi_log_verbose("%s !!! end of worker %d status !!!\n",msg, wid); } uwsgi-2.0.29/core/metrics.c000066400000000000000000000763051477626554400155430ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; /* uWSGI metrics subsystem a metric is a node in a linked list reachable via a numeric id (OID, in SNMP way) or a simple string: uwsgi.worker.1.requests uwsgi.custom.foo.bar the oid representation: 1.3.6.1.4.1.35156.17 = iso.org.dod.internet.private.enterprise.unbit.uwsgi 1.3.6.1.4.1.35156.17.3.1.1 = iso.org.dod.internet.private.enterprise.unbit.uwsgi.worker.1.requests 1.3.6.1.4.1.35156.17.3.1.1 = iso.org.dod.internet.private.enterprise.unbit.uwsgi.worker.1.requests 1.3.6.1.4.1.35156.17.3.1.2.1.1 = iso.org.dod.internet.private.enterprise.unbit.uwsgi.worker.1.core.1.requests ... each metric is a collected value with a specific frequency metrics are meant for numeric values signed 64 bit, but they can be exposed as: gauge counter absolute metrics are managed by a dedicated thread (in the master) holding a linked list of all the items. For few metrics it is a good (read: simple) approach, but you can cache lookups in a uWSGI cache for really big list. (TODO) struct uwsgi_metric *um = uwsgi_register_metric("worker.1.requests", "3.1.1", UWSGI_METRIC_COUNTER, "ptr", &uwsgi.workers[1].requests, 0, NULL); prototype: struct uwsgi_metric *uwsgi_register_metric(char *name, char *oid, uint8_t value_type, char *collector, void *ptr, uint32_t freq, void *custom); value_type = UWSGI_METRIC_COUNTER/UWSGI_METRIC_GAUGE/UWSGI_METRIC_ABSOLUTE collect_way = "ptr" -> get from a pointer / UWSGI_METRIC_FUNC -> get from a func with the prototype int64_t func(struct uwsgi_metric *); / UWSGI_METRIC_FILE -> get the value from a file, ptr is the filename For some metric (or all ?) you may want to hold a value even after a server reload. For such a reason you can specify a directory on wich the server (on startup/restart) will look for a file named like the metric and will read the initial value from it. It may look an old-fashioned and quite inefficient way, but it is the most versatile for a sysadmin (allowing him/her to even modify the values manually) When registering a metric with the same name of an already registered one, the new one will overwrite the previous one. This allows plugins writer to override default behaviours Applications are allowed to update metrics (but they cannot register new ones), with simple api funcs: uwsgi.metric_set("worker.1.requests", N) uwsgi.metric_inc("worker.1.requests", N=1) uwsgi.metric_dec("worker.1.requests", N=1) uwsgi.metric_mul("worker.1.requests", N=1) uwsgi.metric_div("worker.1.requests", N=1) and obviously they can get values: uwsgi.metric_get("worker.1.requests") Updating metrics from your app MUST BE ATOMIC, for such a reason a uWSGI rwlock is initialized on startup and used for each operation (simple reading from a metric does not require locking) Metrics can be updated from the internal routing subsystem too: route-if = equal:${REQUEST_URI};/foobar metricinc:foobar.test 2 and can be accessed as ${metric[foobar.test]} The stats server exports the metrics list in the "metrics" attribute (obviously some info could be redundant) */ int64_t uwsgi_metric_collector_file(struct uwsgi_metric *metric) { char *filename = metric->arg1; if (!filename) return 0; int split_pos = metric->arg1n; char buf[4096]; int64_t ret = 0; int fd = open(filename, O_RDONLY); if (fd < 0) { uwsgi_error_open(filename); return 0; } ssize_t rlen = read(fd, buf, 4096); if (rlen <= 0) goto end; char *ptr = buf; ssize_t i; int pos = 0; int found = 0; for(i=0;i= '0' && buf[i] <= '9') || (buf[i] >= 'a' && buf[i] <= 'z') || (buf[i] >= 'A' && buf[i] <= 'Z') || buf[i] == '.' || buf[i] == '-' || buf[i] == '_' )) { return 0; } } return 1; } /* allowed chars for metrics oid 0-9 . oids can be null */ static int uwsgi_validate_metric_oid(char *buf) { if (!buf) return 1; size_t len = strlen(buf); size_t i; for(i=0;i= '0' && buf[i] <= '9') || buf[i] == '.' )) { return 0; } } return 1; } void uwsgi_metric_append(struct uwsgi_metric *um) { struct uwsgi_metric *old_metric=NULL,*metric=uwsgi.metrics; while(metric) { old_metric = metric; metric = metric->next; } if (old_metric) { old_metric->next = um; } else { uwsgi.metrics = um; } uwsgi.metrics_cnt++; } struct uwsgi_metric_collector *uwsgi_metric_collector_by_name(char *name) { if (!name) return NULL; struct uwsgi_metric_collector *umc = uwsgi.metric_collectors; while(umc) { if (!strcmp(name, umc->name)) return umc; umc = umc->next; } uwsgi_log("unable to find metric collector \"%s\"\n", name); exit(1); } struct uwsgi_metric *uwsgi_register_metric_do(char *name, char *oid, uint8_t value_type, char *collector, void *ptr, uint32_t freq, void *custom, int do_not_push) { if (!uwsgi.has_metrics) return NULL; struct uwsgi_metric *old_metric=NULL,*metric=uwsgi.metrics; if (!uwsgi_validate_metric_name(name)) { uwsgi_log("invalid metric name: %s\n", name); exit(1); } if (!uwsgi_validate_metric_oid(oid)) { uwsgi_log("invalid metric oid: %s\n", oid); exit(1); } while(metric) { if (!strcmp(metric->name, name)) { goto found; } old_metric = metric; metric = metric->next; } metric = uwsgi_calloc(sizeof(struct uwsgi_metric)); // always make a copy of the name (so we can use stack for building strings) metric->name = uwsgi_str(name); metric->name_len = strlen(metric->name); if (!do_not_push) { if (old_metric) { old_metric->next = metric; } else { uwsgi.metrics = metric; } uwsgi.metrics_cnt++; } found: metric->oid = oid; if (metric->oid) { metric->oid_len = strlen(oid); metric->oid = uwsgi_str(oid); char *p, *ctx = NULL; char *oid_tmp = uwsgi_str(metric->oid); // slower but we save lot of memory struct uwsgi_buffer *ub = uwsgi_buffer_new(1); uwsgi_foreach_token(oid_tmp, ".", p, ctx) { uint64_t l = strtoull(p, NULL, 10); if (uwsgi_base128(ub, l, 1)) { uwsgi_log("unable to encode oid %s to asn/ber\n", metric->oid); exit(1); } } metric->asn = ub->buf; metric->asn_len = ub->pos; ub->buf = NULL; uwsgi_buffer_destroy(ub); free(oid_tmp); } metric->type = value_type; metric->collector = uwsgi_metric_collector_by_name(collector); metric->ptr = ptr; metric->freq = freq; if (!metric->freq) metric->freq = 1; metric->custom = custom; if (uwsgi.metrics_dir) { char *filename = uwsgi_concat3(uwsgi.metrics_dir, "/", name); int fd = open(filename, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP); if (fd < 0) { uwsgi_error_open(filename); exit(1); } // fill the file if (lseek(fd, uwsgi.page_size-1, SEEK_SET) < 0) { uwsgi_error("uwsgi_register_metric()/lseek()"); uwsgi_log("unable to register metric: %s\n", name); exit(1); } if (write(fd, "\0", 1) != 1) { uwsgi_error("uwsgi_register_metric()/write()"); uwsgi_log("unable to register metric: %s\n", name); exit(1); } metric->map = mmap(NULL, uwsgi.page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (metric->map == MAP_FAILED) { uwsgi_error("uwsgi_register_metric()/mmap()"); uwsgi_log("unable to register metric: %s\n", name); exit(1); } // we can now safely close the file descriptor and update the file from memory close(fd); free(filename); } return metric; } struct uwsgi_metric *uwsgi_register_metric(char *name, char *oid, uint8_t value_type, char *collector, void *ptr, uint32_t freq, void *custom) { return uwsgi_register_metric_do(name, oid, value_type, collector, ptr, freq, custom, 0); } struct uwsgi_metric *uwsgi_register_keyval_metric(char *arg) { char *m_name = NULL; char *m_oid = NULL; char *m_type = NULL; char *m_collector = NULL; char *m_freq = NULL; char *m_arg1 = NULL; char *m_arg2 = NULL; char *m_arg3 = NULL; char *m_arg1n = NULL; char *m_arg2n = NULL; char *m_arg3n = NULL; char *m_initial_value = NULL; char *m_children = NULL; char *m_alias = NULL; char *m_reset_after_push = NULL; if (!strchr(arg, '=')) { m_name = uwsgi_str(arg); } else if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=', "name", &m_name, "oid", &m_oid, "type", &m_type, "initial_value", &m_initial_value, "collector", &m_collector, "freq", &m_freq, "arg1", &m_arg1, "arg2", &m_arg2, "arg3", &m_arg3, "arg1n", &m_arg1n, "arg2n", &m_arg2n, "arg3n", &m_arg3n, "children", &m_children, "alias", &m_alias, "reset_after_push", &m_reset_after_push, NULL)) { uwsgi_log("invalid metric keyval syntax: %s\n", arg); exit(1); } if (!m_name) { uwsgi_log("you need to specify a metric name: %s\n", arg); exit(1); } uint8_t type = UWSGI_METRIC_COUNTER; char *collector = NULL; uint32_t freq = 0; int64_t initial_value = 0; if (m_type) { if (!strcmp(m_type, "gauge")) { type = UWSGI_METRIC_GAUGE; } else if (!strcmp(m_type, "absolute")) { type = UWSGI_METRIC_ABSOLUTE; } else if (!strcmp(m_type, "alias")) { type = UWSGI_METRIC_ALIAS; } } if (m_collector) { collector = m_collector; } if (m_freq) freq = strtoul(m_freq, NULL, 10); if (m_initial_value) { initial_value = strtoll(m_initial_value, NULL, 10); } struct uwsgi_metric* um = uwsgi_register_metric(m_name, m_oid, type, collector, NULL, freq, NULL); um->initial_value = initial_value; if (m_reset_after_push){ um->reset_after_push = 1; } if (m_children) { char *p, *ctx = NULL; uwsgi_foreach_token(m_children, ";", p, ctx) { struct uwsgi_metric *child = uwsgi_metric_find_by_name(p); if (!child) { uwsgi_log("unable to find metric \"%s\"\n", p); exit(1); } uwsgi_metric_add_child(um, child); } } if (m_alias) { struct uwsgi_metric *alias = uwsgi_metric_find_by_name(m_alias); if (!alias) { uwsgi_log("unable to find metric \"%s\"\n", m_alias); exit(1); } um->ptr = (void *) alias; } um->arg1 = m_arg1; um->arg2 = m_arg2; um->arg3 = m_arg3; if (m_arg1n) um->arg1n = strtoll(m_arg1n, NULL, 10); if (m_arg2n) um->arg2n = strtoll(m_arg2n, NULL, 10); if (m_arg3n) um->arg3n = strtoll(m_arg3n, NULL, 10); free(m_name); if (m_oid) free(m_oid); if (m_type) free(m_type); if (m_collector) free(m_collector); if (m_freq) free(m_freq); /* DO NOT FREE THEM if (m_arg1) free(m_arg1); if (m_arg2) free(m_arg2); if (m_arg3) free(m_arg3); */ if (m_arg1n) free(m_arg1n); if (m_arg2n) free(m_arg2n); if (m_arg3n) free(m_arg3n); if (m_initial_value) free(m_initial_value); if (m_children) free(m_children); if (m_alias) free(m_alias); if (m_reset_after_push) free(m_reset_after_push); return um; } static void *uwsgi_metrics_loop(void *arg) { // block signals on this thread sigset_t smask; sigfillset(&smask); #ifndef UWSGI_DEBUG sigdelset(&smask, SIGSEGV); #endif pthread_sigmask(SIG_BLOCK, &smask, NULL); for(;;) { struct uwsgi_metric *metric = uwsgi.metrics; // every second scan the whole metrics tree time_t now = uwsgi_now(); while(metric) { if (!metric->last_update) { metric->last_update = now; } else { if ((uint32_t) (now - metric->last_update) < metric->freq) goto next; } uwsgi_wlock(uwsgi.metrics_lock); int64_t value = *metric->value; // gather the new value based on the type of collection strategy if (metric->collector) { *metric->value = metric->initial_value + metric->collector->func(metric); } int64_t new_value = *metric->value; uwsgi_rwunlock(uwsgi.metrics_lock); metric->last_update = now; if (uwsgi.metrics_dir && metric->map) { if (value != new_value) { int ret = snprintf(metric->map, uwsgi.page_size, "%lld\n", (long long) new_value); if (ret > 0 && ret < uwsgi.page_size) { memset(metric->map+ret, 0, 4096-ret); } } } // thresholds; struct uwsgi_metric_threshold *umt = metric->thresholds; while(umt) { if (new_value >= umt->value) { if (umt->reset) { uwsgi_wlock(uwsgi.metrics_lock); *metric->value = umt->reset_value; uwsgi_rwunlock(uwsgi.metrics_lock); } if (umt->alarm) { if (umt->last_alarm + umt->rate <= now) { if (umt->msg) { uwsgi_alarm_trigger(umt->alarm, umt->msg, umt->msg_len); } else { uwsgi_alarm_trigger(umt->alarm, metric->name, metric->name_len); } umt->last_alarm = now; } } } umt = umt->next; } next: metric = metric->next; } sleep(1); } return NULL; } void uwsgi_metrics_start_collector() { if (!uwsgi.has_metrics) return; pthread_t t; pthread_create(&t, NULL, uwsgi_metrics_loop, NULL); uwsgi_log("metrics collector thread started\n"); } struct uwsgi_metric *uwsgi_metric_find_by_name(char *name) { struct uwsgi_metric *um = uwsgi.metrics; while(um) { if (!strcmp(um->name, name)) { return um; } um = um->next; } return NULL; } struct uwsgi_metric *uwsgi_metric_find_by_namen(char *name, size_t len) { struct uwsgi_metric *um = uwsgi.metrics; while(um) { if (!uwsgi_strncmp(um->name, um->name_len, name, len)) { return um; } um = um->next; } return NULL; } struct uwsgi_metric_child *uwsgi_metric_add_child(struct uwsgi_metric *parent, struct uwsgi_metric *child) { struct uwsgi_metric_child *umc = parent->children, *old_umc = NULL; while(umc) { old_umc = umc; umc = umc->next; } umc = uwsgi_calloc(sizeof(struct uwsgi_metric_child)); umc->um = child; if (old_umc) { old_umc->next = umc; } else { parent->children = umc; } return umc; } struct uwsgi_metric *uwsgi_metric_find_by_oid(char *oid) { struct uwsgi_metric *um = uwsgi.metrics; while(um) { if (um->oid && !strcmp(um->oid, oid)) { return um; } um = um->next; } return NULL; } struct uwsgi_metric *uwsgi_metric_find_by_oidn(char *oid, size_t len) { struct uwsgi_metric *um = uwsgi.metrics; while(um) { if (um->oid && !uwsgi_strncmp(um->oid, um->oid_len, oid, len)) { return um; } um = um->next; } return NULL; } struct uwsgi_metric *uwsgi_metric_find_by_asn(char *asn, size_t len) { struct uwsgi_metric *um = uwsgi.metrics; while(um) { if (um->oid && um->asn && !uwsgi_strncmp(um->asn, um->asn_len, asn, len)) { return um; } um = um->next; } return NULL; } /* api functions metric_set metric_inc metric_dec metric_mul metric_div */ #define um_op struct uwsgi_metric *um = NULL;\ if (!uwsgi.has_metrics) return -1;\ if (name) {\ um = uwsgi_metric_find_by_name(name);\ }\ else if (oid) {\ um = uwsgi_metric_find_by_oid(oid);\ }\ if (!um) return -1;\ if (um->collector || um->type == UWSGI_METRIC_ALIAS) return -1;\ uwsgi_wlock(uwsgi.metrics_lock) int uwsgi_metric_set(char *name, char *oid, int64_t value) { um_op; *um->value = value; uwsgi_rwunlock(uwsgi.metrics_lock); return 0; } int uwsgi_metric_inc(char *name, char *oid, int64_t value) { um_op; *um->value += value; uwsgi_rwunlock(uwsgi.metrics_lock); return 0; } int uwsgi_metric_dec(char *name, char *oid, int64_t value) { um_op; *um->value -= value; uwsgi_rwunlock(uwsgi.metrics_lock); return 0; } int uwsgi_metric_mul(char *name, char *oid, int64_t value) { um_op; *um->value *= value; uwsgi_rwunlock(uwsgi.metrics_lock); return 0; } int uwsgi_metric_div(char *name, char *oid, int64_t value) { // avoid division by zero if (value == 0) return -1; um_op; *um->value /= value; uwsgi_rwunlock(uwsgi.metrics_lock); return 0; } int64_t uwsgi_metric_get(char *name, char *oid) { if (!uwsgi.has_metrics) return 0; int64_t ret = 0; struct uwsgi_metric *um = NULL; if (name) { um = uwsgi_metric_find_by_name(name); } else if (oid) { um = uwsgi_metric_find_by_oid(oid); } if (!um) return 0; // now (in rlocked context) we get the value from // the map uwsgi_rlock(uwsgi.metrics_lock); ret = *um->value; // unlock uwsgi_rwunlock(uwsgi.metrics_lock); return ret; } int64_t uwsgi_metric_getn(char *name, size_t nlen, char *oid, size_t olen) { if (!uwsgi.has_metrics) return 0; int64_t ret = 0; struct uwsgi_metric *um = NULL; if (name) { um = uwsgi_metric_find_by_namen(name, nlen); } else if (oid) { um = uwsgi_metric_find_by_oidn(oid, olen); } if (!um) return 0; // now (in rlocked context) we get the value from // the map uwsgi_rlock(uwsgi.metrics_lock); ret = *um->value; // unlock uwsgi_rwunlock(uwsgi.metrics_lock); return ret; } int uwsgi_metric_set_max(char *name, char *oid, int64_t value) { um_op; if (value > *um->value) *um->value = value; uwsgi_rwunlock(uwsgi.metrics_lock); return 0; } int uwsgi_metric_set_min(char *name, char *oid, int64_t value) { um_op; if ((value > um->initial_value || 0) && value < *um->value) *um->value = value; uwsgi_rwunlock(uwsgi.metrics_lock); return 0; } #define uwsgi_metric_name(f, n) ret = snprintf(buf, 4096, f, n); if (ret <= 1 || ret >= 4096) { uwsgi_log("unable to register metric name %s\n", f); exit(1);} #define uwsgi_metric_name2(f, n, n2) ret = snprintf(buf, 4096, f, n, n2); if (ret <= 1 || ret >= 4096) { uwsgi_log("unable to register metric name %s\n", f); exit(1);} #define uwsgi_metric_oid(f, n) ret = snprintf(buf2, 4096, f, n); if (ret <= 1 || ret >= 4096) { uwsgi_log("unable to register metric oid %s\n", f); exit(1);} #define uwsgi_metric_oid2(f, n, n2) ret = snprintf(buf2, 4096, f, n, n2); if (ret <= 1 || ret >= 4096) { uwsgi_log("unable to register metric oid %s\n", f); exit(1);} void uwsgi_setup_metrics() { if (!uwsgi.has_metrics) return; char buf[4096]; char buf2[4096]; // create the main rwlock uwsgi.metrics_lock = uwsgi_rwlock_init("metrics"); // get realpath of the storage dir if (uwsgi.metrics_dir) { char *dir = uwsgi_expand_path(uwsgi.metrics_dir, strlen(uwsgi.metrics_dir), NULL); if (!dir) { uwsgi_error("uwsgi_setup_metrics()/uwsgi_expand_path()"); exit(1); } uwsgi.metrics_dir = dir; } // the 'core' namespace uwsgi_register_metric("core.routed_signals", "5.1", UWSGI_METRIC_COUNTER, "ptr", &uwsgi.shared->routed_signals, 0, NULL); uwsgi_register_metric("core.unrouted_signals", "5.2", UWSGI_METRIC_COUNTER, "ptr", &uwsgi.shared->unrouted_signals, 0, NULL); uwsgi_register_metric("core.busy_workers", "5.3", UWSGI_METRIC_GAUGE, "ptr", &uwsgi.shared->busy_workers, 0, NULL); uwsgi_register_metric("core.idle_workers", "5.4", UWSGI_METRIC_GAUGE, "ptr", &uwsgi.shared->idle_workers, 0, NULL); uwsgi_register_metric("core.overloaded", "5.5", UWSGI_METRIC_COUNTER, "ptr", &uwsgi.shared->overloaded, 0, NULL); // parents are appended only at the end struct uwsgi_metric *total_tx = uwsgi_register_metric_do("core.total_tx", "5.100", UWSGI_METRIC_COUNTER, "sum", NULL, 0, NULL, 1); struct uwsgi_metric *total_rss = uwsgi_register_metric_do("core.total_rss", "5.101", UWSGI_METRIC_GAUGE, "sum", NULL, 0, NULL, 1); struct uwsgi_metric *total_vsz = uwsgi_register_metric_do("core.total_vsz", "5.102", UWSGI_METRIC_GAUGE, "sum", NULL, 0, NULL, 1); struct uwsgi_metric *total_avg_rt = uwsgi_register_metric_do("core.avg_response_time", "5.103", UWSGI_METRIC_GAUGE, "avg", NULL, 0, NULL, 1); struct uwsgi_metric *total_running_time = uwsgi_register_metric_do("core.total_running_time", "5.104", UWSGI_METRIC_COUNTER, "sum", NULL, 0, NULL, 1); int ret; // create the 'worker' namespace int i; for(i=0;i<=uwsgi.numproc;i++) { uwsgi_metric_name("worker.%d.requests", i) ; uwsgi_metric_oid("3.%d.1", i); uwsgi_register_metric(buf, buf2, UWSGI_METRIC_COUNTER, "ptr", &uwsgi.workers[i].requests, 0, NULL); uwsgi_metric_name("worker.%d.delta_requests", i) ; uwsgi_metric_oid("3.%d.2", i); uwsgi_register_metric(buf, buf2, UWSGI_METRIC_ABSOLUTE, "ptr", &uwsgi.workers[i].delta_requests, 0, NULL); uwsgi_metric_name("worker.%d.failed_requests", i) ; uwsgi_metric_oid("3.%d.13", i); uwsgi_register_metric(buf, buf2, UWSGI_METRIC_COUNTER, "ptr", &uwsgi.workers[i].failed_requests, 0, NULL); uwsgi_metric_name("worker.%d.respawns", i) ; uwsgi_metric_oid("3.%d.14", i); uwsgi_register_metric(buf, buf2, UWSGI_METRIC_COUNTER, "ptr", &uwsgi.workers[i].respawn_count, 0, NULL); uwsgi_metric_name("worker.%d.avg_response_time", i) ; uwsgi_metric_oid("3.%d.8", i); struct uwsgi_metric *avg_rt = uwsgi_register_metric(buf, buf2, UWSGI_METRIC_GAUGE, "ptr", &uwsgi.workers[i].avg_response_time, 0, NULL); if (i > 0) uwsgi_metric_add_child(total_avg_rt, avg_rt); uwsgi_metric_name("worker.%d.total_tx", i) ; uwsgi_metric_oid("3.%d.9", i); struct uwsgi_metric *tx = uwsgi_register_metric(buf, buf2, UWSGI_METRIC_COUNTER, "ptr", &uwsgi.workers[i].tx, 0, NULL); if (i > 0) uwsgi_metric_add_child(total_tx, tx); uwsgi_metric_name("worker.%d.rss_size", i) ; uwsgi_metric_oid("3.%d.11", i); struct uwsgi_metric *rss = uwsgi_register_metric(buf, buf2, UWSGI_METRIC_GAUGE, "ptr", &uwsgi.workers[i].rss_size, 0, NULL); if (i > 0) uwsgi_metric_add_child(total_rss, rss); uwsgi_metric_name("worker.%d.vsz_size", i) ; uwsgi_metric_oid("3.%d.12", i); struct uwsgi_metric *vsz = uwsgi_register_metric(buf, buf2, UWSGI_METRIC_GAUGE, "ptr", &uwsgi.workers[i].vsz_size, 0, NULL); if (i > 0) uwsgi_metric_add_child(total_vsz, vsz); uwsgi_metric_name("worker.%d.running_time", i) ; uwsgi_metric_oid("3.%d.13", i); struct uwsgi_metric *running_time = uwsgi_register_metric(buf, buf2, UWSGI_METRIC_COUNTER, "ptr", &uwsgi.workers[i].running_time, 0, NULL); if (i > 0) uwsgi_metric_add_child(total_running_time, running_time); // skip core metrics for worker 0 if (i == 0) continue; if (uwsgi.metrics_no_cores) continue; int j; for(j=0;jqueue, 0, NULL); pos++; uwsgi_sock = uwsgi_sock->next; } // create aliases uwsgi_register_metric("rss_size", NULL, UWSGI_METRIC_ALIAS, NULL, total_rss, 0, NULL); uwsgi_register_metric("vsz_size", NULL, UWSGI_METRIC_ALIAS, NULL, total_vsz, 0, NULL); // create custom/user-defined metrics struct uwsgi_string_list *usl; uwsgi_foreach(usl, uwsgi.additional_metrics) { struct uwsgi_metric *um = uwsgi_register_keyval_metric(usl->value); if (um) { uwsgi_log("added custom metric: %s\n", um->name); } } // allocate shared memory int64_t *values = uwsgi_calloc_shared(sizeof(int64_t) * uwsgi.metrics_cnt); pos = 0; struct uwsgi_metric *metric = uwsgi.metrics; while(metric) { metric->value = &values[pos]; pos++; metric = metric->next; } // remap aliases metric = uwsgi.metrics; while(metric) { if (metric->type == UWSGI_METRIC_ALIAS) { struct uwsgi_metric *alias = (struct uwsgi_metric *) metric->ptr; if (!alias) { uwsgi_log("metric alias \"%s\" requires a mapping !!!\n", metric->name); exit(1); } metric->value = alias->value; metric->oid = alias->oid; } if (metric->initial_value) { *metric->value = metric->initial_value; } metric = metric->next; } // setup thresholds uwsgi_foreach(usl, uwsgi.metrics_threshold) { char *m_key = NULL; char *m_value = NULL; char *m_alarm = NULL; char *m_rate = NULL; char *m_reset = NULL; char *m_msg = NULL; if (uwsgi_kvlist_parse(usl->value, usl->len, ',', '=', "key", &m_key, "value", &m_value, "alarm", &m_alarm, "rate", &m_rate, "msg", &m_msg, "reset", &m_reset, NULL)) { uwsgi_log("invalid metric threshold keyval syntax: %s\n", usl->value); exit(1); } if (!m_key || !m_value) { uwsgi_log("metric's threshold requires a key and a value: %s\n", usl->value); exit(1); } struct uwsgi_metric *um = uwsgi_metric_find_by_name(m_key); if (!um) { uwsgi_log("unable to find metric %s\n", m_key); exit(1); } struct uwsgi_metric_threshold *umt = uwsgi_calloc(sizeof(struct uwsgi_metric_threshold)); umt->value = strtoll(m_value, NULL, 10); if (m_reset) { umt->reset = 1; umt->reset_value = strtoll(m_reset, NULL, 10); } if (m_rate) { umt->rate = (int32_t) atoi(m_rate); } umt->alarm = m_alarm; if (m_msg) { umt->msg = m_msg; umt->msg_len = strlen(m_msg); } free(m_key); free(m_value); if (m_rate) free(m_rate); if (m_reset) free(m_reset); if (um->thresholds) { struct uwsgi_metric_threshold *umt_list = um->thresholds; while(umt_list) { if (!umt_list->next) { umt_list->next = umt; break; } umt_list = umt_list->next; } } else { um->thresholds = umt; } uwsgi_log("added threshold for metric %s (value: %lld)\n", um->name, umt->value); } uwsgi_log("initialized %llu metrics\n", uwsgi.metrics_cnt); if (uwsgi.metrics_dir) { uwsgi_log("memory allocated for metrics storage: %llu bytes (%llu MB)\n", uwsgi.metrics_cnt * uwsgi.page_size, (uwsgi.metrics_cnt * uwsgi.page_size)/1024/1024); if (uwsgi.metrics_dir_restore) { metric = uwsgi.metrics; while(metric) { if (metric->map) { metric->initial_value = strtoll(metric->map, NULL, 10); } metric = metric->next; } } } } struct uwsgi_metric_collector *uwsgi_register_metric_collector(char *name, int64_t (*func)(struct uwsgi_metric *)) { struct uwsgi_metric_collector *collector = uwsgi.metric_collectors, *old_collector = NULL; while(collector) { if (!strcmp(collector->name, name)) goto found; old_collector = collector; collector = collector->next; } collector = uwsgi_calloc(sizeof(struct uwsgi_metric_collector)); collector->name = name; if (old_collector) { old_collector->next = collector; } else { uwsgi.metric_collectors = collector; } found: collector->func = func; return collector; } static int64_t uwsgi_metric_collector_ptr(struct uwsgi_metric *um) { return *um->ptr; } static int64_t uwsgi_metric_collector_sum(struct uwsgi_metric *um) { int64_t total = 0; struct uwsgi_metric_child *umc = um->children; while(umc) { struct uwsgi_metric *c = umc->um; total += *c->value; umc = umc->next; } return total; } static int64_t uwsgi_metric_collector_accumulator(struct uwsgi_metric *um) { int64_t total = *um->value; struct uwsgi_metric_child *umc = um->children; while(umc) { struct uwsgi_metric *c = umc->um; total += *c->value; umc = umc->next; } return total; } static int64_t uwsgi_metric_collector_multiplier(struct uwsgi_metric *um) { int64_t total = 0; struct uwsgi_metric_child *umc = um->children; while(umc) { struct uwsgi_metric *c = umc->um; total += *c->value; umc = umc->next; } return total * um->arg1n; } static int64_t uwsgi_metric_collector_adder(struct uwsgi_metric *um) { int64_t total = 0; struct uwsgi_metric_child *umc = um->children; while(umc) { struct uwsgi_metric *c = umc->um; total += *c->value; umc = umc->next; } return total + um->arg1n; } static int64_t uwsgi_metric_collector_avg(struct uwsgi_metric *um) { int64_t total = 0; int64_t count = 0; struct uwsgi_metric_child *umc = um->children; while(umc) { struct uwsgi_metric *c = umc->um; total += *c->value; count++; umc = umc->next; } if (count == 0) return 0; return total/count; } static int64_t uwsgi_metric_collector_func(struct uwsgi_metric *um) { if (!um->arg1) return 0; int64_t (*func)(struct uwsgi_metric *) = (int64_t (*)(struct uwsgi_metric *)) um->custom; if (!func) { func = dlsym(RTLD_DEFAULT, um->arg1); um->custom = func; } if (!func) return 0; return func(um); } void uwsgi_metrics_collectors_setup() { uwsgi_register_metric_collector("ptr", uwsgi_metric_collector_ptr); uwsgi_register_metric_collector("file", uwsgi_metric_collector_file); uwsgi_register_metric_collector("sum", uwsgi_metric_collector_sum); uwsgi_register_metric_collector("accumulator", uwsgi_metric_collector_accumulator); uwsgi_register_metric_collector("adder", uwsgi_metric_collector_adder); uwsgi_register_metric_collector("multiplier", uwsgi_metric_collector_multiplier); uwsgi_register_metric_collector("avg", uwsgi_metric_collector_avg); uwsgi_register_metric_collector("func", uwsgi_metric_collector_func); } uwsgi-2.0.29/core/mount.c000066400000000000000000000142511477626554400152270ustar00rootroot00000000000000#include "uwsgi.h" /* jail systems (Linux namespaces, FreeBSD jails...) heavily rely on mount/umount to simplify setups (expecially because the mount command could not be available in the initial phase of jailing, we need an api to mount/umount filesystems int uwsgi_mount(char *fs, char *what, char *where, int flags); int uwsgi_umount(char *where, int flags); */ #ifdef __linux__ #ifndef MS_REC #define MS_REC 16384 #endif #include #endif struct uwsgi_mount_flag { char *key; uint64_t value; }; static struct uwsgi_mount_flag umflags[] = { #ifdef MS_BIND {"bind", MS_BIND}, #endif #ifdef MS_DIRSYNC {"dirsync", MS_DIRSYNC}, #endif #ifdef MS_MANDLOCK {"mandlock", MS_MANDLOCK}, #endif #ifdef MS_MOVE {"move", MS_MOVE}, #endif #ifdef MS_NOATIME {"noatime", MS_NOATIME}, #endif #ifdef MS_NODEV {"nodev", MS_NODEV}, #endif #ifdef MS_NOEXEC {"noexec", MS_NOEXEC}, #endif #ifdef MS_RDONLY {"rdonly", MS_RDONLY}, {"readonly", MS_RDONLY}, {"ro", MS_RDONLY}, #endif #ifdef MS_REMOUNT {"remount", MS_REMOUNT}, #endif #ifdef MS_NOSUID {"nosuid", MS_NOSUID}, #endif #ifdef MS_SYNCHRONOUS {"sync", MS_SYNCHRONOUS}, #endif #ifdef MNT_FORCE {"force", MNT_FORCE}, #endif #ifdef MNT_DETACH {"detach", MNT_DETACH}, #endif #ifdef MS_REC {"rec", MS_REC}, {"recursive", MS_REC}, #endif #ifdef MS_PRIVATE {"private", MS_PRIVATE}, #endif #ifdef MS_SHARED {"shared", MS_SHARED}, #endif #ifdef MNT_RDONLY {"rdonly", MNT_RDONLY}, {"readonly", MNT_RDONLY}, {"ro", MNT_RDONLY}, #endif #ifdef MNT_NOEXEC {"noexec", MNT_NOEXEC}, #endif #ifdef MNT_NOSUID {"nosuid", MNT_NOSUID}, #endif #ifdef MNT_NOATIME {"noatime", MNT_NOATIME}, #endif #ifdef MNT_SNAPSHOT {"snapshot", MNT_SNAPSHOT}, #endif {NULL, 0}, }; uint64_t uwsgi_mount_flag(char *mflag) { struct uwsgi_mount_flag *umf = umflags; while(umf->key) { if (!strcmp(umf->key, mflag)) return umf->value; umf++; } return 0; } int uwsgi_mount(char *fs, char *what, char *where, char *flags, char *data) { #if defined(__linux__) || defined(__FreeBSD__) || defined(__GNU_kFreeBSD__) #if defined(__FreeBSD__) || defined(__GNU_kFreeBSD__) struct iovec iov[6]; #endif unsigned long mountflags = 0; if (!flags) goto parsed; char *mflags = uwsgi_str(flags); char *p, *ctx = NULL; uwsgi_foreach_token(mflags, ",", p, ctx) { unsigned long flag = (unsigned long) uwsgi_mount_flag(p); if (!flag) { uwsgi_log("unknown mount flag \"%s\"\n", p); exit(1); } mountflags |= flag; } free(mflags); parsed: #ifdef __linux__ return mount(what, where, fs, mountflags, data); #elif defined(__FreeBSD__) || defined(__GNU_kFreeBSD__) iov[0].iov_base = "fstype"; iov[0].iov_len = 7; iov[1].iov_base = fs; iov[1].iov_len = strlen(fs) + 1; iov[2].iov_base = "fspath"; iov[2].iov_len = 7; iov[3].iov_base = where; iov[3].iov_len = strlen(where) + 1; iov[4].iov_base = "target"; iov[4].iov_len = 7; iov[5].iov_base = what; iov[5].iov_len = strlen(what) + 1; return nmount(iov, 6, (int) mountflags); #endif #endif return -1; } int uwsgi_umount(char *where, char *flags) { #if defined(__linux__) || defined(__FreeBSD__) || defined(__GNU_kFreeBSD__) unsigned long mountflags = 0; if (!flags) goto parsed; char *mflags = uwsgi_str(flags); char *p, *ctx = NULL; uwsgi_foreach_token(mflags, ",", p, ctx) { unsigned long flag = (unsigned long) uwsgi_mount_flag(p); if (!flag) { uwsgi_log("unknown umount flag \"%s\"\n", p); exit(1); } mountflags |= flag; } free(mflags); parsed: #ifdef __linux__ // we need a special case for recursive umount if (mountflags & MS_REC) { mountflags &= ~MS_REC; int unmounted = 1; char *slashed = uwsgi_concat2(where, "/"); while (unmounted) { unmounted = 0; FILE *procmounts = fopen("/proc/self/mounts", "r"); if (!procmounts) { uwsgi_log("the /proc filesystem must be mounted for recursive umount\n"); uwsgi_error("open()"); exit(1); } char line[1024]; while (fgets(line, 1024, procmounts) != NULL) { char *delim0 = strchr(line, ' '); if (!delim0) continue; delim0++; char *delim1 = strchr(delim0, ' '); if (!delim1) continue; *delim1 = 0; if (!uwsgi_starts_with(delim0, strlen(delim0), slashed, strlen(slashed))) goto unmountable; continue; unmountable: if (!umount2(delim0, mountflags)) unmounted++; } fclose(procmounts); } free(slashed); } return umount2(where, mountflags); #elif defined(__FreeBSD__) || defined(__GNU_kFreeBSD__) return unmount(where, mountflags); #endif #endif return -1; } int uwsgi_mount_hook(char *arg) { char *data = NULL; char *tmp_arg = uwsgi_str(arg); char *fs = tmp_arg; char *what = strchr(fs, ' '); if (!what) goto error; *what = 0; what++; char *where = strchr(what, ' '); if (!where) goto error; *where = 0; where++; char *flags = strchr(where, ' '); if (flags) { *flags = 0; flags++; data = strchr(flags, ' '); if (data) { *data = 0; data++; } } if (uwsgi_mount(fs, what, where, flags, data)) { uwsgi_error("uwsgi_mount()"); free(tmp_arg); return -1; } free(tmp_arg); return 0; error: free(tmp_arg); uwsgi_log("uwsgi_mount_hook() invalid syntax\n"); return -1; } int uwsgi_umount_hook(char *arg) { char *tmp_arg = uwsgi_str(arg); char *where = tmp_arg; char *flags = strchr(where, ' '); if (flags) { *flags = 0; flags++; } if (uwsgi_umount(where, flags)) { uwsgi_error("uwsgi_umount()"); free(tmp_arg); return -1; } free(tmp_arg); return 0; } int uwsgi_check_mountpoint(char *mountpoint) { #ifdef __linux__ struct statfs sfs; int ret = statfs(mountpoint, &sfs); if (ret) { uwsgi_error("uwsgi_check_mountpoint()/statfs()"); return -1; } return 0; #else uwsgi_log("this platform does not support mountpoints check !!!\n"); return -1; #endif } uwsgi-2.0.29/core/mule.c000066400000000000000000000267761477626554400150460ustar00rootroot00000000000000/* uWSGI mules are very simple workers only managing signals or running custom code in background. By default they born in signal-only mode, but if you patch them (passing the script/code to run) they will became fully customized daemons. */ #include "uwsgi.h" extern struct uwsgi_server uwsgi; void uwsgi_mule_handler(void); int mule_send_msg(int fd, char *message, size_t len) { socklen_t so_bufsize_len = sizeof(int); int so_bufsize = 0; if (write(fd, message, len) != (ssize_t) len) { if (errno == EAGAIN || errno == EWOULDBLOCK) { if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &so_bufsize, &so_bufsize_len)) { uwsgi_error("getsockopt()"); } uwsgi_log("*** MULE MSG QUEUE IS FULL: buffer size %d bytes (you can tune it with --mule-msg-size) ***\n", so_bufsize); } else { uwsgi_error("mule_send_msg()"); } return -1; } return 0; } void uwsgi_mule(int id) { int i; pid_t pid = uwsgi_fork(uwsgi.mules[id - 1].name); if (pid == 0) { #ifdef __linux__ if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) { uwsgi_error("prctl()"); } #endif signal(SIGALRM, SIG_IGN); signal(SIGHUP, end_me); signal(SIGINT, end_me); signal(SIGTERM, end_me); signal(SIGUSR1, SIG_IGN); signal(SIGUSR2, SIG_IGN); signal(SIGPIPE, SIG_IGN); signal(SIGSTOP, SIG_IGN); signal(SIGTSTP, SIG_IGN); uwsgi.muleid = id; // avoid race conditions uwsgi.mules[id - 1].id = id; uwsgi.mules[id - 1].pid = getpid(); uwsgi.mypid = uwsgi.mules[id - 1].pid; uwsgi_fixup_fds(0, id, NULL); uwsgi.my_signal_socket = uwsgi.mules[id - 1].signal_pipe[1]; uwsgi.signal_socket = uwsgi.shared->mule_signal_pipe[1]; uwsgi_close_all_sockets(); for (i = 0; i < 256; i++) { if (uwsgi.p[i]->master_fixup) { uwsgi.p[i]->master_fixup(1); } } for (i = 0; i < 256; i++) { if (uwsgi.p[i]->post_fork) { uwsgi.p[i]->post_fork(); } } uwsgi_hooks_run(uwsgi.hook_as_mule, "as-mule", 1); uwsgi_mule_run(); } else if (pid > 0) { uwsgi.mules[id - 1].id = id; uwsgi.mules[id - 1].pid = pid; uwsgi_log("spawned uWSGI mule %d (pid: %d)\n", id, (int) pid); } } void uwsgi_mule_run() { int id = uwsgi.muleid; int i; if (uwsgi.mules[id - 1].patch) { for (i = 0; i < 256; i++) { if (uwsgi.p[i]->mule) { if (uwsgi.p[i]->mule(uwsgi.mules[id - 1].patch) == 1) { // never here ? end_me(1); } } } } uwsgi_mule_handler(); } int uwsgi_farm_has_mule(struct uwsgi_farm *farm, int muleid) { struct uwsgi_mule_farm *umf = farm->mules; while (umf) { if (umf->mule->id == muleid) { return 1; } umf = umf->next; } return 0; } int farm_has_signaled(int fd) { int i; for (i = 0; i < uwsgi.farms_cnt; i++) { struct uwsgi_mule_farm *umf = uwsgi.farms[i].mules; while (umf) { if (umf->mule->id == uwsgi.muleid && uwsgi.farms[i].signal_pipe[1] == fd) { return 1; } umf = umf->next; } } return 0; } int farm_has_msg(int fd) { int i; for (i = 0; i < uwsgi.farms_cnt; i++) { struct uwsgi_mule_farm *umf = uwsgi.farms[i].mules; while (umf) { if (umf->mule->id == uwsgi.muleid && uwsgi.farms[i].queue_pipe[1] == fd) { return 1; } umf = umf->next; } } return 0; } void uwsgi_mule_add_farm_to_queue(int queue) { int i; for (i = 0; i < uwsgi.farms_cnt; i++) { if (uwsgi_farm_has_mule(&uwsgi.farms[i], uwsgi.muleid)) { event_queue_add_fd_read(queue, uwsgi.farms[i].signal_pipe[1]); event_queue_add_fd_read(queue, uwsgi.farms[i].queue_pipe[1]); } } } void uwsgi_mule_handler() { ssize_t len; uint8_t uwsgi_signal; int rlen; int interesting_fd; // this must be configurable char message[65536]; int mule_queue = event_queue_init(); event_queue_add_fd_read(mule_queue, uwsgi.signal_socket); event_queue_add_fd_read(mule_queue, uwsgi.my_signal_socket); event_queue_add_fd_read(mule_queue, uwsgi.mules[uwsgi.muleid - 1].queue_pipe[1]); event_queue_add_fd_read(mule_queue, uwsgi.shared->mule_queue_pipe[1]); uwsgi_mule_add_farm_to_queue(mule_queue); for (;;) { rlen = event_queue_wait(mule_queue, -1, &interesting_fd); if (rlen <= 0) { continue; } if (interesting_fd == uwsgi.signal_socket || interesting_fd == uwsgi.my_signal_socket || farm_has_signaled(interesting_fd)) { len = read(interesting_fd, &uwsgi_signal, 1); if (len <= 0) { if (len < 0 && (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)) continue; uwsgi_log_verbose("uWSGI mule %d braying: my master died, i will follow him...\n", uwsgi.muleid); end_me(0); } #ifdef UWSGI_DEBUG uwsgi_log_verbose("master sent signal %d to mule %d\n", uwsgi_signal, uwsgi.muleid); #endif if (uwsgi_signal_handler(uwsgi_signal)) { uwsgi_log_verbose("error managing signal %d on mule %d\n", uwsgi_signal, uwsgi.muleid); } } else if (interesting_fd == uwsgi.mules[uwsgi.muleid - 1].queue_pipe[1] || interesting_fd == uwsgi.shared->mule_queue_pipe[1] || farm_has_msg(interesting_fd)) { len = read(interesting_fd, message, 65536); if (len < 0) { if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) { uwsgi_error("uwsgi_mule_handler/read()"); } } else { int i, found = 0; for (i = 0; i < 256; i++) { if (uwsgi.p[i]->mule_msg) { if (uwsgi.p[i]->mule_msg(message, len)) { found = 1; break; } } } if (!found) uwsgi_log("*** mule %d received a %ld bytes message ***\n", uwsgi.muleid, (long) len); } } } } struct uwsgi_mule *get_mule_by_id(int id) { int i; for (i = 0; i < uwsgi.mules_cnt; i++) { if (uwsgi.mules[i].id == id) { return &uwsgi.mules[i]; } } return NULL; } struct uwsgi_farm *get_farm_by_name(char *name) { int i; for (i = 0; i < uwsgi.farms_cnt; i++) { if (!strcmp(uwsgi.farms[i].name, name)) { return &uwsgi.farms[i]; } } return NULL; } struct uwsgi_mule_farm *uwsgi_mule_farm_new(struct uwsgi_mule_farm **umf, struct uwsgi_mule *um) { struct uwsgi_mule_farm *uwsgi_mf = *umf, *old_umf; if (!uwsgi_mf) { *umf = uwsgi_malloc(sizeof(struct uwsgi_mule_farm)); uwsgi_mf = *umf; } else { while (uwsgi_mf) { old_umf = uwsgi_mf; uwsgi_mf = uwsgi_mf->next; } uwsgi_mf = uwsgi_malloc(sizeof(struct uwsgi_mule_farm)); old_umf->next = uwsgi_mf; } uwsgi_mf->mule = um; uwsgi_mf->next = NULL; return uwsgi_mf; } ssize_t uwsgi_mule_get_msg(int manage_signals, int manage_farms, char *message, size_t buffer_size, int timeout) { ssize_t len = 0; struct pollfd *mulepoll; int count = 4; int farms_count = 0; uint8_t uwsgi_signal; int i; if (uwsgi.muleid == 0) return -1; if (manage_signals) count = 2; if (!manage_farms) goto next; for (i = 0; i < uwsgi.farms_cnt; i++) { if (uwsgi_farm_has_mule(&uwsgi.farms[i], uwsgi.muleid)) farms_count++; } next: if (timeout > -1) timeout = timeout * 1000; mulepoll = uwsgi_malloc(sizeof(struct pollfd) * (count + farms_count)); mulepoll[0].fd = uwsgi.mules[uwsgi.muleid - 1].queue_pipe[1]; mulepoll[0].events = POLLIN; mulepoll[1].fd = uwsgi.shared->mule_queue_pipe[1]; mulepoll[1].events = POLLIN; if (count > 2) { mulepoll[2].fd = uwsgi.signal_socket; mulepoll[2].events = POLLIN; mulepoll[3].fd = uwsgi.my_signal_socket; mulepoll[3].events = POLLIN; } if (farms_count > 0) { int tmp_cnt = 0; for (i = 0; i < uwsgi.farms_cnt; i++) { if (uwsgi_farm_has_mule(&uwsgi.farms[i], uwsgi.muleid)) { mulepoll[count + tmp_cnt].fd = uwsgi.farms[i].queue_pipe[1]; mulepoll[count + tmp_cnt].events = POLLIN; tmp_cnt++; } } } int ret = -1; retry: ret = poll(mulepoll, count + farms_count, timeout); if (ret < 0) { uwsgi_error("uwsgi_mule_get_msg()/poll()"); } else if (ret > 0 ) { if (mulepoll[0].revents & POLLIN) { len = read(uwsgi.mules[uwsgi.muleid - 1].queue_pipe[1], message, buffer_size); } else if (mulepoll[1].revents & POLLIN) { len = read(uwsgi.shared->mule_queue_pipe[1], message, buffer_size); } else { if (count > 2) { int interesting_fd = -1; if (mulepoll[2].revents & POLLIN) { interesting_fd = mulepoll[2].fd; } else if (mulepoll[3].revents & POLLIN) { interesting_fd = mulepoll[3].fd; } if (interesting_fd > -1) { len = read(interesting_fd, &uwsgi_signal, 1); if (len <= 0) { if (uwsgi_is_again()) goto retry; uwsgi_log_verbose("uWSGI mule %d braying: my master died, i will follow him...\n", uwsgi.muleid); end_me(0); } #ifdef UWSGI_DEBUG uwsgi_log_verbose("master sent signal %d to mule %d\n", uwsgi_signal, uwsgi.muleid); #endif if (uwsgi_signal_handler(uwsgi_signal)) { uwsgi_log_verbose("error managing signal %d on mule %d\n", uwsgi_signal, uwsgi.muleid); } // set the error condition len = -1; goto clear; } } // read messages in the farm for (i = 0; i < farms_count; i++) { if (mulepoll[count + i].revents & POLLIN) { len = read(mulepoll[count + i].fd, message, buffer_size); break; } } } } if (len < 0) { if (uwsgi_is_again()) goto retry; uwsgi_error("read()"); goto clear; } clear: free(mulepoll); return len; } void uwsgi_opt_add_mule(char *opt, char *value, void *foobar) { uwsgi.mules_cnt++; uwsgi_string_new_list(&uwsgi.mules_patches, value); } void uwsgi_opt_add_mules(char *opt, char *value, void *foobar) { int i; for (i = 0; i < atoi(value); i++) { uwsgi.mules_cnt++; uwsgi_string_new_list(&uwsgi.mules_patches, NULL); } } void uwsgi_opt_add_farm(char *opt, char *value, void *foobar) { uwsgi.farms_cnt++; uwsgi_string_new_list(&uwsgi.farms_list, value); } void uwsgi_setup_mules_and_farms() { int i; if (uwsgi.mules_cnt > 0) { uwsgi.mules = (struct uwsgi_mule *) uwsgi_calloc_shared(sizeof(struct uwsgi_mule) * uwsgi.mules_cnt); create_signal_pipe(uwsgi.shared->mule_signal_pipe); create_msg_pipe(uwsgi.shared->mule_queue_pipe, uwsgi.mule_msg_size); for (i = 0; i < uwsgi.mules_cnt; i++) { // create the socket pipe create_signal_pipe(uwsgi.mules[i].signal_pipe); create_msg_pipe(uwsgi.mules[i].queue_pipe, uwsgi.mule_msg_size); uwsgi.mules[i].id = i + 1; snprintf(uwsgi.mules[i].name, 0xff, "uWSGI mule %d", i + 1); } } if (uwsgi.farms_cnt > 0) { uwsgi.farms = (struct uwsgi_farm *) uwsgi_calloc_shared(sizeof(struct uwsgi_farm) * uwsgi.farms_cnt); struct uwsgi_string_list *farm_name = uwsgi.farms_list; for (i = 0; i < uwsgi.farms_cnt; i++) { char *farm_value = uwsgi_str(farm_name->value); char *mules_list = strchr(farm_value, ':'); if (!mules_list) { uwsgi_log("invalid farm value (%s) must be in the form name:mule[,muleN].\n", farm_value); exit(1); } mules_list[0] = 0; mules_list++; snprintf(uwsgi.farms[i].name, 0xff, "%s", farm_value); // create the socket pipe create_signal_pipe(uwsgi.farms[i].signal_pipe); create_msg_pipe(uwsgi.farms[i].queue_pipe, uwsgi.mule_msg_size); char *p, *ctx = NULL; uwsgi_foreach_token(mules_list, ",", p, ctx) { struct uwsgi_mule *um = get_mule_by_id(atoi(p)); if (!um) { uwsgi_log("invalid mule id: %s\n", p); exit(1); } uwsgi_mule_farm_new(&uwsgi.farms[i].mules, um); } uwsgi_log("created farm %d name: %s mules:%s\n", i + 1, uwsgi.farms[i].name, strchr(farm_name->value, ':') + 1); farm_name = farm_name->next; free(farm_value); } } } uwsgi-2.0.29/core/notify.c000066400000000000000000000053631477626554400154010ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; void uwsgi_systemd_notify(char *message) { struct msghdr *msghdr = (struct msghdr *) uwsgi.notification_object; struct iovec *iovec = msghdr->msg_iov; iovec[0].iov_base = "STATUS="; iovec[0].iov_len = 7; iovec[1].iov_base = message; iovec[1].iov_len = strlen(message); iovec[2].iov_base = "\n"; iovec[2].iov_len = 1; msghdr->msg_iovlen = 3; if (sendmsg(uwsgi.notification_fd, msghdr, 0) < 0) { uwsgi_error("sendmsg()"); } } void uwsgi_systemd_notify_ready(void) { struct msghdr *msghdr = (struct msghdr *) uwsgi.notification_object; struct iovec *iovec = msghdr->msg_iov; iovec[0].iov_base = "STATUS=uWSGI is ready\nREADY=1\n"; iovec[0].iov_len = 30; msghdr->msg_iovlen = 1; if (sendmsg(uwsgi.notification_fd, msghdr, 0) < 0) { uwsgi_error("sendmsg()"); } } void uwsgi_systemd_init(char *systemd_socket) { struct sockaddr_un *sd_sun; struct msghdr *msghdr; uwsgi.notification_fd = socket(AF_UNIX, SOCK_DGRAM, 0); if (uwsgi.notification_fd < 0) { uwsgi_error("socket()"); return; } size_t len = strlen(systemd_socket); sd_sun = uwsgi_malloc(sizeof(struct sockaddr_un)); memset(sd_sun, 0, sizeof(struct sockaddr_un)); sd_sun->sun_family = AF_UNIX; strncpy(sd_sun->sun_path, systemd_socket, UMIN(len, sizeof(sd_sun->sun_path))); if (sd_sun->sun_path[0] == '@') sd_sun->sun_path[0] = 0; msghdr = uwsgi_malloc(sizeof(struct msghdr)); memset(msghdr, 0, sizeof(struct msghdr)); msghdr->msg_iov = uwsgi_malloc(sizeof(struct iovec) * 3); memset(msghdr->msg_iov, 0, sizeof(struct iovec) * 3); msghdr->msg_name = sd_sun; msghdr->msg_namelen = sizeof(struct sockaddr_un) - (sizeof(sd_sun->sun_path) - len); uwsgi.notification_object = msghdr; uwsgi.notify = uwsgi_systemd_notify; uwsgi.notify_ready = uwsgi_systemd_notify_ready; } int uwsgi_notify_socket_manage(int fd) { char buf[8192]; ssize_t rlen = read(fd, buf, 8192); if (rlen < 0) { if (uwsgi_is_again()) return 0; uwsgi_error("uwsgi_notify_socket_manage()/read()"); exit(1); } if (rlen > 0) { uwsgi_log_verbose("[notify-socket] %.*s\n", rlen, buf); } return 0; } int uwsgi_notify_msg(char *dst, char *msg, size_t len) { static int notify_fd = -1; if (notify_fd < 0) { notify_fd = socket(AF_UNIX, SOCK_DGRAM, 0); if (notify_fd < 0) { uwsgi_error("uwsgi_notify_msg()/socket()"); return -1; } } struct sockaddr_un un_addr; memset(&un_addr, 0, sizeof(struct sockaddr_un)); un_addr.sun_family = AF_UNIX; // use 102 as the magic number strncat(un_addr.sun_path, dst, 102); if (sendto(notify_fd, msg, len, 0, (struct sockaddr *) &un_addr, sizeof(un_addr)) < 0) { return -1; } return 0; } uwsgi-2.0.29/core/offload.c000066400000000000000000000417141477626554400155030ustar00rootroot00000000000000#include "uwsgi.h" /* uWSGI offloading subsystem steps to offload a task 1) allocate a uwsgi_offload_request structure (could be on stack) struct uwsgi_offload_request uor; 2) prepare it for a specific engine (last argument is the takeover flag) uwsgi_offload_setup(my_engine, &uor, 1) 3) run it (last argument is the waiter) int uwsgi_offload_run(wsgi_req, &uor, NULL); between 2 and 3 you can set specific values */ extern struct uwsgi_server uwsgi; #define uwsgi_offload_retry if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) return 0; #define uwsgi_offload_0r_1w(x, y) if (event_queue_del_fd(ut->queue, x, event_queue_read())) return -1;\ if (event_queue_fd_read_to_write(ut->queue, y)) return -1; void uwsgi_offload_setup(struct uwsgi_offload_engine *uoe, struct uwsgi_offload_request *uor, struct wsgi_request *wsgi_req, uint8_t takeover) { memset(uor, 0, sizeof(struct uwsgi_offload_request)); uor->engine = uoe; uor->s = wsgi_req->fd; uor->fd = -1; uor->fd2 = -1; // an engine could changes behaviour based on pipe anf takeover values uor->pipe[0] = -1; uor->pipe[1] = -1; uor->takeover = takeover; } static int uwsgi_offload_enqueue(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) { struct uwsgi_core *uc = &uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id]; uc->offloaded_requests++; // round robin if (uc->offload_rr >= uwsgi.offload_threads) { uc->offload_rr = 0; } struct uwsgi_thread *ut = uwsgi.offload_thread[uc->offload_rr]; uc->offload_rr++; if (write(ut->pipe[0], uor, sizeof(struct uwsgi_offload_request)) != sizeof(struct uwsgi_offload_request)) { if (uor->takeover) { wsgi_req->fd_closed = 0; } return -1; } #ifdef UWSGI_DEBUG uwsgi_log("[offload] created session %p\n", uor); #endif return 0; } /* pipe offload engine: fd -> the file descriptor to read from len -> amount of data to transfer */ static int u_offload_pipe_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) { if (uor->fd < 0 || !uor->len) { return -1; } return 0; } /* memory offload engine: buf -> pointer to the memory to transfer (memory is freed at the end) len -> amount of data to transfer */ static int u_offload_memory_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) { if (!uor->buf || !uor->len) { return -1; } return 0; } /* transfer offload engine: name -> socket name ubuf -> data to send */ static int u_offload_transfer_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) { if (!uor->name) { return -1; } uor->fd = uwsgi_connect(uor->name, 0, 1); if (uor->fd < 0) { uwsgi_error("u_offload_transfer_prepare()/connect()"); return -1; } return 0; } /* sendfile offload engine: name -> filename to transfer fd -> file descriptor of file to transfer fd2 -> sendfile destination (default wsgi_req->fd) len -> size of the file or amount of data to transfer pos -> position in the file */ static int u_offload_sendfile_prepare(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor) { if (!uor->name && uor->fd == -1) return -1; if (uor->name) { uor->fd = open(uor->name, O_RDONLY | O_NONBLOCK); if (uor->fd < 0) { uwsgi_error_open(uor->name); return -1; } } // make a fstat to get the file size if (!uor->len) { struct stat st; if (fstat(uor->fd, &st)) { uwsgi_error("u_offload_sendfile_prepare()/fstat()"); if (uor->name) { close(uor->fd); } return -1; } uor->len = st.st_size; } if (uor->fd2 == -1) { uor->fd2 = uor->s; } uor->s = -1; return 0; } static void uwsgi_offload_close(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor) { // call the free function asap if (uor->free) { uor->free(uor); } // close the socket and the file descriptor if (uor->takeover && uor->s > -1) { close(uor->s); } if (uor->fd != -1) { close(uor->fd); } if (uor->fd2 != -1) { close(uor->fd2); } // remove the structure from the linked list; struct uwsgi_offload_request *prev = uor->prev; struct uwsgi_offload_request *next = uor->next; if (uor == ut->offload_requests_head) { ut->offload_requests_head = next; } if (uor == ut->offload_requests_tail) { ut->offload_requests_tail = prev; } if (prev) { prev->next = next; } if (next) { next->prev = prev; } if (uor->buf) { free(uor->buf); } if (uor->ubuf) { uwsgi_buffer_destroy(uor->ubuf); } if (uor->ubuf1) { uwsgi_buffer_destroy(uor->ubuf1); } if (uor->ubuf2) { uwsgi_buffer_destroy(uor->ubuf2); } if (uor->ubuf3) { uwsgi_buffer_destroy(uor->ubuf3); } if (uor->ubuf4) { uwsgi_buffer_destroy(uor->ubuf4); } if (uor->ubuf5) { uwsgi_buffer_destroy(uor->ubuf5); } if (uor->ubuf6) { uwsgi_buffer_destroy(uor->ubuf6); } if (uor->ubuf7) { uwsgi_buffer_destroy(uor->ubuf7); } if (uor->ubuf8) { uwsgi_buffer_destroy(uor->ubuf8); } if (uor->pipe[0] != -1) { close(uor->pipe[1]); close(uor->pipe[0]); } #ifdef UWSGI_DEBUG uwsgi_log("[offload] destroyed session %p\n", uor); #endif free(uor); } static void uwsgi_offload_append(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor) { if (!ut->offload_requests_head) { ut->offload_requests_head = uor; } if (ut->offload_requests_tail) { ut->offload_requests_tail->next = uor; uor->prev = ut->offload_requests_tail; } ut->offload_requests_tail = uor; } static struct uwsgi_offload_request *uwsgi_offload_get_by_fd(struct uwsgi_thread *ut, int s) { struct uwsgi_offload_request *uor = ut->offload_requests_head; while (uor) { if (uor->s == s || uor->fd == s || uor->fd2 == s) { return uor; } uor = uor->next; } return NULL; } static void uwsgi_offload_loop(struct uwsgi_thread *ut) { int i; void *events = event_queue_alloc(uwsgi.offload_threads_events); for (;;) { // TODO make timeout tunable int nevents = event_queue_wait_multi(ut->queue, -1, events, uwsgi.offload_threads_events); for (i = 0; i < nevents; i++) { int interesting_fd = event_queue_interesting_fd(events, i); if (interesting_fd == ut->pipe[1]) { struct uwsgi_offload_request *uor = uwsgi_malloc(sizeof(struct uwsgi_offload_request)); ssize_t len = read(ut->pipe[1], uor, sizeof(struct uwsgi_offload_request)); if (len != sizeof(struct uwsgi_offload_request)) { uwsgi_error("read()"); free(uor); continue; } // cal the event function for the first time if (uor->engine->event_func(ut, uor, -1)) { uwsgi_offload_close(ut, uor); continue; } uwsgi_offload_append(ut, uor); continue; } // get the task from the interesting fd struct uwsgi_offload_request *uor = uwsgi_offload_get_by_fd(ut, interesting_fd); if (!uor) continue; // run the hook if (uor->engine->event_func(ut, uor, interesting_fd)) { uwsgi_offload_close(ut, uor); } } } } struct uwsgi_thread *uwsgi_offload_thread_start() { return uwsgi_thread_new(uwsgi_offload_loop); } /* offload memory transfer uor->len -> the size of the memory chunk uor->buf -> the memory to transfer uor->written -> written bytes status: none */ static int u_offload_memory_do(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) { if (fd == -1) { if (event_queue_add_fd_write(ut->queue, uor->s)) return -1; return 0; } ssize_t rlen = write(uor->s, uor->buf + uor->written, uor->len - uor->written); if (rlen > 0) { uor->written += rlen; if (uor->written >= uor->len) { return -1; } return 0; } else if (rlen < 0) { uwsgi_offload_retry uwsgi_error("u_offload_memory_do()"); } return -1; } /* the offload task starts after having acquired the file fd uor->len -> the size of the file uor->pos -> start writing from pos (default 0) status: none */ static int u_offload_sendfile_do(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) { if (fd == -1) { if (event_queue_add_fd_write(ut->queue, uor->fd2)) return -1; return 0; } #if defined(__linux__) || defined(__sun__) || defined(__GNU_kFreeBSD__) ssize_t len = sendfile(uor->fd2, uor->fd, &uor->pos, 128 * 1024); if (len > 0) { uor->written += len; if (uor->written >= uor->len) { return -1; } return 0; } else if (len < 0) { uwsgi_offload_retry uwsgi_error("u_offload_sendfile_do()"); } #elif defined(__FreeBSD__) || defined(__DragonFly__) off_t sbytes = 0; int ret = sendfile(uor->fd, uor->fd2, uor->pos, 0, NULL, &sbytes, 0); // transfer finished if (ret == -1) { uor->pos += sbytes; uwsgi_offload_retry uwsgi_error("u_offload_sendfile_do()"); } #elif defined(__APPLE__) && !defined(NO_SENDFILE) off_t len = 0; int ret = sendfile(uor->fd, uor->fd2, uor->pos, &len, NULL, 0); // transfer finished if (ret == -1) { uor->pos += len; uwsgi_offload_retry uwsgi_error("u_offload_sendfile_do()"); } #endif return -1; } /* pipe offloading status: 0 -> waiting for data on fd 1 -> waiting for write to s */ static int u_offload_pipe_do(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) { ssize_t rlen; // setup if (fd == -1) { event_queue_add_fd_read(ut->queue, uor->fd); return 0; } switch(uor->status) { // read event from fd case 0: if (!uor->buf) { uor->buf = uwsgi_malloc(4096); } rlen = read(uor->fd, uor->buf, 4096); if (rlen > 0) { uor->to_write = rlen; uor->pos = 0; if (event_queue_del_fd(ut->queue, uor->fd, event_queue_read())) return -1; if (event_queue_add_fd_write(ut->queue, uor->s)) return -1; uor->status = 1; return 0; } if (rlen < 0) { uwsgi_offload_retry uwsgi_error("u_offload_pipe_do() -> read()"); } return -1; // write event on s case 1: rlen = write(uor->s, uor->buf + uor->pos, uor->to_write); if (rlen > 0) { uor->to_write -= rlen; uor->pos += rlen; if (uor->to_write == 0) { if (event_queue_del_fd(ut->queue, uor->s, event_queue_write())) return -1; if (event_queue_add_fd_read(ut->queue, uor->fd)) return -1; uor->status = 0; } return 0; } else if (rlen < 0) { uwsgi_offload_retry uwsgi_error("u_offload_pipe_do() -> write()"); } return -1; default: break; } return -1; } /* the offload task starts soon after the call to connect() status: 0 -> waiting for connection on fd 1 -> sending request to fd (write event) 2 -> start waiting for read on s and fd 3 -> write to s 4 -> write to fd */ static int u_offload_transfer_do(struct uwsgi_thread *ut, struct uwsgi_offload_request *uor, int fd) { ssize_t rlen; // setup if (fd == -1) { event_queue_add_fd_write(ut->queue, uor->fd); return 0; } switch(uor->status) { // waiting for connection case 0: if (fd == uor->fd) { uor->status = 1; // ok try to send the request right now... return u_offload_transfer_do(ut, uor, fd); } return -1; // write event (or just connected) case 1: if (fd == uor->fd) { // maybe we want only a connection... if (uor->ubuf->pos == 0) { uor->status = 2; if (event_queue_add_fd_read(ut->queue, uor->s)) return -1; if (event_queue_fd_write_to_read(ut->queue, uor->fd)) return -1; return 0; } rlen = write(uor->fd, uor->ubuf->buf + uor->written, uor->ubuf->pos-uor->written); if (rlen > 0) { uor->written += rlen; if (uor->written >= (size_t)uor->ubuf->pos) { uor->status = 2; if (event_queue_add_fd_read(ut->queue, uor->s)) return -1; if (event_queue_fd_write_to_read(ut->queue, uor->fd)) return -1; } return 0; } else if (rlen < 0) { uwsgi_offload_retry uwsgi_error("u_offload_transfer_do() -> write()"); } } return -1; // read event from s or fd case 2: if (!uor->buf) { uor->buf = uwsgi_malloc(4096); } if (fd == uor->fd) { rlen = read(uor->fd, uor->buf, 4096); if (rlen > 0) { uor->to_write = rlen; uor->pos = 0; uwsgi_offload_0r_1w(uor->fd, uor->s) uor->status = 3; return 0; } if (rlen < 0) { uwsgi_offload_retry uwsgi_error("u_offload_transfer_do() -> read()/fd"); } } else if (fd == uor->s) { rlen = read(uor->s, uor->buf, 4096); if (rlen > 0) { uor->to_write = rlen; uor->pos = 0; uwsgi_offload_0r_1w(uor->s, uor->fd) uor->status = 4; return 0; } if (rlen < 0) { uwsgi_offload_retry uwsgi_error("u_offload_transfer_do() -> read()/s"); } } return -1; // write event on s case 3: rlen = write(uor->s, uor->buf + uor->pos, uor->to_write); if (rlen > 0) { uor->to_write -= rlen; uor->pos += rlen; if (uor->to_write == 0) { if (event_queue_fd_write_to_read(ut->queue, uor->s)) return -1; if (event_queue_add_fd_read(ut->queue, uor->fd)) return -1; uor->status = 2; } return 0; } else if (rlen < 0) { uwsgi_offload_retry uwsgi_error("u_offload_transfer_do() -> write()/s"); } return -1; // write event on fd case 4: rlen = write(uor->fd, uor->buf + uor->pos, uor->to_write); if (rlen > 0) { uor->to_write -= rlen; uor->pos += rlen; if (uor->to_write == 0) { if (event_queue_fd_write_to_read(ut->queue, uor->fd)) return -1; if (event_queue_add_fd_read(ut->queue, uor->s)) return -1; uor->status = 2; } return 0; } else if (rlen < 0) { uwsgi_offload_retry uwsgi_error("u_offload_transfer_do() -> write()/fd"); } return -1; default: break; } return -1; } int uwsgi_offload_run(struct wsgi_request *wsgi_req, struct uwsgi_offload_request *uor, int *wait) { if (uor->engine->prepare_func(wsgi_req, uor)) { return -1; } if (wait) { if (pipe(uor->pipe)) { uwsgi_error("uwsgi_offload_setup()/pipe()"); return -1; } *wait = uor->pipe[0]; uwsgi_socket_nb(uor->pipe[0]); uwsgi_socket_nb(uor->pipe[1]); } if (uor->takeover) { wsgi_req->fd_closed = 1; } if (uwsgi_offload_enqueue(wsgi_req, uor)) { close(uor->pipe[0]); close(uor->pipe[1]); if (uor->takeover) { wsgi_req->fd_closed = 0; } return -1; } return 0; }; struct uwsgi_offload_engine *uwsgi_offload_engine_by_name(char *name) { struct uwsgi_offload_engine *uoe = uwsgi.offload_engines; while(uoe) { if (!strcmp(name, uoe->name)) { return uoe; } } return NULL; } struct uwsgi_offload_engine *uwsgi_offload_register_engine(char *name, int (*prepare_func)(struct wsgi_request *, struct uwsgi_offload_request *), int (*event_func) (struct uwsgi_thread *, struct uwsgi_offload_request *, int)) { struct uwsgi_offload_engine *old_engine=NULL,*engine=uwsgi.offload_engines; while(engine) { if (!strcmp(engine->name, name)) { return engine; } old_engine = engine; engine = engine->next; } engine = uwsgi_calloc(sizeof(struct uwsgi_offload_engine)); engine->name = name; engine->prepare_func = prepare_func; engine->event_func = event_func; if (old_engine) { old_engine->next = engine; } else { uwsgi.offload_engines = engine; } return engine; } void uwsgi_offload_engines_register_all() { uwsgi.offload_engine_sendfile = uwsgi_offload_register_engine("sendfile", u_offload_sendfile_prepare, u_offload_sendfile_do); uwsgi.offload_engine_transfer = uwsgi_offload_register_engine("transfer", u_offload_transfer_prepare, u_offload_transfer_do); uwsgi.offload_engine_memory = uwsgi_offload_register_engine("memory", u_offload_memory_prepare, u_offload_memory_do); uwsgi.offload_engine_pipe = uwsgi_offload_register_engine("pipe", u_offload_pipe_prepare, u_offload_pipe_do); } int uwsgi_offload_request_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) { struct uwsgi_offload_request uor; uwsgi_offload_setup(uwsgi.offload_engine_sendfile, &uor, wsgi_req, 1); uor.fd = fd; uor.len = len; uor.pos = pos; return uwsgi_offload_run(wsgi_req, &uor, NULL); } int uwsgi_offload_request_net_do(struct wsgi_request *wsgi_req, char *socketname, struct uwsgi_buffer *ubuf) { struct uwsgi_offload_request uor; uwsgi_offload_setup(uwsgi.offload_engine_transfer, &uor, wsgi_req, 1); uor.name = socketname; uor.ubuf = ubuf; return uwsgi_offload_run(wsgi_req, &uor, NULL); } int uwsgi_offload_request_memory_do(struct wsgi_request *wsgi_req, char *buf, size_t len) { struct uwsgi_offload_request uor; uwsgi_offload_setup(uwsgi.offload_engine_memory, &uor, wsgi_req, 1); uor.buf = buf; uor.len = len; return uwsgi_offload_run(wsgi_req, &uor, NULL); } int uwsgi_offload_request_pipe_do(struct wsgi_request *wsgi_req, int fd, size_t len) { struct uwsgi_offload_request uor; uwsgi_offload_setup(uwsgi.offload_engine_pipe, &uor, wsgi_req, 1); uor.fd = fd; uor.len = len; return uwsgi_offload_run(wsgi_req, &uor, NULL); } uwsgi-2.0.29/core/plugins.c000066400000000000000000000170101477626554400155420ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; #ifdef UWSGI_ELF static void uwsgi_plugin_parse_section(char *filename) { size_t s_len = 0; char *buf = uwsgi_elf_section(filename, "uwsgi", &s_len); if (buf) { char *ctx = NULL; char *p = strtok_r(buf, "\n", &ctx); while (p) { char *equal = strchr(p, '='); if (equal) { *equal = 0; if (!strcmp(p, "requires")) { if (!plugin_already_loaded(equal+1)) { uwsgi_load_plugin(-1, equal + 1, NULL); } } } p = strtok_r(NULL, "\n", &ctx); } free(buf); } } #endif struct uwsgi_plugin *uwsgi_plugin_get(const char *plugin) { int i; for (i = 0; i < 256; i++) { if (uwsgi.p[i]->name) { if (!strcmp(plugin, uwsgi.p[i]->name)) { #ifdef UWSGI_DEBUG uwsgi_log("%s plugin already available\n", plugin); #endif return uwsgi.p[i]; } } if (uwsgi.p[i]->alias) { if (!strcmp(plugin, uwsgi.p[i]->alias)) { #ifdef UWSGI_DEBUG uwsgi_log("%s plugin already available\n", plugin); #endif return uwsgi.p[i]; } } } for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->name) { if (!strcmp(plugin, uwsgi.gp[i]->name)) { #ifdef UWSGI_DEBUG uwsgi_log("%s plugin already available\n", plugin); #endif return uwsgi.p[i]; } } if (uwsgi.gp[i]->alias) { if (!strcmp(plugin, uwsgi.gp[i]->alias)) { #ifdef UWSGI_DEBUG uwsgi_log("%s plugin already available\n", plugin); #endif return uwsgi.p[i]; } } } return NULL; } int plugin_already_loaded(const char *plugin) { struct uwsgi_plugin *up = uwsgi_plugin_get(plugin); if (up) return 1; return 0; } void *uwsgi_load_plugin(int modifier, char *plugin, char *has_option) { void *plugin_handle = NULL; char *plugin_abs_path = NULL; char *plugin_filename = NULL; int need_free = 0; char *plugin_name = uwsgi_strip(uwsgi_str(plugin)); char *plugin_symbol_name_start; struct uwsgi_plugin *up; char linkpath_buf[1024], linkpath[1024]; int linkpath_size; char *colon = strchr(plugin_name, ':'); if (colon) { colon[0] = 0; modifier = atoi(plugin_name); plugin_name = colon + 1; colon[0] = ':'; } char *init_func = strchr(plugin_name, '|'); if (init_func) { init_func[0] = 0; init_func++; } if (!uwsgi_endswith(plugin_name, "_plugin.so")) { plugin_name = uwsgi_concat2(plugin_name, "_plugin.so"); need_free = 1; } plugin_symbol_name_start = plugin_name; // step 1: check for absolute plugin (stop if it fails) if (strchr(plugin_name, '/')) { #ifdef UWSGI_ELF uwsgi_plugin_parse_section(plugin_name); #endif plugin_handle = dlopen(plugin_name, RTLD_NOW | RTLD_GLOBAL); if (!plugin_handle) { if (!has_option) uwsgi_log("%s\n", dlerror()); goto end; } plugin_symbol_name_start = uwsgi_get_last_char(plugin_name, '/'); plugin_symbol_name_start++; plugin_abs_path = plugin_name; goto success; } // step dir, check for user-supplied plugins directory struct uwsgi_string_list *pdir = uwsgi.plugins_dir; while (pdir) { plugin_filename = uwsgi_concat3(pdir->value, "/", plugin_name); #ifdef UWSGI_ELF uwsgi_plugin_parse_section(plugin_filename); #endif plugin_handle = dlopen(plugin_filename, RTLD_NOW | RTLD_GLOBAL); if (plugin_handle) { plugin_abs_path = plugin_filename; //free(plugin_filename); goto success; } free(plugin_filename); plugin_filename = NULL; pdir = pdir->next; } // last step: search in compile-time plugin_dir if (!plugin_handle) { plugin_filename = uwsgi_concat3(UWSGI_PLUGIN_DIR, "/", plugin_name); #ifdef UWSGI_ELF uwsgi_plugin_parse_section(plugin_filename); #endif plugin_handle = dlopen(plugin_filename, RTLD_NOW | RTLD_GLOBAL); plugin_abs_path = plugin_filename; //free(plugin_filename); } success: if (!plugin_handle) { if (!has_option) uwsgi_log("!!! UNABLE to load uWSGI plugin: %s !!!\n", dlerror()); } else { if (init_func) { void (*plugin_init_func)() = dlsym(plugin_handle, init_func); if (plugin_init_func) { plugin_init_func(); } } char *plugin_entry_symbol = uwsgi_concat2n(plugin_symbol_name_start, strlen(plugin_symbol_name_start) - 3, "", 0); up = dlsym(plugin_handle, plugin_entry_symbol); if (!up) { // is it a link ? memset(linkpath_buf, 0, 1024); memset(linkpath, 0, 1024); if ((linkpath_size = readlink(plugin_abs_path, linkpath_buf, 1023)) > 0) { do { linkpath_buf[linkpath_size] = '\0'; strncpy(linkpath, linkpath_buf, linkpath_size + 1); } while ((linkpath_size = readlink(linkpath, linkpath_buf, 1023)) > 0); #ifdef UWSGI_DEBUG uwsgi_log("%s\n", linkpath); #endif free(plugin_entry_symbol); char *slash = uwsgi_get_last_char(linkpath, '/'); if (!slash) { slash = linkpath; } else { slash++; } plugin_entry_symbol = uwsgi_concat2n(slash, strlen(slash) - 3, "", 0); up = dlsym(plugin_handle, plugin_entry_symbol); } } if (up) { if (!up->name) { uwsgi_log("the loaded plugin (%s) has no .name attribute\n", plugin_name); if (dlclose(plugin_handle)) { uwsgi_error("dlclose()"); } if (need_free) free(plugin_name); if (plugin_filename) free(plugin_filename); free(plugin_entry_symbol); return NULL; } if (plugin_already_loaded(up->name)) { if (dlclose(plugin_handle)) { uwsgi_error("dlclose()"); } if (need_free) free(plugin_name); if (plugin_filename) free(plugin_filename); free(plugin_entry_symbol); return NULL; } if (has_option) { struct uwsgi_option *op = up->options; int found = 0; while (op && op->name) { if (!strcmp(has_option, op->name)) { found = 1; break; } op++; } if (!found) { if (dlclose(plugin_handle)) { uwsgi_error("dlclose()"); } if (need_free) free(plugin_name); if (plugin_filename) free(plugin_filename); free(plugin_entry_symbol); return NULL; } } if (modifier != -1) { fill_plugin_table(modifier, up); up->modifier1 = modifier; } else { fill_plugin_table(up->modifier1, up); } if (need_free) free(plugin_name); if (plugin_filename) free(plugin_filename); free(plugin_entry_symbol); if (up->on_load) up->on_load(); return plugin_handle; } if (!has_option) uwsgi_log("%s\n", dlerror()); } end: if (need_free) free(plugin_name); if (plugin_filename) free(plugin_filename); return NULL; } int uwsgi_try_autoload(char *option) { DIR *d; struct dirent *dp; // step dir, check for user-supplied plugins directory struct uwsgi_string_list *pdir = uwsgi.plugins_dir; while (pdir) { d = opendir(pdir->value); if (d) { while ((dp = readdir(d)) != NULL) { if (uwsgi_endswith(dp->d_name, "_plugin.so")) { char *filename = uwsgi_concat3(pdir->value, "/", dp->d_name); if (uwsgi_load_plugin(-1, filename, option)) { uwsgi_log("option \"%s\" found in plugin %s\n", option, filename); free(filename); closedir(d); // add new options build_options(); return 1; } free(filename); } } closedir(d); } pdir = pdir->next; } // last step: search in compile-time plugin_dir d = opendir(UWSGI_PLUGIN_DIR); if (!d) return 0; while ((dp = readdir(d)) != NULL) { if (uwsgi_endswith(dp->d_name, "_plugin.so")) { char *filename = uwsgi_concat3(UWSGI_PLUGIN_DIR, "/", dp->d_name); if (uwsgi_load_plugin(-1, filename, option)) { uwsgi_log("option \"%s\" found in plugin %s\n", option, filename); free(filename); closedir(d); // add new options build_options(); return 1; } free(filename); } } closedir(d); return 0; } uwsgi-2.0.29/core/plugins_builder.c000066400000000000000000000051461477626554400172570ustar00rootroot00000000000000#include "uwsgi.h" #define UWSGI_BUILD_DIR ".uwsgi_plugins_builder" /* steps: mkdir(.uwsgi_plugin_builder) generate .uwsgi_plugin_builder/uwsgi.h generate .uwsgi_plugin_builder/uwsgiconfig.py setenv(UWSGI_PLUGINS_BUILDER_CFLAGS=uwsgi_cflags) exec PYTHON .uwsgi_plugin_builder/uwsgiconfig.py --extra-plugin [name] */ void uwsgi_build_plugin(char *directory) { if (!uwsgi_file_exists(UWSGI_BUILD_DIR)) { if (mkdir(UWSGI_BUILD_DIR, S_IRWXU) < 0) { uwsgi_error("uwsgi_build_plugin()/mkdir() " UWSGI_BUILD_DIR "/"); _exit(1); } } char *dot_h = uwsgi_get_dot_h(); if (!dot_h) { uwsgi_log("unable to generate uwsgi.h"); _exit(1); } if (strlen(dot_h) == 0) { free(dot_h); uwsgi_log("invalid uwsgi.h"); _exit(1); } int dot_h_fd = open(UWSGI_BUILD_DIR "/uwsgi.h", O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR); if (dot_h_fd < 0) { uwsgi_error_open(UWSGI_BUILD_DIR "/uwsgi.h"); free(dot_h); _exit(1); } ssize_t dot_h_len = (ssize_t) strlen(dot_h); if (write(dot_h_fd, dot_h, dot_h_len) != dot_h_len) { uwsgi_error("uwsgi_build_plugin()/write()"); _exit(1); } char *config_py = uwsgi_get_config_py(); if (!config_py) { uwsgi_log("unable to generate uwsgiconfig.py"); _exit(1); } if (strlen(config_py) == 0) { uwsgi_log("invalid uwsgiconfig.py"); _exit(1); } int config_py_fd = open(UWSGI_BUILD_DIR "/uwsgiconfig.py", O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR); if (config_py_fd < 0) { uwsgi_error_open(UWSGI_BUILD_DIR "/uwsgiconfig.py"); _exit(1); } ssize_t config_py_len = (ssize_t) strlen(config_py); if (write(config_py_fd, config_py, config_py_len) != config_py_len) { uwsgi_error("uwsgi_build_plugin()/write()"); _exit(1); } char *cflags = uwsgi_get_cflags(); if (!cflags) { uwsgi_log("unable to find cflags\n"); _exit(1); } if (strlen(cflags) == 0) { uwsgi_log("invalid cflags\n"); _exit(1); } if (setenv("UWSGI_PLUGINS_BUILDER_CFLAGS", cflags, 1)) { uwsgi_error("uwsgi_build_plugin()/setenv()"); _exit(1); } // now run the python script char *argv[6]; argv[0] = getenv("PYTHON"); if (!argv[0]) argv[0] = "python"; argv[1] = UWSGI_BUILD_DIR "/uwsgiconfig.py"; argv[2] = "--extra-plugin"; char *space = strchr(directory, ' '); if (space) { *space = 0; argv[3] = directory; argv[4] = space+1; argv[5] = NULL; } else { argv[3] = directory; argv[4] = NULL; } execvp(argv[0], argv); // never here... _exit(1); } uwsgi-2.0.29/core/progress.c000066400000000000000000000053751477626554400157400ustar00rootroot00000000000000#include "uwsgi.h" /* upload progress facilities */ extern struct uwsgi_server uwsgi; char *uwsgi_upload_progress_create(struct wsgi_request *wsgi_req, int *fd) { const char *x_progress_id = "X-Progress-ID="; char *xpi_ptr = (char *) x_progress_id; uint16_t i; char *upload_progress_filename = NULL; if (wsgi_req->uri_len <= 51) return NULL; for (i = 0; i < wsgi_req->uri_len; i++) { if (wsgi_req->uri[i] == xpi_ptr[0]) { if (xpi_ptr[0] == '=') { if (wsgi_req->uri + i + 36 <= wsgi_req->uri + wsgi_req->uri_len) { upload_progress_filename = wsgi_req->uri + i + 1; } break; } xpi_ptr++; } else { xpi_ptr = (char *) x_progress_id; } } // now check for valid uuid (from spec available at http://en.wikipedia.org/wiki/Universally_unique_identifier) if (!upload_progress_filename) return NULL; uwsgi_log("upload progress uuid = %.*s\n", 36, upload_progress_filename); if (!check_hex(upload_progress_filename, 8)) return NULL; if (upload_progress_filename[8] != '-') return NULL; if (!check_hex(upload_progress_filename + 9, 4)) return NULL; if (upload_progress_filename[13] != '-') return NULL; if (!check_hex(upload_progress_filename + 14, 4)) return NULL; if (upload_progress_filename[18] != '-') return NULL; if (!check_hex(upload_progress_filename + 19, 4)) return NULL; if (upload_progress_filename[23] != '-') return NULL; if (!check_hex(upload_progress_filename + 24, 12)) return NULL; upload_progress_filename = uwsgi_concat4n(uwsgi.upload_progress, strlen(uwsgi.upload_progress), "/", 1, upload_progress_filename, 36, ".js", 3); // here we use O_EXCL to avoid eventual application bug in uuid generation/using *fd = open(upload_progress_filename, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP); if (*fd < 0) { uwsgi_error_open(upload_progress_filename); free(upload_progress_filename); return NULL; } return upload_progress_filename; } int uwsgi_upload_progress_update(struct wsgi_request *wsgi_req, int fd, size_t remains) { char buf[4096]; int ret = snprintf(buf, 4096, "{ \"state\" : \"uploading\", \"received\" : %llu, \"size\" : %llu }\r\n", (unsigned long long) (wsgi_req->post_cl - remains), (unsigned long long) wsgi_req->post_cl); if (ret <= 0 || ret >= 4096) { return -1; } if (lseek(fd, 0, SEEK_SET)) { uwsgi_error("uwsgi_upload_progress_update()/lseek()"); return -1; } if (write(fd, buf, ret) != ret) { uwsgi_error("uwsgi_upload_progress_update()/write()"); return -1; } if (fsync(fd)) { uwsgi_error("uwsgi_upload_progress_update()/fsync()"); return -1; } return 0; } void uwsgi_upload_progress_destroy(char *filename, int fd) { close(fd); if (unlink(filename)) { uwsgi_error("uwsgi_upload_progress_destroy()/unlink()"); } free(filename); } uwsgi-2.0.29/core/protocol.c000066400000000000000000000754661477626554400157450ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; // this is like uwsgi_str_num but with security checks static size_t get_content_length(char *buf, uint16_t size) { int i; size_t val = 0; for (i = 0; i < size; i++) { if (buf[i] >= '0' && buf[i] <= '9') { val = (val * 10) + (buf[i] - '0'); continue; } break; } return val; } int uwsgi_read_response(int fd, struct uwsgi_header *uh, int timeout, char **buf) { char *ptr = (char *) uh; size_t remains = 4; int ret = -1; int rlen; ssize_t len; while (remains > 0) { rlen = uwsgi_waitfd(fd, timeout); if (rlen > 0) { len = read(fd, ptr, remains); if (len <= 0) break; remains -= len; ptr += len; if (remains == 0) { ret = uh->modifier2; break; } continue; } // timed out ? else if (ret == 0) ret = -2; break; } if (buf && uh->pktsize > 0) { if (*buf == NULL) *buf = uwsgi_malloc(uh->pktsize); remains = uh->pktsize; ptr = *buf; ret = -1; while (remains > 0) { rlen = uwsgi_waitfd(fd, timeout); if (rlen > 0) { len = read(fd, ptr, remains); if (len <= 0) break; remains -= len; ptr += len; if (remains == 0) { ret = uh->modifier2; break; } continue; } // timed out ? else if (ret == 0) ret = -2; break; } } return ret; } int uwsgi_parse_array(char *buffer, uint16_t size, char **argv, uint16_t argvs[], uint8_t * argc) { char *ptrbuf, *bufferend; uint16_t strsize = 0; uint8_t max = *argc; *argc = 0; ptrbuf = buffer; bufferend = ptrbuf + size; while (ptrbuf < bufferend && *argc < max) { if (ptrbuf + 2 < bufferend) { memcpy(&strsize, ptrbuf, 2); #ifdef __BIG_ENDIAN__ strsize = uwsgi_swap16(strsize); #endif ptrbuf += 2; /* item cannot be null */ if (!strsize) continue; if (ptrbuf + strsize <= bufferend) { // item argv[*argc] = uwsgi_cheap_string(ptrbuf, strsize); argvs[*argc] = strsize; #ifdef UWSGI_DEBUG uwsgi_log("arg %s\n", argv[*argc]); #endif ptrbuf += strsize; *argc = *argc + 1; } else { uwsgi_log("invalid uwsgi array. skip this var.\n"); return -1; } } else { uwsgi_log("invalid uwsgi array. skip this request.\n"); return -1; } } return 0; } int uwsgi_simple_parse_vars(struct wsgi_request *wsgi_req, char *ptrbuf, char *bufferend) { uint16_t strsize; while (ptrbuf < bufferend) { if (ptrbuf + 2 < bufferend) { memcpy(&strsize, ptrbuf, 2); #ifdef __BIG_ENDIAN__ strsize = uwsgi_swap16(strsize); #endif /* key cannot be null */ if (!strsize) { uwsgi_log("uwsgi key cannot be null. skip this request.\n"); return -1; } ptrbuf += 2; if (ptrbuf + strsize < bufferend) { // var key wsgi_req->hvec[wsgi_req->var_cnt].iov_base = ptrbuf; wsgi_req->hvec[wsgi_req->var_cnt].iov_len = strsize; ptrbuf += strsize; // value can be null (even at the end) so use <= if (ptrbuf + 2 <= bufferend) { memcpy(&strsize, ptrbuf, 2); #ifdef __BIG_ENDIAN__ strsize = uwsgi_swap16(strsize); #endif ptrbuf += 2; if (ptrbuf + strsize <= bufferend) { if (wsgi_req->var_cnt < uwsgi.vec_size - (4 + 1)) { wsgi_req->var_cnt++; } else { uwsgi_log("max vec size reached. skip this header.\n"); return -1; } // var value wsgi_req->hvec[wsgi_req->var_cnt].iov_base = ptrbuf; wsgi_req->hvec[wsgi_req->var_cnt].iov_len = strsize; if (wsgi_req->var_cnt < uwsgi.vec_size - (4 + 1)) { wsgi_req->var_cnt++; } else { uwsgi_log("max vec size reached. skip this var.\n"); return -1; } ptrbuf += strsize; } else { uwsgi_log("invalid uwsgi request (current strsize: %d). skip.\n", strsize); return -1; } } else { uwsgi_log("invalid uwsgi request (current strsize: %d). skip.\n", strsize); return -1; } } } } return 0; } #define uwsgi_proto_key(x, y) memcmp(x, key, y) static int uwsgi_proto_check_5(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) { if (!uwsgi_proto_key("HTTPS", 5)) { wsgi_req->https = buf; wsgi_req->https_len = len; return 0; } return 0; } static int uwsgi_proto_check_9(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) { if (!uwsgi_proto_key("PATH_INFO", 9)) { wsgi_req->path_info = buf; wsgi_req->path_info_len = len; wsgi_req->path_info_pos = wsgi_req->var_cnt + 1; #ifdef UWSGI_DEBUG uwsgi_debug("PATH_INFO=%.*s\n", wsgi_req->path_info_len, wsgi_req->path_info); #endif return 0; } if (!uwsgi_proto_key("HTTP_HOST", 9)) { wsgi_req->host = buf; wsgi_req->host_len = len; #ifdef UWSGI_DEBUG uwsgi_debug("HTTP_HOST=%.*s\n", wsgi_req->host_len, wsgi_req->host); #endif return 0; } return 0; } static void uwsgi_parse_http_range(char *buf, uint16_t len, enum uwsgi_range *parsed, int64_t *from, int64_t *to) { *parsed = UWSGI_RANGE_INVALID; *from = 0; *to = 0; uint16_t rlen = 0; uint16_t i; for(i=0;i= *from) { *parsed = UWSGI_RANGE_PARSED; } else { *from = 0; *to = 0; } } else { /* RFC7233 suffix-byte-range-spec: `bytes=-500` */ *from = -(int64_t)uwsgi_str_num(dash+1, rlen - ((dash+1)-range)); if (*from < 0) { *to = INT64_MAX; *parsed = UWSGI_RANGE_PARSED; } } } static int uwsgi_proto_check_10(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) { if (uwsgi.honour_range && !uwsgi_proto_key("HTTP_IF_RANGE", 13)) { wsgi_req->if_range = buf; wsgi_req->if_range_len = len; } if (uwsgi.honour_range && !uwsgi_proto_key("HTTP_RANGE", 10)) { uwsgi_parse_http_range(buf, len, &wsgi_req->range_parsed, &wsgi_req->range_from, &wsgi_req->range_to); // set deprecated fields for binary compatibility wsgi_req->__range_from = (size_t)wsgi_req->range_from; wsgi_req->__range_to = (size_t)wsgi_req->range_to; return 0; } if (!uwsgi_proto_key("UWSGI_FILE", 10)) { wsgi_req->file = buf; wsgi_req->file_len = len; wsgi_req->dynamic = 1; return 0; } if (!uwsgi_proto_key("UWSGI_HOME", 10)) { wsgi_req->home = buf; wsgi_req->home_len = len; return 0; } return 0; } static int uwsgi_proto_check_11(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) { if (!uwsgi_proto_key("SCRIPT_NAME", 11)) { wsgi_req->script_name = buf; wsgi_req->script_name_len = len; wsgi_req->script_name_pos = wsgi_req->var_cnt + 1; #ifdef UWSGI_DEBUG uwsgi_debug("SCRIPT_NAME=%.*s\n", wsgi_req->script_name_len, wsgi_req->script_name); #endif return 0; } if (!uwsgi_proto_key("REQUEST_URI", 11)) { wsgi_req->uri = buf; wsgi_req->uri_len = len; return 0; } if (!uwsgi_proto_key("REMOTE_USER", 11)) { wsgi_req->remote_user = buf; wsgi_req->remote_user_len = len; return 0; } if (wsgi_req->host_len == 0 && !uwsgi_proto_key("SERVER_NAME", 11)) { wsgi_req->host = buf; wsgi_req->host_len = len; #ifdef UWSGI_DEBUG uwsgi_debug("SERVER_NAME=%.*s\n", wsgi_req->host_len, wsgi_req->host); #endif return 0; } if (wsgi_req->remote_addr_len == 0 && !uwsgi_proto_key("REMOTE_ADDR", 11)) { wsgi_req->remote_addr = buf; wsgi_req->remote_addr_len = len; return 0; } if (!uwsgi_proto_key("HTTP_COOKIE", 11)) { wsgi_req->cookie = buf; wsgi_req->cookie_len = len; return 0; } if (!uwsgi_proto_key("UWSGI_APPID", 11)) { wsgi_req->appid = buf; wsgi_req->appid_len = len; return 0; } if (!uwsgi_proto_key("UWSGI_CHDIR", 11)) { wsgi_req->chdir = buf; wsgi_req->chdir_len = len; return 0; } if (!uwsgi_proto_key("HTTP_ORIGIN", 11)) { wsgi_req->http_origin = buf; wsgi_req->http_origin_len = len; return 0; } return 0; } static int uwsgi_proto_check_12(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) { if (!uwsgi_proto_key("QUERY_STRING", 12)) { wsgi_req->query_string = buf; wsgi_req->query_string_len = len; return 0; } if (!uwsgi_proto_key("CONTENT_TYPE", 12)) { wsgi_req->content_type = buf; wsgi_req->content_type_len = len; return 0; } if (!uwsgi_proto_key("HTTP_REFERER", 12)) { wsgi_req->referer = buf; wsgi_req->referer_len = len; return 0; } if (!uwsgi_proto_key("UWSGI_SCHEME", 12)) { wsgi_req->scheme = buf; wsgi_req->scheme_len = len; return 0; } if (!uwsgi_proto_key("UWSGI_SCRIPT", 12)) { wsgi_req->script = buf; wsgi_req->script_len = len; wsgi_req->dynamic = 1; return 0; } if (!uwsgi_proto_key("UWSGI_MODULE", 12)) { wsgi_req->module = buf; wsgi_req->module_len = len; wsgi_req->dynamic = 1; return 0; } if (!uwsgi_proto_key("UWSGI_PYHOME", 12)) { wsgi_req->home = buf; wsgi_req->home_len = len; return 0; } if (!uwsgi_proto_key("UWSGI_SETENV", 12)) { char *env_value = memchr(buf, '=', len); if (env_value) { env_value[0] = 0; env_value = uwsgi_concat2n(env_value + 1, len - ((env_value + 1) - buf), "", 0); if (setenv(buf, env_value, 1)) { uwsgi_error("setenv()"); } free(env_value); } return 0; } return 0; } static int uwsgi_proto_check_13(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) { if (!uwsgi_proto_key("DOCUMENT_ROOT", 13)) { wsgi_req->document_root = buf; wsgi_req->document_root_len = len; return 0; } return 0; } static int uwsgi_proto_check_14(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) { if (!uwsgi_proto_key("REQUEST_METHOD", 14)) { wsgi_req->method = buf; wsgi_req->method_len = len; return 0; } if (!uwsgi_proto_key("CONTENT_LENGTH", 14)) { wsgi_req->post_cl = get_content_length(buf, len); if (uwsgi.limit_post) { if (wsgi_req->post_cl > uwsgi.limit_post) { uwsgi_log("Invalid (too big) CONTENT_LENGTH. skip.\n"); return -1; } } return 0; } if (!uwsgi_proto_key("UWSGI_POSTFILE", 14)) { char *postfile = uwsgi_concat2n(buf, len, "", 0); wsgi_req->post_file = fopen(postfile, "r"); if (!wsgi_req->post_file) { uwsgi_error_open(postfile); } free(postfile); return 0; } if (!uwsgi_proto_key("UWSGI_CALLABLE", 14)) { wsgi_req->callable = buf; wsgi_req->callable_len = len; wsgi_req->dynamic = 1; return 0; } return 0; } static int uwsgi_proto_check_15(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) { if (!uwsgi_proto_key("SERVER_PROTOCOL", 15)) { wsgi_req->protocol = buf; wsgi_req->protocol_len = len; return 0; } if (!uwsgi_proto_key("HTTP_USER_AGENT", 15)) { wsgi_req->user_agent = buf; wsgi_req->user_agent_len = len; return 0; } if (uwsgi.caches && !uwsgi_proto_key("UWSGI_CACHE_GET", 15)) { wsgi_req->cache_get = buf; wsgi_req->cache_get_len = len; return 0; } return 0; } static int uwsgi_proto_check_18(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) { if (!uwsgi_proto_key("HTTP_AUTHORIZATION", 18)) { wsgi_req->authorization = buf; wsgi_req->authorization_len = len; return 0; } if (!uwsgi_proto_key("UWSGI_TOUCH_RELOAD", 18)) { wsgi_req->touch_reload = buf; wsgi_req->touch_reload_len = len; return 0; } return 0; } static int uwsgi_proto_check_20(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) { if (uwsgi.logging_options.log_x_forwarded_for && !uwsgi_proto_key("HTTP_X_FORWARDED_FOR", 20)) { wsgi_req->remote_addr = buf; wsgi_req->remote_addr_len = len; return 0; } if (!uwsgi_proto_key("HTTP_X_FORWARDED_SSL", 20)) { wsgi_req->https = buf; wsgi_req->https_len = len; } if (!uwsgi_proto_key("HTTP_ACCEPT_ENCODING", 20)) { wsgi_req->encoding = buf; wsgi_req->encoding_len = len; return 0; } return 0; } static int uwsgi_proto_check_22(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) { if (!uwsgi_proto_key("HTTP_IF_MODIFIED_SINCE", 22)) { wsgi_req->if_modified_since = buf; wsgi_req->if_modified_since_len = len; return 0; } if (!uwsgi_proto_key("HTTP_SEC_WEBSOCKET_KEY", 22)) { wsgi_req->http_sec_websocket_key = buf; wsgi_req->http_sec_websocket_key_len = len; return 0; } if (!uwsgi_proto_key("HTTP_X_FORWARDED_PROTO", 22)) { wsgi_req->scheme = buf; wsgi_req->scheme_len = len; } return 0; } static int uwsgi_proto_check_27(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) { if (!uwsgi_proto_key("HTTP_SEC_WEBSOCKET_PROTOCOL", 27)) { wsgi_req->http_sec_websocket_protocol = buf; wsgi_req->http_sec_websocket_protocol_len = len; return 0; } return 0; } void uwsgi_proto_hooks_setup() { int i = 0; for(i=0;ibuffer; char *ptrbuf, *bufferend; uint16_t strsize = 0; struct uwsgi_dyn_dict *udd; ptrbuf = buffer; bufferend = ptrbuf + wsgi_req->uh->pktsize; int i; /* set an HTTP 500 status as default */ wsgi_req->status = 500; // skip if already parsed if (wsgi_req->parsed) return 0; // has the protocol already parsed the request ? if (wsgi_req->uri_len > 0) { wsgi_req->parsed = 1; i = uwsgi_simple_parse_vars(wsgi_req, ptrbuf, bufferend); if (i == 0) goto next; return i; } wsgi_req->parsed = 1; wsgi_req->script_name_pos = -1; wsgi_req->path_info_pos = -1; while (ptrbuf < bufferend) { if (ptrbuf + 2 < bufferend) { memcpy(&strsize, ptrbuf, 2); #ifdef __BIG_ENDIAN__ strsize = uwsgi_swap16(strsize); #endif /* key cannot be null */ if (!strsize) { uwsgi_log("uwsgi key cannot be null. skip this var.\n"); return -1; } ptrbuf += 2; if (ptrbuf + strsize < bufferend) { // var key wsgi_req->hvec[wsgi_req->var_cnt].iov_base = ptrbuf; wsgi_req->hvec[wsgi_req->var_cnt].iov_len = strsize; ptrbuf += strsize; // value can be null (even at the end) so use <= if (ptrbuf + 2 <= bufferend) { memcpy(&strsize, ptrbuf, 2); #ifdef __BIG_ENDIAN__ strsize = uwsgi_swap16(strsize); #endif ptrbuf += 2; if (ptrbuf + strsize <= bufferend) { if (wsgi_req->hvec[wsgi_req->var_cnt].iov_len > UWSGI_PROTO_MIN_CHECK && wsgi_req->hvec[wsgi_req->var_cnt].iov_len < UWSGI_PROTO_MAX_CHECK && uwsgi.proto_hooks[wsgi_req->hvec[wsgi_req->var_cnt].iov_len]) { if (uwsgi.proto_hooks[wsgi_req->hvec[wsgi_req->var_cnt].iov_len](wsgi_req, wsgi_req->hvec[wsgi_req->var_cnt].iov_base, ptrbuf, strsize)) { return -1; } } //uwsgi_log("uwsgi %.*s = %.*s\n", wsgi_req->hvec[wsgi_req->var_cnt].iov_len, wsgi_req->hvec[wsgi_req->var_cnt].iov_base, strsize, ptrbuf); if (wsgi_req->var_cnt < uwsgi.vec_size - (4 + 1)) { wsgi_req->var_cnt++; } else { uwsgi_log("max vec size reached. skip this var.\n"); return -1; } // var value wsgi_req->hvec[wsgi_req->var_cnt].iov_base = ptrbuf; wsgi_req->hvec[wsgi_req->var_cnt].iov_len = strsize; //uwsgi_log("%.*s = %.*s\n", wsgi_req->hvec[wsgi_req->var_cnt-1].iov_len, wsgi_req->hvec[wsgi_req->var_cnt-1].iov_base, wsgi_req->hvec[wsgi_req->var_cnt].iov_len, wsgi_req->hvec[wsgi_req->var_cnt].iov_base); if (wsgi_req->var_cnt < uwsgi.vec_size - (4 + 1)) { wsgi_req->var_cnt++; } else { uwsgi_log("max vec size reached. skip this var.\n"); return -1; } ptrbuf += strsize; } else { uwsgi_log("invalid uwsgi request (current strsize: %d). skip.\n", strsize); return -1; } } else { uwsgi_log("invalid uwsgi request (current strsize: %d). skip.\n", strsize); return -1; } } } else { uwsgi_log("invalid uwsgi request (current strsize: %d). skip.\n", strsize); return -1; } } next: // manage post buffering (if needed as post_file could be created before) if (uwsgi.post_buffering > 0 && !wsgi_req->post_file) { // read to disk if post_cl > post_buffering (it will eventually do upload progress...) if (wsgi_req->post_cl >= uwsgi.post_buffering) { if (uwsgi_postbuffer_do_in_disk(wsgi_req)) { return -1; } } // on tiny post use memory else { if (uwsgi_postbuffer_do_in_mem(wsgi_req)) { return -1; } } } // check if data are available in the local cache if (wsgi_req->cache_get_len > 0) { uint64_t cache_value_size; char *cache_value = uwsgi_cache_magic_get(wsgi_req->cache_get, wsgi_req->cache_get_len, &cache_value_size, NULL, NULL); if (cache_value && cache_value_size > 0) { uwsgi_response_write_body_do(wsgi_req, cache_value, cache_value_size); free(cache_value); return -1; } } if (uwsgi.check_cache && wsgi_req->uri_len && wsgi_req->method_len == 3 && wsgi_req->method[0] == 'G' && wsgi_req->method[1] == 'E' && wsgi_req->method[2] == 'T') { uint64_t cache_value_size; char *cache_value = uwsgi_cache_magic_get(wsgi_req->uri, wsgi_req->uri_len, &cache_value_size, NULL, NULL); if (cache_value && cache_value_size > 0) { uwsgi_response_write_body_do(wsgi_req, cache_value, cache_value_size); free(cache_value); return -1; } } if (uwsgi.manage_script_name) { if (uwsgi_apps_cnt > 0 && wsgi_req->path_info_len > 1 && wsgi_req->path_info_pos != -1) { // starts with 1 as the 0 app is the default (/) one int best_found = 0; char *orig_path_info = wsgi_req->path_info; int orig_path_info_len = wsgi_req->path_info_len; // if SCRIPT_NAME is not allocated, add a slot for it if (wsgi_req->script_name_pos == -1) { if (wsgi_req->var_cnt >= uwsgi.vec_size - (4 + 2)) { uwsgi_log("max vec size reached. skip this var.\n"); return -1; } wsgi_req->hvec[wsgi_req->var_cnt].iov_base = "SCRIPT_NAME"; wsgi_req->hvec[wsgi_req->var_cnt].iov_len = 11; wsgi_req->var_cnt++; wsgi_req->script_name_pos = wsgi_req->var_cnt; wsgi_req->hvec[wsgi_req->script_name_pos].iov_base = ""; wsgi_req->hvec[wsgi_req->script_name_pos].iov_len = 0; wsgi_req->var_cnt++; } for (i = 0; i < uwsgi_apps_cnt; i++) { char* mountpoint = uwsgi_apps[i].mountpoint; int mountpoint_len = uwsgi_apps[i].mountpoint_len; // Ignore trailing mountpoint slashes if (mountpoint_len > 0 && mountpoint[mountpoint_len - 1] == '/') { mountpoint_len -= 1; } //uwsgi_log("app mountpoint = %.*s\n", uwsgi_apps[i].mountpoint_len, uwsgi_apps[i].mountpoint); // Check if mountpoint could be a possible candidate if (orig_path_info_len < mountpoint_len || // it should be shorter than or equal to path_info mountpoint_len <= best_found || // it should be better than the previous found // should have the same prefix of path_info uwsgi_startswith(orig_path_info, mountpoint, mountpoint_len) || // and should not be "misleading" (orig_path_info_len > mountpoint_len && orig_path_info[mountpoint_len] != '/' )) { continue; } best_found = mountpoint_len; wsgi_req->script_name = uwsgi_apps[i].mountpoint; wsgi_req->script_name_len = uwsgi_apps[i].mountpoint_len; wsgi_req->path_info = orig_path_info + wsgi_req->script_name_len; wsgi_req->path_info_len = orig_path_info_len - wsgi_req->script_name_len; wsgi_req->hvec[wsgi_req->script_name_pos].iov_base = wsgi_req->script_name; wsgi_req->hvec[wsgi_req->script_name_pos].iov_len = wsgi_req->script_name_len; wsgi_req->hvec[wsgi_req->path_info_pos].iov_base = wsgi_req->path_info; wsgi_req->hvec[wsgi_req->path_info_pos].iov_len = wsgi_req->path_info_len; #ifdef UWSGI_DEBUG uwsgi_log("managed SCRIPT_NAME = %.*s PATH_INFO = %.*s\n", wsgi_req->script_name_len, wsgi_req->script_name, wsgi_req->path_info_len, wsgi_req->path_info); #endif } } } /* CHECK FOR STATIC FILES */ // skip extensions struct uwsgi_string_list *sse = uwsgi.static_skip_ext; while (sse) { if (wsgi_req->path_info_len >= sse->len) { if (!uwsgi_strncmp(wsgi_req->path_info + (wsgi_req->path_info_len - sse->len), sse->len, sse->value, sse->len)) { return 0; } } sse = sse->next; } // check if a file named uwsgi.check_static+env['PATH_INFO'] exists udd = uwsgi.check_static; while (udd) { // need to build the path ? if (udd->value == NULL) { if (uwsgi.threads > 1) pthread_mutex_lock(&uwsgi.lock_static); udd->value = uwsgi_malloc(PATH_MAX + 1); if (!realpath(udd->key, udd->value)) { free(udd->value); udd->value = NULL; } if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.lock_static); if (!udd->value) goto nextcs; udd->vallen = strlen(udd->value); } if (!uwsgi_file_serve(wsgi_req, udd->value, udd->vallen, wsgi_req->path_info, wsgi_req->path_info_len, 0)) { return -1; } nextcs: udd = udd->next; } // check static-map udd = uwsgi.static_maps; while (udd) { #ifdef UWSGI_DEBUG uwsgi_log("checking for %.*s <-> %.*s %.*s\n", (int)wsgi_req->path_info_len, wsgi_req->path_info, (int)udd->keylen, udd->key, (int) udd->vallen, udd->value); #endif if (udd->status == 0) { if (uwsgi.threads > 1) pthread_mutex_lock(&uwsgi.lock_static); char *real_docroot = uwsgi_malloc(PATH_MAX + 1); if (!realpath(udd->value, real_docroot)) { free(real_docroot); real_docroot = NULL; udd->value = NULL; } if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.lock_static); if (!real_docroot) goto nextsm; udd->value = real_docroot; udd->vallen = strlen(udd->value); udd->status = 1 + uwsgi_is_file(real_docroot); } if (!uwsgi_starts_with(wsgi_req->path_info, wsgi_req->path_info_len, udd->key, udd->keylen)) { if (!uwsgi_file_serve(wsgi_req, udd->value, udd->vallen, wsgi_req->path_info + udd->keylen, wsgi_req->path_info_len - udd->keylen, udd->status - 1)) { return -1; } } nextsm: udd = udd->next; } // check for static_maps in append mode udd = uwsgi.static_maps2; while (udd) { #ifdef UWSGI_DEBUG uwsgi_log("checking for %.*s <-> %.*s\n", wsgi_req->path_info_len, wsgi_req->path_info, udd->keylen, udd->key); #endif if (udd->status == 0) { if (uwsgi.threads > 1) pthread_mutex_lock(&uwsgi.lock_static); char *real_docroot = uwsgi_malloc(PATH_MAX + 1); if (!realpath(udd->value, real_docroot)) { free(real_docroot); real_docroot = NULL; udd->value = NULL; } if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.lock_static); if (!real_docroot) goto nextsm2; udd->value = real_docroot; udd->vallen = strlen(udd->value); udd->status = 1 + uwsgi_is_file(real_docroot); } if (!uwsgi_starts_with(wsgi_req->path_info, wsgi_req->path_info_len, udd->key, udd->keylen)) { if (!uwsgi_file_serve(wsgi_req, udd->value, udd->vallen, wsgi_req->path_info, wsgi_req->path_info_len, udd->status - 1)) { return -1; } } nextsm2: udd = udd->next; } // finally check for docroot if (uwsgi.check_static_docroot && wsgi_req->document_root_len > 0) { char *real_docroot = uwsgi_expand_path(wsgi_req->document_root, wsgi_req->document_root_len, NULL); if (!real_docroot) { return -1; } if (!uwsgi_file_serve(wsgi_req, real_docroot, strlen(real_docroot), wsgi_req->path_info, wsgi_req->path_info_len, 0)) { free(real_docroot); return -1; } free(real_docroot); } return 0; } int uwsgi_hooked_parse(char *buffer, size_t len, void (*hook) (char *, uint16_t, char *, uint16_t, void *), void *data) { char *ptrbuf, *bufferend; uint16_t keysize = 0, valsize = 0; char *key; ptrbuf = buffer; bufferend = buffer + len; while (ptrbuf < bufferend) { if (ptrbuf + 2 >= bufferend) return -1; memcpy(&keysize, ptrbuf, 2); #ifdef __BIG_ENDIAN__ keysize = uwsgi_swap16(keysize); #endif /* key cannot be null */ if (!keysize) return -1; ptrbuf += 2; if (ptrbuf + keysize > bufferend) return -1; // key key = ptrbuf; ptrbuf += keysize; // value can be null if (ptrbuf + 2 > bufferend) return -1; memcpy(&valsize, ptrbuf, 2); #ifdef __BIG_ENDIAN__ valsize = uwsgi_swap16(valsize); #endif ptrbuf += 2; if (ptrbuf + valsize > bufferend) return -1; // now call the hook hook(key, keysize, ptrbuf, valsize, data); ptrbuf += valsize; } return 0; } int uwsgi_hooked_parse_array(char *buffer, size_t len, void (*hook) (uint16_t, char *, uint16_t, void *), void *data) { char *ptrbuf, *bufferend; uint16_t valsize = 0; char *value; uint16_t pos = 0; ptrbuf = buffer; bufferend = buffer + len; while (ptrbuf < bufferend) { if (ptrbuf + 2 > bufferend) return -1; memcpy(&valsize, ptrbuf, 2); #ifdef __BIG_ENDIAN__ valsize = uwsgi_swap16(valsize); #endif ptrbuf += 2; if (ptrbuf + valsize > bufferend) return -1; // key value = ptrbuf; // now call the hook hook(pos, value, valsize, data); ptrbuf += valsize; pos++; } return 0; } // this functions transform a raw HTTP response to a uWSGI-managed response int uwsgi_blob_to_response(struct wsgi_request *wsgi_req, char *body, size_t len) { char *line = body; size_t line_len = 0; size_t i; int status_managed = 0; for(i=0;ibuffer (generally when uwsgi protocol is in use) In such a case, allocate a proto_parser_buf and move data there */ char *uwsgi_req_append(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, char *val, uint16_t vallen) { if (!wsgi_req->proto_parser_buf) { if (wsgi_req->proto_parser_remains > 0) { wsgi_req->proto_parser_buf = uwsgi_malloc(wsgi_req->proto_parser_remains); memcpy(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains); wsgi_req->proto_parser_remains_buf = wsgi_req->proto_parser_buf; } } if ((wsgi_req->uh->pktsize + (2 + keylen + 2 + vallen)) > uwsgi.buffer_size) { uwsgi_log("not enough buffer space to add %.*s variable, consider increasing it with the --buffer-size option\n", keylen, key); return NULL; } if (wsgi_req->var_cnt >= uwsgi.vec_size - (4 + 2)) { uwsgi_log("max vec size reached. skip this header.\n"); return NULL; } char *ptr = wsgi_req->buffer + wsgi_req->uh->pktsize; *ptr++ = (uint8_t) (keylen & 0xff); *ptr++ = (uint8_t) ((keylen >> 8) & 0xff); memcpy(ptr, key, keylen); wsgi_req->hvec[wsgi_req->var_cnt].iov_base = ptr; wsgi_req->hvec[wsgi_req->var_cnt].iov_len = keylen; wsgi_req->var_cnt++; ptr += keylen; *ptr++ = (uint8_t) (vallen & 0xff); *ptr++ = (uint8_t) ((vallen >> 8) & 0xff); memcpy(ptr, val, vallen); wsgi_req->hvec[wsgi_req->var_cnt].iov_base = ptr; wsgi_req->hvec[wsgi_req->var_cnt].iov_len = vallen; wsgi_req->var_cnt++; wsgi_req->uh->pktsize += (2 + keylen + 2 + vallen); return ptr; } int uwsgi_req_append_path_info_with_index(struct wsgi_request *wsgi_req, char *index, uint16_t index_len) { if (!wsgi_req->proto_parser_buf) { if (wsgi_req->proto_parser_remains > 0) { wsgi_req->proto_parser_buf = uwsgi_malloc(wsgi_req->proto_parser_remains); memcpy(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains); wsgi_req->proto_parser_remains_buf = wsgi_req->proto_parser_buf; } } uint8_t need_slash = 0; if (wsgi_req->path_info_len > 0) { if (wsgi_req->path_info[wsgi_req->path_info_len-1] != '/') { need_slash = 1; } } wsgi_req->path_info_len += need_slash + index_len; // 2 + 9 + 2 if ((wsgi_req->uh->pktsize + (13 + wsgi_req->path_info_len)) > uwsgi.buffer_size) { uwsgi_log("not enough buffer space to transform the PATH_INFO variable, consider increasing it with the --buffer-size option\n"); return -1; } if (wsgi_req->var_cnt >= uwsgi.vec_size - (4 + 2)) { uwsgi_log("max vec size reached for PATH_INFO + index. skip this request.\n"); return -1; } uint16_t keylen = 9; char *ptr = wsgi_req->buffer + wsgi_req->uh->pktsize; *ptr++ = (uint8_t) (keylen & 0xff); *ptr++ = (uint8_t) ((keylen >> 8) & 0xff); memcpy(ptr, "PATH_INFO", keylen); wsgi_req->hvec[wsgi_req->var_cnt].iov_base = ptr; wsgi_req->hvec[wsgi_req->var_cnt].iov_len = keylen; wsgi_req->var_cnt++; ptr += keylen; *ptr++ = (uint8_t) (wsgi_req->path_info_len & 0xff); *ptr++ = (uint8_t) ((wsgi_req->path_info_len >> 8) & 0xff); char *new_path_info = ptr; memcpy(ptr, wsgi_req->path_info, wsgi_req->path_info_len - (need_slash + index_len)); ptr+=wsgi_req->path_info_len - (need_slash + index_len); if (need_slash) { *ptr ++= '/'; } memcpy(ptr, index, index_len); wsgi_req->hvec[wsgi_req->var_cnt].iov_base = new_path_info; wsgi_req->hvec[wsgi_req->var_cnt].iov_len = wsgi_req->path_info_len; wsgi_req->var_cnt++; wsgi_req->uh->pktsize += 13 + wsgi_req->path_info_len; wsgi_req->path_info = new_path_info; return 0; } uwsgi-2.0.29/core/querystring.c000066400000000000000000000021501477626554400164540ustar00rootroot00000000000000#include "uwsgi.h" /* QUERY_STRING management functions (mainly used by the internal routing subsystem) */ static char *check_qs(char *qs, uint16_t qs_len, char *key, uint16_t keylen, uint16_t *vallen) { // search for the equal sign char *equal = memchr(qs, '=', qs_len); if (!equal) return NULL; if (uwsgi_strncmp(key, keylen, qs, equal-qs)) { return NULL; } qs_len -= (equal-qs)+1; if (qs_len == 0) return NULL; *vallen = qs_len; return equal+1; } char *uwsgi_get_qs(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) { uint16_t i; char *qs = wsgi_req->query_string; uint16_t qs_len = 0; char *ptr = wsgi_req->query_string; //start splitting by ; for(i=0;iquery_string_len;i++) { if (!qs) { qs = ptr + i; } if (ptr[i] == '&') { char *value = check_qs(qs, qs_len, key, keylen, vallen); if (value) { return value; } qs_len = 0; qs = NULL; } else { qs_len++; } } if (qs_len > 0) { char *value = check_qs(qs, qs_len, key, keylen, vallen); if (value) { return value; } } return NULL; } uwsgi-2.0.29/core/queue.c000066400000000000000000000105441477626554400152120ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; void uwsgi_init_queue() { if (!uwsgi.queue_blocksize) uwsgi.queue_blocksize = 8192; if ((uwsgi.queue_blocksize * uwsgi.queue_size) % uwsgi.page_size != 0) { uwsgi_log("invalid queue size/blocksize %llu: must be a multiple of memory page size (%d bytes)\n", (unsigned long long) uwsgi.queue_blocksize, uwsgi.page_size); exit(1); } if (uwsgi.queue_store) { uwsgi.queue_filesize = uwsgi.queue_blocksize * uwsgi.queue_size + 16; int queue_fd; struct stat qst; if (stat(uwsgi.queue_store, &qst)) { uwsgi_log("creating a new queue store file: %s\n", uwsgi.queue_store); queue_fd = open(uwsgi.queue_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); if (queue_fd >= 0) { // fill the queue store if (ftruncate(queue_fd, uwsgi.queue_filesize)) { uwsgi_log("ftruncate()"); exit(1); } } } else { if ((size_t) qst.st_size != uwsgi.queue_filesize || !S_ISREG(qst.st_mode)) { uwsgi_log("invalid queue store file. Please remove it or fix queue blocksize/items to match its size\n"); exit(1); } queue_fd = open(uwsgi.queue_store, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); uwsgi_log("recovered queue from backing store file: %s\n", uwsgi.queue_store); } if (queue_fd < 0) { uwsgi_error_open(uwsgi.queue_store); exit(1); } uwsgi.queue = mmap(NULL, uwsgi.queue_filesize, PROT_READ | PROT_WRITE, MAP_SHARED, queue_fd, 0); // fix header uwsgi.queue_header = uwsgi.queue; uwsgi.queue += 16; close(queue_fd); } else { uwsgi.queue = mmap(NULL, (uwsgi.queue_blocksize * uwsgi.queue_size) + 16, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); // fix header uwsgi.queue_header = uwsgi.queue; uwsgi.queue += 16; uwsgi.queue_header->pos = 0; uwsgi.queue_header->pull_pos = 0; } if (uwsgi.queue == MAP_FAILED) { uwsgi_error("mmap()"); exit(1); } uwsgi.queue_lock = uwsgi_rwlock_init("queue"); uwsgi_log("*** Queue subsystem initialized: %luMB preallocated ***\n", (uwsgi.queue_blocksize * uwsgi.queue_size) / (1024 * 1024)); } char *uwsgi_queue_get(uint64_t index, uint64_t * size) { struct uwsgi_queue_item *uqi; char *ptr = (char *) uwsgi.queue; if (index >= uwsgi.queue_size) return NULL; ptr = ptr + (uwsgi.queue_blocksize * index); uqi = (struct uwsgi_queue_item *) ptr; *size = uqi->size; return ptr + sizeof(struct uwsgi_queue_item); } char *uwsgi_queue_pop(uint64_t * size) { struct uwsgi_queue_item *uqi; char *ptr = (char *) uwsgi.queue; if (uwsgi.queue_header->pos == 0) { uwsgi.queue_header->pos = uwsgi.queue_size - 1; } else { uwsgi.queue_header->pos--; } ptr = ptr + (uwsgi.queue_blocksize * uwsgi.queue_header->pos); uqi = (struct uwsgi_queue_item *) ptr; if (!uqi->size) return NULL; *size = uqi->size; // remove item uqi->size = 0; return ptr + sizeof(struct uwsgi_queue_item); } char *uwsgi_queue_pull(uint64_t * size) { struct uwsgi_queue_item *uqi; char *ptr = (char *) uwsgi.queue; ptr = ptr + (uwsgi.queue_blocksize * uwsgi.queue_header->pull_pos); uqi = (struct uwsgi_queue_item *) ptr; if (!uqi->size) return NULL; *size = uqi->size; uwsgi.queue_header->pull_pos++; if (uwsgi.queue_header->pull_pos >= uwsgi.queue_size) uwsgi.queue_header->pull_pos = 0; // remove item uqi->size = 0; return ptr + sizeof(struct uwsgi_queue_item); } int uwsgi_queue_push(char *message, uint64_t size) { struct uwsgi_queue_item *uqi; char *ptr = (char *) uwsgi.queue; if (size > uwsgi.queue_blocksize - sizeof(struct uwsgi_queue_item)) return 0; if (!size) return 0; ptr = ptr + (uwsgi.queue_blocksize * uwsgi.queue_header->pos); uqi = (struct uwsgi_queue_item *) ptr; ptr += sizeof(struct uwsgi_queue_item); uqi->size = size; uqi->ts = uwsgi_now(); memcpy(ptr, message, size); uwsgi.queue_header->pos++; if (uwsgi.queue_header->pos >= uwsgi.queue_size) uwsgi.queue_header->pos = 0; return 1; } int uwsgi_queue_set(uint64_t pos, char *message, uint64_t size) { struct uwsgi_queue_item *uqi; char *ptr = (char *) uwsgi.queue; if (size > uwsgi.queue_blocksize + sizeof(struct uwsgi_queue_item)) return 0; if (!size) return 0; if (pos >= uwsgi.queue_size) return 0; ptr = ptr + (uwsgi.queue_blocksize * pos); uqi = (struct uwsgi_queue_item *) ptr; ptr += sizeof(struct uwsgi_queue_item); uqi->size = size; uqi->ts = uwsgi_now(); memcpy(ptr, message, size); return 1; } uwsgi-2.0.29/core/rb_timers.c000066400000000000000000000166171477626554400160630ustar00rootroot00000000000000/* uWSGI rbtree implementation based on nginx Copyright (C) Igor Sysoev Copyright (C) Nginx, Inc. Copyright (C) Unbit S.a.s. The red-black tree code is based on the algorithm described in the "Introduction to Algorithms" by Cormen, Leiserson and Rivest. */ #include "uwsgi.h" #define uwsgi_rbt_red(node) ((node)->color = 1) #define uwsgi_rbt_black(node) ((node)->color = 0) #define uwsgi_rbt_is_red(node) ((node)->color) #define uwsgi_rbt_is_black(node) (!uwsgi_rbt_is_red(node)) #define uwsgi_rbt_copy_color(n1, n2) (n1->color = n2->color) struct uwsgi_rbtree *uwsgi_init_rb_timer() { struct uwsgi_rbtree *tree = uwsgi_calloc(sizeof(struct uwsgi_rbtree)); struct uwsgi_rb_timer *sentinel = uwsgi_calloc(sizeof(struct uwsgi_rb_timer)); // no need to set it black, calloc already did it //uwsgi_rbt_black(sentinel); tree->root = sentinel; tree->sentinel = sentinel; return tree; } struct uwsgi_rb_timer *uwsgi_min_rb_timer(struct uwsgi_rbtree *tree, struct uwsgi_rb_timer *node) { if (!node) node = tree->root; struct uwsgi_rb_timer *sentinel = tree->sentinel; if (tree->root == sentinel) return NULL; while (node->left != sentinel) { node = node->left; } return node; } static void uwsgi_rbtree_lr(struct uwsgi_rb_timer **root, struct uwsgi_rb_timer *sentinel, struct uwsgi_rb_timer *node) { struct uwsgi_rb_timer *temp; temp = node->right; node->right = temp->left; if (temp->left != sentinel) { temp->left->parent = node; } temp->parent = node->parent; if (node == *root) { *root = temp; } else if (node == node->parent->left) { node->parent->left = temp; } else { node->parent->right = temp; } temp->left = node; node->parent = temp; } static void uwsgi_rbtree_rr(struct uwsgi_rb_timer **root, struct uwsgi_rb_timer *sentinel, struct uwsgi_rb_timer *node) { struct uwsgi_rb_timer *temp; temp = node->left; node->left = temp->right; if (temp->right != sentinel) { temp->right->parent = node; } temp->parent = node->parent; if (node == *root) { *root = temp; } else if (node == node->parent->right) { node->parent->right = temp; } else { node->parent->left = temp; } temp->right = node; node->parent = temp; } static void uwsgi_rbt_add(struct uwsgi_rb_timer *temp, struct uwsgi_rb_timer *node, struct uwsgi_rb_timer *sentinel) { struct uwsgi_rb_timer **p; for (;;) { p = (node->value < temp->value) ? &temp->left : &temp->right; if (*p == sentinel) break; temp = *p; } *p = node; node->parent = temp; node->left = sentinel; node->right = sentinel; uwsgi_rbt_red(node); } struct uwsgi_rb_timer *uwsgi_add_rb_timer(struct uwsgi_rbtree *tree, uint64_t value, void *data) { struct uwsgi_rb_timer *node = uwsgi_malloc(sizeof(struct uwsgi_rb_timer)); struct uwsgi_rb_timer *new_node = node; node->value = value; node->data = data; struct uwsgi_rb_timer *temp = NULL; /* a binary tree insert */ struct uwsgi_rb_timer **root = &tree->root; struct uwsgi_rb_timer *sentinel = tree->sentinel; if (*root == sentinel) { node->parent = NULL; node->left = sentinel; node->right = sentinel; uwsgi_rbt_black(node); *root = node; return new_node; } uwsgi_rbt_add(*root, node, sentinel); /* re-balance tree */ while (node != *root && uwsgi_rbt_is_red(node->parent)) { if (node->parent == node->parent->parent->left) { temp = node->parent->parent->right; if (uwsgi_rbt_is_red(temp)) { uwsgi_rbt_black(node->parent); uwsgi_rbt_black(temp); uwsgi_rbt_red(node->parent->parent); node = node->parent->parent; } else { if (node == node->parent->right) { node = node->parent; uwsgi_rbtree_lr(root, sentinel, node); } uwsgi_rbt_black(node->parent); uwsgi_rbt_red(node->parent->parent); uwsgi_rbtree_rr(root, sentinel, node->parent->parent); } } else { temp = node->parent->parent->left; if (uwsgi_rbt_is_red(temp)) { uwsgi_rbt_black(node->parent); uwsgi_rbt_black(temp); uwsgi_rbt_red(node->parent->parent); node = node->parent->parent; } else { if (node == node->parent->left) { node = node->parent; uwsgi_rbtree_rr(root, sentinel, node); } uwsgi_rbt_black(node->parent); uwsgi_rbt_red(node->parent->parent); uwsgi_rbtree_lr(root, sentinel, node->parent->parent); } } } uwsgi_rbt_black(*root); return new_node; } void uwsgi_del_rb_timer(struct uwsgi_rbtree *tree, struct uwsgi_rb_timer *node) { uint8_t red; struct uwsgi_rb_timer **root, *sentinel, *subst, *temp, *w; /* a binary tree delete */ root = &tree->root; sentinel = tree->sentinel; if (node->left == sentinel) { temp = node->right; subst = node; } else if (node->right == sentinel) { temp = node->left; subst = node; } else { subst = uwsgi_min_rb_timer(tree, node->right); if (subst->left != sentinel) { temp = subst->left; } else { temp = subst->right; } } if (subst == *root) { *root = temp; uwsgi_rbt_black(temp); return; } red = uwsgi_rbt_is_red(subst); if (subst == subst->parent->left) { subst->parent->left = temp; } else { subst->parent->right = temp; } if (subst == node) { temp->parent = subst->parent; } else { if (subst->parent == node) { temp->parent = subst; } else { temp->parent = subst->parent; } subst->left = node->left; subst->right = node->right; subst->parent = node->parent; uwsgi_rbt_copy_color(subst, node); if (node == *root) { *root = subst; } else { if (node == node->parent->left) { node->parent->left = subst; } else { node->parent->right = subst; } } if (subst->left != sentinel) { subst->left->parent = subst; } if (subst->right != sentinel) { subst->right->parent = subst; } } if (red) { return; } /* a delete fixup */ while (temp != *root && uwsgi_rbt_is_black(temp)) { if (temp == temp->parent->left) { w = temp->parent->right; if (uwsgi_rbt_is_red(w)) { uwsgi_rbt_black(w); uwsgi_rbt_red(temp->parent); uwsgi_rbtree_lr(root, sentinel, temp->parent); w = temp->parent->right; } if (uwsgi_rbt_is_black(w->left) && uwsgi_rbt_is_black(w->right)) { uwsgi_rbt_red(w); temp = temp->parent; } else { if (uwsgi_rbt_is_black(w->right)) { uwsgi_rbt_black(w->left); uwsgi_rbt_red(w); uwsgi_rbtree_rr(root, sentinel, w); w = temp->parent->right; } uwsgi_rbt_copy_color(w, temp->parent); uwsgi_rbt_black(temp->parent); uwsgi_rbt_black(w->right); uwsgi_rbtree_lr(root, sentinel, temp->parent); temp = *root; } } else { w = temp->parent->left; if (uwsgi_rbt_is_red(w)) { uwsgi_rbt_black(w); uwsgi_rbt_red(temp->parent); uwsgi_rbtree_rr(root, sentinel, temp->parent); w = temp->parent->left; } if (uwsgi_rbt_is_black(w->left) && uwsgi_rbt_is_black(w->right)) { uwsgi_rbt_red(w); temp = temp->parent; } else { if (uwsgi_rbt_is_black(w->left)) { uwsgi_rbt_black(w->right); uwsgi_rbt_red(w); uwsgi_rbtree_lr(root, sentinel, w); w = temp->parent->left; } uwsgi_rbt_copy_color(w, temp->parent); uwsgi_rbt_black(temp->parent); uwsgi_rbt_black(w->left); uwsgi_rbtree_rr(root, sentinel, temp->parent); temp = *root; } } } uwsgi_rbt_black(temp); } uwsgi-2.0.29/core/reader.c000066400000000000000000000504761477626554400153400ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; int uwsgi_simple_wait_read_hook(int fd, int timeout) { struct pollfd upoll; timeout = timeout * 1000; int ret; upoll.fd = fd; upoll.events = POLLIN; upoll.revents = 0; for (;;) { ret = poll(&upoll, 1, timeout); if ((ret < 0) && (errno == EINTR)) continue; break; } if (ret > 0) { if (upoll.revents & POLLIN) { return 1; } return -1; } if (ret < 0) { uwsgi_error("uwsgi_simple_wait_read_hook()/poll()"); } return ret; } int uwsgi_simple_wait_read2_hook(int fd0, int fd1, int timeout, int *fd) { struct pollfd upoll[2]; timeout = timeout * 1000; upoll[0].fd = fd0; upoll[0].events = POLLIN; upoll[0].revents = 0; upoll[1].fd = fd1; upoll[1].events = POLLIN; upoll[1].revents = 0; int ret = poll(upoll, 2, timeout); if (ret > 0) { if (upoll[0].revents & POLLIN) { *fd = fd0; return 1; } if (upoll[1].revents & POLLIN) { *fd = fd1; return 1; } return -1; } if (ret < 0) { uwsgi_error("uwsgi_simple_wait_read_hook2()/poll()"); } return ret; } /* seek()/rewind() language-independent implementations. */ void uwsgi_request_body_seek(struct wsgi_request *wsgi_req, off_t pos) { if (wsgi_req->post_file) { if (pos < 0) { if (fseek(wsgi_req->post_file, pos, SEEK_CUR)) { uwsgi_req_error("uwsgi_request_body_seek()/fseek()"); wsgi_req->read_errors++; } wsgi_req->post_pos = ftell(wsgi_req->post_file); return; } if (fseek(wsgi_req->post_file, pos, SEEK_SET)) { uwsgi_req_error("uwsgi_request_body_seek()/fseek()"); wsgi_req->read_errors++; } wsgi_req->post_pos = ftell(wsgi_req->post_file); return; } if (uwsgi.post_buffering) { if (pos < 0) { if ((off_t) wsgi_req->post_pos - pos < 0) { wsgi_req->post_pos = 0; return; } wsgi_req->post_pos -= pos; return; } if (pos >= (off_t) uwsgi.post_buffering) { pos = uwsgi.post_buffering - 1; } wsgi_req->post_pos = pos; } } /* read() and readline() language-independent implementations. */ #define uwsgi_read_error0(x) uwsgi_log("[uwsgi-body-read] Error reading %llu bytes. Content-Length: %llu consumed: %llu left: %llu message: Client closed connection\n",\ (unsigned long long) x,\ (unsigned long long) wsgi_req->post_cl, (unsigned long long) wsgi_req->post_pos, (unsigned long long) wsgi_req->post_cl-wsgi_req->post_pos); #define uwsgi_read_error(x) uwsgi_log("[uwsgi-body-read] Error reading %llu bytes. Content-Length: %llu consumed: %llu left: %llu message: %s\n",\ (unsigned long long) x,\ (unsigned long long) wsgi_req->post_cl, (unsigned long long) wsgi_req->post_pos, (unsigned long long) wsgi_req->post_cl-wsgi_req->post_pos,\ strerror(errno)); #define uwsgi_read_timeout(x) uwsgi_log("[uwsgi-body-read] Timeout reading %llu bytes. Content-Length: %llu consumed: %llu left: %llu\n",\ (unsigned long long) x,\ (unsigned long long) wsgi_req->post_cl, (unsigned long long) wsgi_req->post_pos, (unsigned long long) wsgi_req->post_cl-wsgi_req->post_pos); static int consume_body_for_readline(struct wsgi_request *wsgi_req) { size_t remains = UMIN(uwsgi.buffer_size, wsgi_req->post_cl - wsgi_req->post_pos); int ret; // allocate more memory if needed if (wsgi_req->post_readline_size - wsgi_req->post_readline_watermark == 0) { memmove(wsgi_req->post_readline_buf, wsgi_req->post_readline_buf + wsgi_req->post_readline_pos, wsgi_req->post_readline_watermark - wsgi_req->post_readline_pos); wsgi_req->post_readline_watermark -= wsgi_req->post_readline_pos; wsgi_req->post_readline_pos = 0; // still something to use ? if (wsgi_req->post_readline_size - wsgi_req->post_readline_watermark < remains) { char *tmp_buf = realloc(wsgi_req->post_readline_buf, wsgi_req->post_readline_size + remains); if (!tmp_buf) { uwsgi_req_error("consume_body_for_readline()/realloc()"); return -1; } wsgi_req->post_readline_buf = tmp_buf; wsgi_req->post_readline_size += remains; // INFORM THE USER HIS readline() USAGE IS FOOLISH if (!wsgi_req->post_warning && wsgi_req->post_readline_size > (uwsgi.body_read_warning * 1024*1024)) { uwsgi_log("[uwsgi-warning] you are using readline() on request body allocating over than %llu MB, that is really bad and can be avoided...\n", (unsigned long long) (wsgi_req->post_readline_size/(1024*1024))); wsgi_req->post_warning = 1; } } } remains = UMIN(wsgi_req->post_readline_size - wsgi_req->post_readline_watermark, wsgi_req->post_cl - wsgi_req->post_pos); // read from a file if (wsgi_req->post_file) { size_t ret = fread(wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark, remains, 1, wsgi_req->post_file); if (ret == 0) { uwsgi_req_error("consume_body_for_readline()/fread()"); return -1; } wsgi_req->post_pos += remains; wsgi_req->post_readline_watermark += remains; return 0; } // read from post_buffering memory if (uwsgi.post_buffering) { memcpy(wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark, wsgi_req->post_buffering_buf + wsgi_req->post_pos, remains); wsgi_req->post_pos += remains; wsgi_req->post_readline_watermark += remains; return 0; } // read from socket ssize_t len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark , remains); if (len > 0) { wsgi_req->post_pos += len; wsgi_req->post_readline_watermark += len; return 0; } if (len == 0) { uwsgi_read_error(remains); wsgi_req->read_errors++; return -1; } if (len < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) { goto wait; } uwsgi_read_error(remains); wsgi_req->read_errors++; return -1; } wait: ret = uwsgi_wait_read_req(wsgi_req); if (ret > 0) { len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_readline_buf + wsgi_req->post_readline_watermark , remains); if (len > 0) { wsgi_req->post_pos += len; wsgi_req->post_readline_watermark += len; return 0; } uwsgi_read_error(remains); wsgi_req->read_errors++; return -1; } // 0 means timeout else if (ret == 0) { uwsgi_read_timeout(remains); return -1; } uwsgi_read_error(remains); wsgi_req->read_errors++; return -1; } // TODO take hint into account // readline_buf is allocated when needed and freed at the end of the request char *uwsgi_request_body_readline(struct wsgi_request *wsgi_req, ssize_t hint, ssize_t *rlen) { // return 0 if no post_cl or pos >= post_cl and no residual data if ((!wsgi_req->post_cl || wsgi_req->post_pos >= wsgi_req->post_cl ) && !wsgi_req->post_readline_pos) { return uwsgi.empty; } // some residual data ? if (wsgi_req->post_readline_pos > 0) { size_t i; for(i=wsgi_req->post_readline_pos;ipost_readline_watermark;i++) { // found a newline if (wsgi_req->post_readline_buf[i] == '\n') { *rlen = (i+1)-wsgi_req->post_readline_pos; char *buf = wsgi_req->post_readline_buf + wsgi_req->post_readline_pos; wsgi_req->post_readline_pos += *rlen; // all the readline buffer has been consumed if (wsgi_req->post_readline_pos >= wsgi_req->post_readline_watermark) { wsgi_req->post_readline_pos = 0; wsgi_req->post_readline_watermark = 0; } return buf; } } // ok, no newline found, continue below } // allocate memory on the first round if (!wsgi_req->post_readline_buf) { size_t amount = UMIN(uwsgi.buffer_size, wsgi_req->post_cl); wsgi_req->post_readline_buf = malloc(amount); if (!wsgi_req->post_readline_buf) { uwsgi_req_error("uwsgi_request_body_readline()/malloc()"); wsgi_req->read_errors++; *rlen = -1; return NULL; } wsgi_req->post_readline_size = amount; } // ok, no newline found, consume a bit more of memory and retry for(;;) { // no more data to consume if (wsgi_req->post_pos >= wsgi_req->post_cl) break; if (consume_body_for_readline(wsgi_req)) { wsgi_req->read_errors++; *rlen = -1; return NULL; } size_t i; for(i=wsgi_req->post_readline_pos;ipost_readline_watermark;i++) { if (wsgi_req->post_readline_buf[i] == '\n') { *rlen = (i+1)-wsgi_req->post_readline_pos; char *buf = wsgi_req->post_readline_buf + wsgi_req->post_readline_pos; wsgi_req->post_readline_pos += *rlen; if (wsgi_req->post_readline_pos >= wsgi_req->post_readline_watermark) { wsgi_req->post_readline_pos = 0; wsgi_req->post_readline_watermark = 0; } return buf; } } } // no line found, let's return all *rlen = wsgi_req->post_readline_watermark - wsgi_req->post_readline_pos; char *buf = wsgi_req->post_readline_buf + wsgi_req->post_readline_pos; wsgi_req->post_readline_pos = 0; return buf; } char *uwsgi_request_body_read(struct wsgi_request *wsgi_req, ssize_t hint, ssize_t *rlen) { int ret = -1; size_t remains = hint; // return empty if no post_cl or pos >= post_cl and no residual data if ((!wsgi_req->post_cl || wsgi_req->post_pos >= wsgi_req->post_cl ) && !wsgi_req->post_readline_pos) { return uwsgi.empty; } // return the whole input if (remains <= 0) { remains = wsgi_req->post_cl; } // some residual data ? if (wsgi_req->post_readline_pos > 0) { if (remains <= (wsgi_req->post_readline_watermark - wsgi_req->post_readline_pos)) { *rlen = remains; char *buf = wsgi_req->post_readline_buf + wsgi_req->post_readline_pos; wsgi_req->post_readline_pos += remains; return buf; } // the hint is higher than residual data, let's copy it to read() memory and go on size_t avail = wsgi_req->post_readline_watermark - wsgi_req->post_readline_pos; // check if we have enough memory... if (avail > wsgi_req->post_read_buf_size) { char *tmp_buf = realloc(wsgi_req->post_read_buf, avail); if (!tmp_buf) { uwsgi_req_error("uwsgi_request_body_read()/realloc()"); *rlen = -1; wsgi_req->read_errors++; return NULL; } wsgi_req->post_read_buf = tmp_buf; wsgi_req->post_read_buf_size = avail; if (!wsgi_req->post_warning && wsgi_req->post_read_buf_size > (uwsgi.body_read_warning * 1024*1024)) { uwsgi_log("[uwsgi-warning] you are using read() on request body allocating over than %llu MB, that is really bad and can be avoided...\n", (unsigned long long) (wsgi_req->post_read_buf_size/(1024*1024))); wsgi_req->post_warning = 1; } } // fix remains... if (remains > 0) { remains -= avail; } *rlen += avail; memcpy(wsgi_req->post_read_buf, wsgi_req->post_readline_buf + wsgi_req->post_readline_pos, avail); wsgi_req->post_readline_pos = 0; wsgi_req->post_readline_watermark = 0; } if (remains + wsgi_req->post_pos > wsgi_req->post_cl) { remains = wsgi_req->post_cl - wsgi_req->post_pos; } if (remains == 0) { if (*rlen > 0) { return wsgi_req->post_read_buf; } else { return uwsgi.empty; } } // read from post buffering memory if (uwsgi.post_buffering > 0 && !wsgi_req->post_file) { *rlen += remains; char *buf = wsgi_req->post_buffering_buf+wsgi_req->post_pos; wsgi_req->post_pos += remains; return buf; } // ok we need to check if we need to allocate memory if (!wsgi_req->post_read_buf) { wsgi_req->post_read_buf = malloc(remains); if (!wsgi_req->post_read_buf) { uwsgi_req_error("uwsgi_request_body_read()/malloc()"); wsgi_req->read_errors++; *rlen = -1; return NULL; } wsgi_req->post_read_buf_size = remains; } // need to realloc ? else { if ((remains+*rlen) > wsgi_req->post_read_buf_size) { char *tmp_buf = realloc(wsgi_req->post_read_buf, (remains+*rlen)); if (!tmp_buf) { uwsgi_req_error("uwsgi_request_body_read()/realloc()"); wsgi_req->read_errors++; *rlen = -1; return NULL; } wsgi_req->post_read_buf = tmp_buf; wsgi_req->post_read_buf_size = (remains+*rlen); if (!wsgi_req->post_warning && wsgi_req->post_read_buf_size > (uwsgi.body_read_warning * 1024*1024)) { uwsgi_log("[uwsgi-warning] you are using read() on request body allocating over than %llu MB, that is really bad and can be avoided...\n", (unsigned long long) (wsgi_req->post_read_buf_size/(1024*1024))); wsgi_req->post_warning = 1; } } } // check for disk buffered body first (they are all read in one shot) if (wsgi_req->post_file) { if (fread(wsgi_req->post_read_buf + *rlen, remains, 1, wsgi_req->post_file) != 1) { *rlen = -1; uwsgi_req_error("uwsgi_request_body_read()/fread()"); wsgi_req->read_errors++; return NULL; } *rlen += remains; wsgi_req->post_pos+= remains; return wsgi_req->post_read_buf; } // ok read all the required bytes... while(remains > 0) { // here we first try to read (as data could be already available) ssize_t len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_read_buf + *rlen , remains); if (len > 0) { wsgi_req->post_pos+=len; remains -= len; *rlen += len; continue; } // client closed connection... if (len == 0) { *rlen = -1; uwsgi_read_error0(remains); return NULL; } if (len < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) { goto wait; } *rlen = -1; uwsgi_read_error(remains); wsgi_req->read_errors++; return NULL; } wait: ret = uwsgi_wait_read_req(wsgi_req); if (ret > 0) { len = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_read_buf + *rlen, remains); if (len > 0) { wsgi_req->post_pos+=len; remains -= len; *rlen += len; continue; }else if (len < 0 && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS)) { goto wait; } *rlen = -1; if (len == 0) { uwsgi_read_error0(remains); } else { uwsgi_read_error(remains); wsgi_req->read_errors++; } return NULL; } // 0 means timeout else if (ret == 0) { *rlen = 0; uwsgi_read_timeout(remains); return NULL; } *rlen = -1; uwsgi_read_error(remains); wsgi_req->read_errors++; return NULL; } return wsgi_req->post_read_buf; } /* post buffering */ int uwsgi_postbuffer_do_in_mem(struct wsgi_request *wsgi_req) { size_t remains = wsgi_req->post_cl; int ret; char *ptr = wsgi_req->post_buffering_buf; while (remains > 0) { if (uwsgi.harakiri_options.workers > 0) { inc_harakiri(uwsgi.harakiri_options.workers); } ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, ptr, remains); if (rlen > 0) { remains -= rlen; ptr += rlen; continue; } if (rlen == 0) { uwsgi_read_error0(remains); return -1; } if (rlen < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) { goto wait; } uwsgi_read_error(remains); wsgi_req->read_errors++; return -1; } wait: ret = uwsgi_wait_read_req(wsgi_req); if (ret > 0) { rlen = wsgi_req->socket->proto_read_body(wsgi_req, ptr, remains); if (rlen > 0) { remains -= rlen; ptr += rlen; continue; } } if (ret < 0) { uwsgi_read_error(remains); wsgi_req->read_errors++; return -1; } uwsgi_read_timeout(remains); return -1; } return 0; } int uwsgi_postbuffer_do_in_disk(struct wsgi_request *wsgi_req) { size_t post_remains = wsgi_req->post_cl; int ret; int upload_progress_fd = -1; char *upload_progress_filename = NULL; wsgi_req->post_file = uwsgi_tmpfile(); if (!wsgi_req->post_file) { uwsgi_req_error("uwsgi_postbuffer_do_in_disk()/uwsgi_tmpfile()"); wsgi_req->read_errors++; return -1; } if (uwsgi.upload_progress) { // first check for X-Progress-ID size // separator + 'X-Progress-ID' + '=' + uuid upload_progress_filename = uwsgi_upload_progress_create(wsgi_req, &upload_progress_fd); if (!upload_progress_filename) { uwsgi_log("invalid X-Progress-ID value: must be a UUID\n"); } } // manage buffered data and upload progress while (post_remains > 0) { // during post buffering we need to constantly reset the harakiri if (uwsgi.harakiri_options.workers > 0) { inc_harakiri(uwsgi.harakiri_options.workers); } // we use the already available post buffering buffer to read chunks.... size_t remains = UMIN(post_remains, uwsgi.post_buffering); // first try to read data (there could be something already available ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_buffering_buf, remains); if (rlen > 0) goto write; if (rlen == 0) { uwsgi_read_error0(remains); goto end; } if (rlen < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) { goto wait; } uwsgi_read_error(remains); wsgi_req->read_errors++; goto end; } wait: ret = uwsgi_wait_read_req(wsgi_req); if (ret > 0) { rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->post_buffering_buf, remains); if (rlen > 0) goto write; if (rlen == 0) { uwsgi_read_error0(remains); } else { uwsgi_read_error(remains); wsgi_req->read_errors++; } goto end; } if (ret < 0) { uwsgi_read_error(remains); wsgi_req->read_errors++; goto end; } uwsgi_read_timeout(remains); goto end; write: if (fwrite(wsgi_req->post_buffering_buf, rlen, 1, wsgi_req->post_file) != 1) { uwsgi_req_error("uwsgi_postbuffer_do_in_disk()/fwrite()"); wsgi_req->read_errors++; goto end; } post_remains -= rlen; if (upload_progress_filename) { // stop updating it on errors if (uwsgi_upload_progress_update(wsgi_req, upload_progress_fd, post_remains)) { uwsgi_upload_progress_destroy(upload_progress_filename, upload_progress_fd); upload_progress_filename = NULL; } } } rewind(wsgi_req->post_file); if (upload_progress_filename) { uwsgi_upload_progress_destroy(upload_progress_filename, upload_progress_fd); } return 0; end: if (upload_progress_filename) { uwsgi_upload_progress_destroy(upload_progress_filename, upload_progress_fd); } return -1; } uwsgi-2.0.29/core/regexp.c000066400000000000000000000104421477626554400153550ustar00rootroot00000000000000#if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) #include "uwsgi.h" extern struct uwsgi_server uwsgi; void uwsgi_opt_pcre_jit(char *opt, char *value, void *foobar) { #if defined(PCRE_STUDY_JIT_COMPILE) && defined(PCRE_CONFIG_JIT) int has_jit = 0, ret; ret = pcre_config(PCRE_CONFIG_JIT, &has_jit); if (ret != 0 || has_jit != 1) return; uwsgi.pcre_jit = PCRE_STUDY_JIT_COMPILE; #elif defined(PCRE2_CONFIG_JIT) int has_jit = 0, ret; ret = pcre2_config(PCRE2_CONFIG_JIT, &has_jit); if (ret != 0) return; uwsgi.pcre_jit = has_jit; #endif } int uwsgi_regexp_build(char *re, uwsgi_pcre ** pattern) { #ifdef UWSGI_PCRE2 int errnbr; size_t erroff; *pattern = pcre2_compile((const unsigned char *) re, PCRE2_ZERO_TERMINATED, 0, &errnbr, &erroff, NULL); #else const char *errstr; int erroff; *pattern = uwsgi_malloc(sizeof(uwsgi_pcre)); (*pattern)->p = pcre_compile((const char *) re, 0, &errstr, &erroff, NULL); #endif #ifdef UWSGI_PCRE2 if (!(*pattern)) { uwsgi_log("pcre error: code %d at offset %d\n", errnbr, erroff); #else if (!((*pattern)->p)) { uwsgi_log("pcre error: %s at offset %d\n", errstr, erroff); #endif return -1; } #ifdef UWSGI_PCRE2 if (uwsgi.pcre_jit) { errnbr = pcre2_jit_compile(*pattern, PCRE2_JIT_COMPLETE); if (errnbr) { pcre2_code_free(*pattern); uwsgi_log("pcre JIT compile error code %d\n", errnbr); return -1; } #else int opt = uwsgi.pcre_jit; (*pattern)->extra = (pcre_extra *) pcre_study((const pcre *) (*pattern)->p, opt, &errstr); if ((*pattern)->extra == NULL && errstr != NULL) { pcre_free((*pattern)->p); free(*pattern); uwsgi_log("pcre (study) error: %s\n", errstr); return -1; #endif } return 0; } int uwsgi_regexp_match(uwsgi_pcre *pattern, const char *subject, int length) { #ifdef UWSGI_PCRE2 return uwsgi_regexp_match_ovec(pattern, subject, length, NULL, 0); #else return pcre_exec((const pcre *) pattern->p, (const pcre_extra *) pattern->extra, subject, length, 0, 0, NULL, 0); #endif } int uwsgi_regexp_match_ovec(uwsgi_pcre *pattern, const char *subject, int length, int *ovec, int n) { #ifdef UWSGI_PCRE2 int rc; int i; pcre2_match_data *match_data; size_t *pcre2_ovec; match_data = pcre2_match_data_create_from_pattern(pattern, NULL); rc = pcre2_match(pattern, (const unsigned char *)subject, length, 0, 0, match_data, NULL); /* * Quoting PCRE{,2} spec, "The first pair of integers, ovector[0] * and ovector[1], identify the portion of the subject string matched * by the entire pattern. The next pair is used for the first capturing * subpattern, and so on." Therefore, the ovector size is the number of * capturing subpatterns (INFO_CAPTURECOUNT), from uwsgi_regexp_ovector(), * as matching pairs, plus room for the first pair. */ if (n > 0) { // copy pcre2 output vector to uwsgi output vector pcre2_ovec = pcre2_get_ovector_pointer(match_data); for (i=0;i<(n+1)*2;i++) { ovec[i] = pcre2_ovec[i]; } #else if (n > 0) { return pcre_exec((const pcre *) pattern->p, (const pcre_extra *) pattern->extra, subject, length, 0, 0, ovec, PCRE_OVECTOR_BYTESIZE(n)); #endif } #ifdef UWSGI_PCRE2 pcre2_match_data_free(match_data); return rc; #else return pcre_exec((const pcre *) pattern->p, (const pcre_extra *) pattern->extra, subject, length, 0, 0, NULL, 0); #endif } int uwsgi_regexp_ovector(const uwsgi_pcre *pattern) { int n; #ifdef UWSGI_PCRE2 if (pcre2_pattern_info(pattern, PCRE2_INFO_CAPTURECOUNT, &n)) #else if (pcre_fullinfo((const pcre *) pattern->p, (const pcre_extra *) pattern->extra, PCRE_INFO_CAPTURECOUNT, &n)) #endif return 0; return n; } char *uwsgi_regexp_apply_ovec(char *src, int src_n, char *dst, int dst_n, int *ovector, int n) { int i; int dollar = 0; size_t dollars = n; for(i=0;iname, name)) { return urv; } old_urv = urv; urv = urv->next; } urv = uwsgi_calloc(sizeof(struct uwsgi_route_var)); urv->name = name; urv->name_len = strlen(name); urv->func = func; if (old_urv) { old_urv->next = urv; } else { uwsgi.route_vars = urv; } return urv; } struct uwsgi_route_var *uwsgi_get_route_var(char *name, uint16_t name_len) { struct uwsgi_route_var *urv = uwsgi.route_vars; while(urv) { if (!uwsgi_strncmp(urv->name, urv->name_len, name, name_len)) { return urv; } urv = urv->next; } return NULL; } struct uwsgi_buffer *uwsgi_routing_translate(struct wsgi_request *wsgi_req, struct uwsgi_route *ur, char *subject, uint16_t subject_len, char *data, size_t data_len) { char *pass1 = data; size_t pass1_len = data_len; if (ur->condition_ub[wsgi_req->async_id] && ur->ovn[wsgi_req->async_id] > 0) { pass1 = uwsgi_regexp_apply_ovec(ur->condition_ub[wsgi_req->async_id]->buf, ur->condition_ub[wsgi_req->async_id]->pos, data, data_len, ur->ovector[wsgi_req->async_id], ur->ovn[wsgi_req->async_id]); pass1_len = strlen(pass1); } // cannot fail else if (subject) { pass1 = uwsgi_regexp_apply_ovec(subject, subject_len, data, data_len, ur->ovector[wsgi_req->async_id], ur->ovn[wsgi_req->async_id]); pass1_len = strlen(pass1); } struct uwsgi_buffer *ub = uwsgi_buffer_new(pass1_len); size_t i; int status = 0; char *key = NULL; size_t keylen = 0; for(i=0;i 0 && key[keylen-1] == ']') { struct uwsgi_route_var *urv = uwsgi_get_route_var(key, bracket - key); if (urv) { need_free = urv->need_free; value = urv->func(wsgi_req, bracket + 1, keylen - (urv->name_len+2), &vallen); } else { value = uwsgi_get_var(wsgi_req, key, keylen, &vallen); } } else { value = uwsgi_get_var(wsgi_req, key, keylen, &vallen); } if (value) { if (uwsgi_buffer_append(ub, value, vallen)) { if (need_free) { free(value); } goto error; } if (need_free) { free(value); } } status = 0; key = NULL; keylen = 0; break; } keylen++; break; default: break; } } // fix the buffer if (status == 1) { if (uwsgi_buffer_append(ub, "$", 1)) goto error; } else if (status == 2) { if (uwsgi_buffer_append(ub, "${", 2)) goto error; if (keylen > 0) { if (uwsgi_buffer_append(ub, key, keylen)) goto error; } } // add the final NULL byte (to simplify plugin work) if (uwsgi_buffer_append(ub, "\0", 1)) goto error; // .. but came back of 1 position to avoid accounting it ub->pos--; if (pass1 != data) { free(pass1); } return ub; error: uwsgi_buffer_destroy(ub); return NULL; } static void uwsgi_routing_reset_memory(struct wsgi_request *wsgi_req, struct uwsgi_route *routes) { // free dynamic memory structures if (routes->if_func) { routes->ovn[wsgi_req->async_id] = 0; if (routes->ovector[wsgi_req->async_id]) { free(routes->ovector[wsgi_req->async_id]); routes->ovector[wsgi_req->async_id] = NULL; } if (routes->condition_ub[wsgi_req->async_id]) { uwsgi_buffer_destroy(routes->condition_ub[wsgi_req->async_id]); routes->condition_ub[wsgi_req->async_id] = NULL; } } } int uwsgi_apply_routes_do(struct uwsgi_route *routes, struct wsgi_request *wsgi_req, char *subject, uint16_t subject_len) { int n = -1; char *orig_subject = subject; uint16_t orig_subject_len = subject_len; uint32_t *r_goto = &wsgi_req->route_goto; uint32_t *r_pc = &wsgi_req->route_pc; if (routes == uwsgi.error_routes) { r_goto = &wsgi_req->error_route_goto; r_pc = &wsgi_req->error_route_pc; } else if (routes == uwsgi.response_routes) { r_goto = &wsgi_req->response_route_goto; r_pc = &wsgi_req->response_route_pc; } else if (routes == uwsgi.final_routes) { r_goto = &wsgi_req->final_route_goto; r_pc = &wsgi_req->final_route_pc; } while (routes) { if (routes->label) goto next; if (*r_goto > 0 && *r_pc < *r_goto) { goto next; } *r_goto = 0; if (!routes->if_func) { // could be a "run" if (!routes->subject) { n = 0; goto run; } if (!subject) { char **subject2 = (char **) (((char *) (wsgi_req)) + routes->subject); uint16_t *subject_len2 = (uint16_t *) (((char *) (wsgi_req)) + routes->subject_len); subject = *subject2 ; subject_len = *subject_len2; } n = uwsgi_regexp_match_ovec(routes->pattern, subject, subject_len, routes->ovector[wsgi_req->async_id], routes->ovn[wsgi_req->async_id]); } else { int ret = routes->if_func(wsgi_req, routes); // error if (ret < 0) { uwsgi_routing_reset_memory(wsgi_req, routes); return UWSGI_ROUTE_BREAK; } // true if (!routes->if_negate) { if (ret == 0) { uwsgi_routing_reset_memory(wsgi_req, routes); goto next; } n = ret; } else { if (ret > 0) { uwsgi_routing_reset_memory(wsgi_req, routes); goto next; } n = 1; } } run: if (n >= 0) { wsgi_req->is_routing = 1; int ret = routes->func(wsgi_req, routes); uwsgi_routing_reset_memory(wsgi_req, routes); wsgi_req->is_routing = 0; if (ret == UWSGI_ROUTE_BREAK) { uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].routed_requests++; return ret; } if (ret == UWSGI_ROUTE_CONTINUE) { return ret; } if (ret == -1) { return UWSGI_ROUTE_BREAK; } } next: subject = orig_subject; subject_len = orig_subject_len; routes = routes->next; if (routes) *r_pc = *r_pc+1; } return UWSGI_ROUTE_CONTINUE; } int uwsgi_apply_routes(struct wsgi_request *wsgi_req) { if (!uwsgi.routes) return UWSGI_ROUTE_CONTINUE; // avoid loops if (wsgi_req->is_routing) return UWSGI_ROUTE_CONTINUE; if (uwsgi_parse_vars(wsgi_req)) { return UWSGI_ROUTE_BREAK; } // in case of static files serving previous rules could be applied if (wsgi_req->routes_applied) { return UWSGI_ROUTE_CONTINUE; } return uwsgi_apply_routes_do(uwsgi.routes, wsgi_req, NULL, 0); } void uwsgi_apply_final_routes(struct wsgi_request *wsgi_req) { if (!uwsgi.final_routes) return; // avoid loops if (wsgi_req->is_routing) return; wsgi_req->is_final_routing = 1; uwsgi_apply_routes_do(uwsgi.final_routes, wsgi_req, NULL, 0); } int uwsgi_apply_error_routes(struct wsgi_request *wsgi_req) { if (!uwsgi.error_routes) return 0; // do not forget to check it !!! if (wsgi_req->is_error_routing) return 0; wsgi_req->is_error_routing = 1; return uwsgi_apply_routes_do(uwsgi.error_routes, wsgi_req, NULL, 0); } int uwsgi_apply_response_routes(struct wsgi_request *wsgi_req) { if (!uwsgi.response_routes) return 0; if (wsgi_req->response_routes_applied) return 0; // do not forget to check it !!! if (wsgi_req->is_response_routing) return 0; wsgi_req->is_response_routing = 1; int ret = uwsgi_apply_routes_do(uwsgi.response_routes, wsgi_req, NULL, 0); wsgi_req->response_routes_applied = 1; return ret; } static void *uwsgi_route_get_condition_func(char *name) { struct uwsgi_route_condition *urc = uwsgi.route_conditions; while(urc) { if (!strcmp(urc->name, name)) { return urc->func; } urc = urc->next; } return NULL; } static int uwsgi_route_condition_status(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { if (wsgi_req->status == ur->if_status) { return 1; } return 0; } void uwsgi_opt_add_route(char *opt, char *value, void *foobar) { char *space = NULL; char *command = NULL; struct uwsgi_route *old_ur = NULL, *ur = uwsgi.routes; if (!uwsgi_starts_with(opt, strlen(opt), "final", 5)) { ur = uwsgi.final_routes; } else if (!uwsgi_starts_with(opt, strlen(opt), "error", 5)) { ur = uwsgi.error_routes; } else if (!uwsgi_starts_with(opt, strlen(opt), "response", 8)) { ur = uwsgi.response_routes; } uint64_t pos = 0; while(ur) { old_ur = ur; ur = ur->next; pos++; } ur = uwsgi_calloc(sizeof(struct uwsgi_route)); if (old_ur) { old_ur->next = ur; } else { if (!uwsgi_starts_with(opt, strlen(opt), "final", 5)) { uwsgi.final_routes = ur; } else if (!uwsgi_starts_with(opt, strlen(opt), "error", 5)) { uwsgi.error_routes = ur; } else if (!uwsgi_starts_with(opt, strlen(opt), "response", 8)) { uwsgi.response_routes = ur; } else { uwsgi.routes = ur; } } ur->pos = pos; // is it a label ? if (foobar == NULL) { ur->label = value; ur->label_len = strlen(value); return; } ur->orig_route = uwsgi_str(value); if (!strcmp(foobar, "run")) { command = ur->orig_route; goto done; } space = strchr(ur->orig_route, ' '); if (!space) { uwsgi_log("invalid route syntax\n"); exit(1); } *space = 0; if (!strcmp(foobar, "if") || !strcmp(foobar, "if-not")) { char *colon = strchr(ur->orig_route, ':'); if (!colon) { uwsgi_log("invalid route condition syntax\n"); exit(1); } *colon = 0; if (!strcmp(foobar, "if-not")) { ur->if_negate = 1; } foobar = colon+1; ur->if_func = uwsgi_route_get_condition_func(ur->orig_route); if (!ur->if_func) { uwsgi_log("unable to find \"%s\" route condition\n", ur->orig_route); exit(1); } } else if (!strcmp(foobar, "status")) { ur->if_status = atoi(ur->orig_route); foobar = ur->orig_route; ur->if_func = uwsgi_route_condition_status; } else if (!strcmp(foobar, "http_host")) { ur->subject = offsetof(struct wsgi_request, host); ur->subject_len = offsetof(struct wsgi_request, host_len); } else if (!strcmp(foobar, "request_uri")) { ur->subject = offsetof(struct wsgi_request, uri); ur->subject_len = offsetof(struct wsgi_request, uri_len); } else if (!strcmp(foobar, "query_string")) { ur->subject = offsetof(struct wsgi_request, query_string); ur->subject_len = offsetof(struct wsgi_request, query_string_len); } else if (!strcmp(foobar, "remote_addr")) { ur->subject = offsetof(struct wsgi_request, remote_addr); ur->subject_len = offsetof(struct wsgi_request, remote_addr_len); } else if (!strcmp(foobar, "user_agent")) { ur->subject = offsetof(struct wsgi_request, user_agent); ur->subject_len = offsetof(struct wsgi_request, user_agent_len); } else if (!strcmp(foobar, "referer")) { ur->subject = offsetof(struct wsgi_request, referer); ur->subject_len = offsetof(struct wsgi_request, referer_len); } else if (!strcmp(foobar, "remote_user")) { ur->subject = offsetof(struct wsgi_request, remote_user); ur->subject_len = offsetof(struct wsgi_request, remote_user_len); } else { ur->subject = offsetof(struct wsgi_request, path_info); ur->subject_len = offsetof(struct wsgi_request, path_info_len); } ur->subject_str = foobar; ur->subject_str_len = strlen(ur->subject_str); ur->regexp = ur->orig_route; command = space + 1; done: ur->action = uwsgi_str(command); char *colon = strchr(command, ':'); if (!colon) { uwsgi_log("invalid route syntax\n"); exit(1); } *colon = 0; struct uwsgi_router *r = uwsgi.routers; while (r) { if (!strcmp(r->name, command)) { if (r->func(ur, colon + 1) == 0) { return; } break; } r = r->next; } uwsgi_log("unable to register route \"%s\"\n", value); exit(1); } void uwsgi_fixup_routes(struct uwsgi_route *ur) { while(ur) { // prepare the main pointers ur->ovn = uwsgi_calloc(sizeof(int) * uwsgi.cores); ur->ovector = uwsgi_calloc(sizeof(int *) * uwsgi.cores); ur->condition_ub = uwsgi_calloc( sizeof(struct uwsgi_buffer *) * uwsgi.cores); // fill them if needed... (this is an optimization for route with a static subject) if (ur->subject && ur->subject_len) { if (uwsgi_regexp_build(ur->orig_route, &ur->pattern)) { exit(1); } int i; for(i=0;iovn[i] = uwsgi_regexp_ovector(ur->pattern); if (ur->ovn[i] > 0) { ur->ovector[i] = uwsgi_calloc(sizeof(int) * PCRE_OVECTOR_BYTESIZE(ur->ovn[i])); } } } ur = ur->next; } } int uwsgi_route_api_func(struct wsgi_request *wsgi_req, char *router, char *args) { struct uwsgi_route *ur = NULL; struct uwsgi_router *r = uwsgi.routers; while(r) { if (!strcmp(router, r->name)) { goto found; } r = r->next; } free(args); return -1; found: ur = uwsgi_calloc(sizeof(struct uwsgi_route)); // initialize the virtual route if (r->func(ur, args)) { free(ur); free(args); return -1; } // call it int ret = ur->func(wsgi_req, ur); if (ur->free) { ur->free(ur); } free(ur); free(args); return ret; } // continue/last route static int uwsgi_router_continue_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) { return UWSGI_ROUTE_CONTINUE; } static int uwsgi_router_continue(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_continue_func; return 0; } // break route static int uwsgi_router_break_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) { if (route->data_len >= 3) { if (uwsgi_response_prepare_headers(wsgi_req, route->data, route->data_len)) goto end; if (uwsgi_response_add_connection_close(wsgi_req)) goto end; if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) goto end; // no need to check for return value uwsgi_response_write_headers_do(wsgi_req); } end: return UWSGI_ROUTE_BREAK; } static int uwsgi_router_break(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_break_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } static int uwsgi_router_return_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) { if (route->data_len < 3) return UWSGI_ROUTE_BREAK; uint16_t status_msg_len = 0; const char *status_msg = uwsgi_http_status_msg(route->data, &status_msg_len); if (!status_msg) return UWSGI_ROUTE_BREAK; char *buf = uwsgi_concat3n(route->data, route->data_len, " ", 1, (char *) status_msg, status_msg_len); if (uwsgi_response_prepare_headers(wsgi_req, buf, route->data_len + 1 + status_msg_len)) goto end; if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) goto end; if (uwsgi_response_add_content_length(wsgi_req, status_msg_len)) goto end; uwsgi_response_write_body_do(wsgi_req, (char *) status_msg, status_msg_len); end: free(buf); return UWSGI_ROUTE_BREAK; } static int uwsgi_router_return(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_return_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } // simple math router static int uwsgi_router_simple_math_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); uint16_t var_vallen = 0; char *var_value = uwsgi_get_var(wsgi_req, ur->data, ur->data_len, &var_vallen); if (!var_value) return UWSGI_ROUTE_BREAK; int64_t base_value = uwsgi_str_num(var_value, var_vallen); int64_t value = 1; if (ur->data2_len) { struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data2, ur->data2_len); if (!ub) return UWSGI_ROUTE_BREAK; value = uwsgi_str_num(ub->buf, ub->pos); uwsgi_buffer_destroy(ub); } char out[sizeof(UMAX64_STR)+1]; int64_t total = 0; switch(ur->custom) { // - case 1: total = base_value - value; break; // * case 2: total = base_value * value; break; // / case 3: if (value == 0) total = 0; else { total = base_value/value; } break; default: total = base_value + value; break; } int ret = uwsgi_long2str2n(total, out, sizeof(UMAX64_STR)+1); if (ret <= 0) return UWSGI_ROUTE_BREAK; if (!uwsgi_req_append(wsgi_req, ur->data, ur->data_len, out, ret)) { return UWSGI_ROUTE_BREAK; } return UWSGI_ROUTE_NEXT; } static int uwsgi_router_simple_math_plus(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_simple_math_func; char *comma = strchr(arg, ','); if (comma) { ur->data = arg; ur->data_len = comma - arg; ur->data2 = comma+1; ur->data2_len = strlen(ur->data); } else { ur->data = arg; ur->data_len = strlen(arg); } return 0; } static int uwsgi_router_simple_math_minus(struct uwsgi_route *ur, char *arg) { ur->custom = 1; return uwsgi_router_simple_math_plus(ur, arg); } static int uwsgi_router_simple_math_multiply(struct uwsgi_route *ur, char *arg) { ur->custom = 2; return uwsgi_router_simple_math_plus(ur, arg); } static int uwsgi_router_simple_math_divide(struct uwsgi_route *ur, char *arg) { ur->custom = 2; return uwsgi_router_simple_math_plus(ur, arg); } // harakiri router static int uwsgi_router_harakiri_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) { if (route->custom > 0) { set_user_harakiri(route->custom); } return UWSGI_ROUTE_NEXT; } static int uwsgi_router_harakiri(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_harakiri_func; ur->custom = atoi(arg); return 0; } // flush response static int transform_flush(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) { // avoid loops !!! if (ut->chunk->pos == 0) return 0; wsgi_req->transformed_chunk = ut->chunk->buf; wsgi_req->transformed_chunk_len = ut->chunk->pos; int ret = uwsgi_response_write_body_do(wsgi_req, ut->chunk->buf, ut->chunk->pos); wsgi_req->transformed_chunk = NULL; wsgi_req->transformed_chunk_len = 0; ut->flushed = 1; return ret; } static int uwsgi_router_flush_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) { struct uwsgi_transformation *ut = uwsgi_add_transformation(wsgi_req, transform_flush, NULL); ut->can_stream = 1; return UWSGI_ROUTE_NEXT; } static int uwsgi_router_flush(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_flush_func; return 0; } // fix content length static int transform_fixcl(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) { char buf[sizeof(UMAX64_STR)+1]; int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%llu", (unsigned long long) ut->chunk->pos); if (ret <= 0 || ret >= (int) (sizeof(UMAX64_STR)+1)) { wsgi_req->write_errors++; return -1; } // do not check for errors !!! uwsgi_response_add_header(wsgi_req, "Content-Length", 14, buf, ret); return 0; } static int uwsgi_router_fixcl_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) { uwsgi_add_transformation(wsgi_req, transform_fixcl, NULL); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_fixcl(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_fixcl_func; return 0; } // force content length static int transform_forcecl(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) { char buf[sizeof(UMAX64_STR)+1]; int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%llu", (unsigned long long) ut->chunk->pos); if (ret <= 0 || ret >= (int) (sizeof(UMAX64_STR)+1)) { wsgi_req->write_errors++; return -1; } // do not check for errors !!! uwsgi_response_add_header_force(wsgi_req, "Content-Length", 14, buf, ret); return 0; } static int uwsgi_router_forcecl_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) { uwsgi_add_transformation(wsgi_req, transform_forcecl, NULL); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_forcecl(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_forcecl_func; return 0; } // log route static int uwsgi_router_log_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; uwsgi_log("%.*s\n", ub->pos, ub->buf); uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_log(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_log_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } // do not log !!! static int uwsgi_router_donotlog_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { wsgi_req->do_not_log = 1; return UWSGI_ROUTE_NEXT; } static int uwsgi_router_donotlog(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_donotlog_func; return 0; } // do not offload !!! static int uwsgi_router_donotoffload_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { wsgi_req->socket->can_offload = 0; return UWSGI_ROUTE_NEXT; } static int uwsgi_router_donotoffload(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_donotoffload_func; return 0; } // logvar route static int uwsgi_router_logvar_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data2, ur->data2_len); if (!ub) return UWSGI_ROUTE_BREAK; uwsgi_logvar_add(wsgi_req, ur->data, ur->data_len, ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_logvar(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_logvar_func; char *equal = strchr(arg, '='); if (!equal) { uwsgi_log("invalid logvar syntax, must be key=value\n"); exit(1); } ur->data = arg; ur->data_len = equal-arg; ur->data2 = equal+1; ur->data2_len = strlen(ur->data2); return 0; } // goto route static int uwsgi_router_goto_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { // build the label (if needed) char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; uint32_t *r_goto = &wsgi_req->route_goto; uint32_t *r_pc = &wsgi_req->route_pc; // find the label struct uwsgi_route *routes = uwsgi.routes; if (wsgi_req->is_error_routing) { routes = uwsgi.error_routes; r_goto = &wsgi_req->error_route_goto; r_pc = &wsgi_req->error_route_pc; } else if (wsgi_req->is_final_routing) { routes = uwsgi.final_routes; r_goto = &wsgi_req->final_route_goto; r_pc = &wsgi_req->final_route_pc; } else if (wsgi_req->is_response_routing) { routes = uwsgi.response_routes; r_goto = &wsgi_req->response_route_goto; r_pc = &wsgi_req->response_route_pc; } while(routes) { if (!routes->label) goto next; if (!uwsgi_strncmp(routes->label, routes->label_len, ub->buf, ub->pos)) { *r_goto = routes->pos; goto found; } next: routes = routes->next; } *r_goto = ur->custom; found: uwsgi_buffer_destroy(ub); if (*r_goto <= *r_pc) { *r_goto = 0; uwsgi_log("[uwsgi-route] ERROR \"goto\" instruction can only jump forward (check your label !!!)\n"); return UWSGI_ROUTE_BREAK; } return UWSGI_ROUTE_NEXT; } static int uwsgi_router_goto(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_goto_func; ur->data = arg; ur->data_len = strlen(arg); ur->custom = atoi(arg); return 0; } // addvar route static int uwsgi_router_addvar_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data2, ur->data2_len); if (!ub) return UWSGI_ROUTE_BREAK; if (!uwsgi_req_append(wsgi_req, ur->data, ur->data_len, ub->buf, ub->pos)) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_addvar(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_addvar_func; char *equal = strchr(arg, '='); if (!equal) { uwsgi_log("[uwsgi-route] invalid addvar syntax, must be KEY=VAL\n"); exit(1); } ur->data = arg; ur->data_len = equal-arg; ur->data2 = equal+1; ur->data2_len = strlen(ur->data2); return 0; } // addheader route static int uwsgi_router_addheader_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; uwsgi_additional_header_add(wsgi_req, ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_addheader(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_addheader_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } // remheader route static int uwsgi_router_remheader_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; uwsgi_remove_header(wsgi_req, ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_remheader(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_remheader_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } // clearheaders route static int uwsgi_router_clearheaders_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; if (uwsgi_response_prepare_headers(wsgi_req, ub->buf, ub->pos)) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_clearheaders(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_clearheaders_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } // disable headers static int uwsgi_router_disableheaders_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { wsgi_req->headers_sent = 1; return UWSGI_ROUTE_NEXT; } static int uwsgi_router_disableheaders(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_disableheaders_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } // signal route static int uwsgi_router_signal_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) { uwsgi_signal_send(uwsgi.signal_socket, route->custom); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_signal(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_signal_func; ur->custom = atoi(arg); return 0; } // chdir route static int uwsgi_router_chdir_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; if (chdir(ub->buf)) { uwsgi_req_error("uwsgi_router_chdir_func()/chdir()"); uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_chdir(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_chdir_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } // setapp route static int uwsgi_router_setapp_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; char *ptr = uwsgi_req_append(wsgi_req, "UWSGI_APPID", 11, ub->buf, ub->pos); if (!ptr) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } wsgi_req->appid = ptr; wsgi_req->appid_len = ub->pos; uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_setapp(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_setapp_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } // setscriptname route static int uwsgi_router_setscriptname_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; char *ptr = uwsgi_req_append(wsgi_req, "SCRIPT_NAME", 11, ub->buf, ub->pos); if (!ptr) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } wsgi_req->script_name = ptr; wsgi_req->script_name_len = ub->pos; uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_setscriptname(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_setscriptname_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } // setmethod route static int uwsgi_router_setmethod_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; char *ptr = uwsgi_req_append(wsgi_req, "REQUEST_METHOD", 14, ub->buf, ub->pos); if (!ptr) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } wsgi_req->method = ptr; wsgi_req->method_len = ub->pos; uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_setmethod(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_setmethod_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } // seturi route static int uwsgi_router_seturi_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; char *ptr = uwsgi_req_append(wsgi_req, "REQUEST_URI", 11, ub->buf, ub->pos); if (!ptr) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } wsgi_req->uri = ptr; wsgi_req->uri_len = ub->pos; uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_seturi(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_seturi_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } // setremoteaddr route static int uwsgi_router_setremoteaddr_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; char *ptr = uwsgi_req_append(wsgi_req, "REMOTE_ADDR", 11, ub->buf, ub->pos); if (!ptr) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } wsgi_req->remote_addr = ptr; wsgi_req->remote_addr_len = ub->pos; uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_setremoteaddr(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_setremoteaddr_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } // setdocroot route static int uwsgi_router_setdocroot_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; char *ptr = uwsgi_req_append(wsgi_req, "DOCUMENT_ROOT", 13, ub->buf, ub->pos); if (!ptr) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } wsgi_req->document_root = ptr; wsgi_req->document_root_len = ub->pos; uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_setdocroot(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_setdocroot_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } // setpathinfo route static int uwsgi_router_setpathinfo_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; char *ptr = uwsgi_req_append(wsgi_req, "PATH_INFO", 9, ub->buf, ub->pos); if (!ptr) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } wsgi_req->path_info = ptr; wsgi_req->path_info_len = ub->pos; uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_setpathinfo(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_setpathinfo_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } // fixpathinfo route static int uwsgi_router_fixpathinfo_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { if (wsgi_req->script_name_len == 0) return UWSGI_ROUTE_NEXT; char *ptr = uwsgi_req_append(wsgi_req, "PATH_INFO", 9, wsgi_req->path_info+wsgi_req->script_name_len, wsgi_req->path_info_len - wsgi_req->script_name_len); if (!ptr) { return UWSGI_ROUTE_BREAK; } wsgi_req->path_info = wsgi_req->path_info+wsgi_req->script_name_len; wsgi_req->path_info_len = wsgi_req->path_info_len - wsgi_req->script_name_len; return UWSGI_ROUTE_NEXT; } static int uwsgi_router_fixpathinfo(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_fixpathinfo_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } // setscheme route static int uwsgi_router_setscheme_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; char *ptr = uwsgi_req_append(wsgi_req, "UWSGI_SCHEME", 12, ub->buf, ub->pos); if (!ptr) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } wsgi_req->scheme = ptr; wsgi_req->scheme_len = ub->pos; uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_setscheme(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_setscheme_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } // setmodifiers static int uwsgi_router_setmodifier1_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { wsgi_req->uh->modifier1 = ur->custom; return UWSGI_ROUTE_NEXT; } static int uwsgi_router_setmodifier1(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_setmodifier1_func; ur->custom = atoi(arg); return 0; } static int uwsgi_router_setmodifier2_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { wsgi_req->uh->modifier2 = ur->custom; return UWSGI_ROUTE_NEXT; } static int uwsgi_router_setmodifier2(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_setmodifier2_func; ur->custom = atoi(arg); return 0; } // setuser route static int uwsgi_router_setuser_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; uint16_t user_len = ub->pos; // stop at the first colon (useful for various tricks) char *colon = memchr(ub->buf, ':', ub->pos); if (colon) { user_len = colon - ub->buf; } char *ptr = uwsgi_req_append(wsgi_req, "REMOTE_USER", 11, ub->buf, user_len); if (!ptr) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } wsgi_req->remote_user = ptr; wsgi_req->remote_user_len = ub->pos; uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_setuser(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_setuser_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } // sethome route static int uwsgi_router_sethome_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; char *ptr = uwsgi_req_append(wsgi_req, "UWSGI_HOME", 10, ub->buf, ub->pos); if (!ptr) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } wsgi_req->home = ptr; wsgi_req->home_len = ub->pos; uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_sethome(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_sethome_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } // setfile route static int uwsgi_router_setfile_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; char *ptr = uwsgi_req_append(wsgi_req, "UWSGI_HOME", 10, ub->buf, ub->pos); if (!ptr) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } wsgi_req->file = ptr; wsgi_req->file_len = ub->pos; wsgi_req->dynamic = 1; uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_setfile(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_setfile_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } // setprocname route static int uwsgi_router_setprocname_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; uwsgi_set_processname(ub->buf); uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_setprocname(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_setprocname_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } // alarm route static int uwsgi_router_alarm_func(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub_alarm = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub_alarm) return UWSGI_ROUTE_BREAK; struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data2, ur->data2_len); if (!ub) { uwsgi_buffer_destroy(ub_alarm); return UWSGI_ROUTE_BREAK; } uwsgi_alarm_trigger(ub_alarm->buf, ub->buf, ub->pos); uwsgi_buffer_destroy(ub_alarm); uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_alarm(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_alarm_func; char *space = strchr(arg, ' '); if (!space) { return -1; } *space = 0; ur->data = arg; ur->data_len = strlen(arg); ur->data2 = space+1; ur->data2_len = strlen(ur->data2); return 0; } // send route static int uwsgi_router_send_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) { char **subject = (char **) (((char *)(wsgi_req))+route->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+route->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, route, *subject, *subject_len, route->data, route->data_len); if (!ub) { return UWSGI_ROUTE_BREAK; } if (route->custom) { if (uwsgi_buffer_append(ub, "\r\n", 2)) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } } uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_send(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_send_func; ur->data = arg; ur->data_len = strlen(arg); return 0; } static int uwsgi_router_send_crnl(struct uwsgi_route *ur, char *arg) { uwsgi_router_send(ur, arg); ur->custom = 1; return 0; } static int uwsgi_route_condition_exists(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len); if (!ub) return -1; if (uwsgi_file_exists(ub->buf)) { uwsgi_buffer_destroy(ub); return 1; } uwsgi_buffer_destroy(ub); return 0; } static int uwsgi_route_condition_isfile(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len); if (!ub) return -1; if (uwsgi_is_file(ub->buf)) { uwsgi_buffer_destroy(ub); return 1; } uwsgi_buffer_destroy(ub); return 0; } static int uwsgi_route_condition_regexp(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len); if (!semicolon) return 0; ur->condition_ub[wsgi_req->async_id] = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str); if (!ur->condition_ub[wsgi_req->async_id]) return -1; uwsgi_pcre *pattern; char *re = uwsgi_concat2n(semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str), "", 0); if (uwsgi_regexp_build(re, &pattern)) { free(re); return -1; } free(re); // a condition has no initialized vectors, let's create them ur->ovn[wsgi_req->async_id] = uwsgi_regexp_ovector(pattern); if (ur->ovn[wsgi_req->async_id] > 0) { ur->ovector[wsgi_req->async_id] = uwsgi_calloc(sizeof(int) * (3 * (ur->ovn[wsgi_req->async_id] + 1))); } if (uwsgi_regexp_match_ovec(pattern, ur->condition_ub[wsgi_req->async_id]->buf, ur->condition_ub[wsgi_req->async_id]->pos, ur->ovector[wsgi_req->async_id], ur->ovn[wsgi_req->async_id] ) >= 0) { #ifdef UWSGI_PCRE2 pcre2_code_free(pattern); #else pcre_free(pattern->p); #ifdef PCRE_STUDY_JIT_COMPILE pcre_free_study(pattern->extra); #else pcre_free(pattern->extra); #endif free(pattern); #endif return 1; } #ifdef UWSGI_PCRE2 pcre2_code_free(pattern); #else pcre_free(pattern->p); #ifdef PCRE_STUDY_JIT_COMPILE pcre_free_study(pattern->extra); #else pcre_free(pattern->extra); #endif free(pattern); #endif return 0; } static int uwsgi_route_condition_empty(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len); if (!ub) return -1; if (ub->pos == 0) { uwsgi_buffer_destroy(ub); return 1; } uwsgi_buffer_destroy(ub); return 0; } static int uwsgi_route_condition_equal(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len); if (!semicolon) return 0; struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str); if (!ub) return -1; struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str)); if (!ub2) { uwsgi_buffer_destroy(ub); return -1; } if(!uwsgi_strncmp(ub->buf, ub->pos, ub2->buf, ub2->pos)) { uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub2); return 1; } uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub2); return 0; } static int uwsgi_route_condition_higher(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len); if (!semicolon) return 0; struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str); if (!ub) return -1; struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str)); if (!ub2) { uwsgi_buffer_destroy(ub); return -1; } long num1 = strtol(ub->buf, NULL, 10); long num2 = strtol(ub2->buf, NULL, 10); if(num1 > num2) { uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub2); return 1; } uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub2); return 0; } static int uwsgi_route_condition_higherequal(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len); if (!semicolon) return 0; struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str); if (!ub) return -1; struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str)); if (!ub2) { uwsgi_buffer_destroy(ub); return -1; } long num1 = strtol(ub->buf, NULL, 10); long num2 = strtol(ub2->buf, NULL, 10); if(num1 >= num2) { uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub2); return 1; } uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub2); return 0; } static int uwsgi_route_condition_lower(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len); if (!semicolon) return 0; struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str); if (!ub) return -1; struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str)); if (!ub2) { uwsgi_buffer_destroy(ub); return -1; } long num1 = strtol(ub->buf, NULL, 10); long num2 = strtol(ub2->buf, NULL, 10); if(num1 < num2) { uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub2); return 1; } uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub2); return 0; } static int uwsgi_route_condition_lowerequal(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len); if (!semicolon) return 0; struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str); if (!ub) return -1; struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str)); if (!ub2) { uwsgi_buffer_destroy(ub); return -1; } long num1 = strtol(ub->buf, NULL, 10); long num2 = strtol(ub2->buf, NULL, 10); if(num1 <= num2) { uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub2); return 1; } uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub2); return 0; } #ifdef UWSGI_SSL static int uwsgi_route_condition_lord(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len); if (!ub) return -1; int ret = uwsgi_legion_i_am_the_lord(ub->buf); uwsgi_buffer_destroy(ub); return ret; } #endif static int uwsgi_route_condition_startswith(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len); if (!semicolon) return 0; struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str); if (!ub) return -1; struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str)); if (!ub2) { uwsgi_buffer_destroy(ub); return -1; } if(!uwsgi_starts_with(ub->buf, ub->pos, ub2->buf, ub2->pos)) { uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub2); return 1; } uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub2); return 0; } static int uwsgi_route_condition_ipv4in(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { #define IP4_LEN (sizeof("255.255.255.255")-1) #define IP4PFX_LEN (sizeof("255.255.255.255/32")-1) char ipbuf[IP4_LEN+1] = {}, maskbuf[IP4PFX_LEN+1] = {}; char *slash; int pfxlen = 32; in_addr_t ip, net, mask; char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len); if (!semicolon) return 0; struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str); if (!ub) return -1; struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str)); if (!ub2) { uwsgi_buffer_destroy(ub); return -1; } if (ub->pos > IP4_LEN || ub2->pos >= IP4PFX_LEN) { uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub2); return -1; } memcpy(ipbuf, ub->buf, ub->pos); memcpy(maskbuf, ub2->buf, ub2->pos); if ((slash = strchr(maskbuf, '/')) != NULL) { *slash++ = 0; pfxlen = atoi(slash); } uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub2); if ((ip = htonl(inet_addr(ipbuf))) == ~(in_addr_t)0) return 0; if ((net = htonl(inet_addr(maskbuf))) == ~(in_addr_t)0) return 0; if (pfxlen < 0 || pfxlen > 32) return 0; mask = (~0UL << (32 - pfxlen)) & ~0U; return ((ip & mask) == (net & mask)); #undef IP4_LEN #undef IP4PFX_LEN } static int uwsgi_route_condition_ipv6in(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { #define IP6_LEN (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")-1) #define IP6PFX_LEN (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128")-1) #define IP6_U32LEN (128 / 8 / 4) char ipbuf[IP6_LEN+1] = {}, maskbuf[IP6PFX_LEN+1] = {}; char *slash; int pfxlen = 128; uint32_t ip[IP6_U32LEN], net[IP6_U32LEN], mask[IP6_U32LEN] = {}; char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len); if (!semicolon) return 0; struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str); if (!ub) return -1; struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str)); if (!ub2) { uwsgi_buffer_destroy(ub); return -1; } if (ub->pos > IP6_LEN || ub2->pos >= IP6PFX_LEN) { uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub2); return -1; } memcpy(ipbuf, ub->buf, ub->pos); memcpy(maskbuf, ub2->buf, ub2->pos); if ((slash = strchr(maskbuf, '/')) != NULL) { *slash++ = 0; pfxlen = atoi(slash); } uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub2); if (inet_pton(AF_INET6, ipbuf, ip) != 1) return 0; if (inet_pton(AF_INET6, maskbuf, net) != 1) return 0; if (pfxlen < 0 || pfxlen > 128) return 0; memset(mask, 0xFF, sizeof(mask)); int i = (pfxlen / 32); switch (i) { case 0: mask[0] = 0; /* fallthrough */ case 1: mask[1] = 0; /* fallthrough */ case 2: mask[2] = 0; /* fallthrough */ case 3: mask[3] = 0; /* fallthrough */ } if (pfxlen % 32) mask[i] = htonl(~(uint32_t)0 << (32 - (pfxlen % 32))); for (i = 0; i < 4; i++) if ((ip[i] & mask[i]) != (net[i] & mask[i])) return 0; return 1; #undef IP6_LEN #undef IP6PFX_LEN #undef IP6_U32LEN } static int uwsgi_route_condition_contains(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len); if (!semicolon) return 0; struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str); if (!ub) return -1; struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str)); if (!ub2) { uwsgi_buffer_destroy(ub); return -1; } if(uwsgi_contains_n(ub->buf, ub->pos, ub2->buf, ub2->pos)) { uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub2); return 1; } uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub2); return 0; } static int uwsgi_route_condition_endswith(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char *semicolon = memchr(ur->subject_str, ';', ur->subject_str_len); if (!semicolon) return 0; struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, semicolon - ur->subject_str); if (!ub) return -1; struct uwsgi_buffer *ub2 = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, semicolon+1, ur->subject_str_len - ((semicolon+1) - ur->subject_str)); if (!ub2) { uwsgi_buffer_destroy(ub); return -1; } if (ub2->pos > ub->pos) goto zero; if(!uwsgi_strncmp(ub->buf + (ub->pos - ub2->pos), ub2->pos, ub2->buf, ub2->pos)) { uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub2); return 1; } zero: uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub2); return 0; } static int uwsgi_route_condition_isdir(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len); if (!ub) return -1; if (uwsgi_is_dir(ub->buf)) { uwsgi_buffer_destroy(ub); return 1; } uwsgi_buffer_destroy(ub); return 0; } static int uwsgi_route_condition_islink(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len); if (!ub) return -1; if (uwsgi_is_link(ub->buf)) { uwsgi_buffer_destroy(ub); return 1; } uwsgi_buffer_destroy(ub); return 0; } static int uwsgi_route_condition_isexec(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, ur->subject_str, ur->subject_str_len); if (!ub) return -1; if (!access(ub->buf, X_OK)) { uwsgi_buffer_destroy(ub); return 1; } uwsgi_buffer_destroy(ub); return 0; } static char *uwsgi_route_var_uwsgi(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) { char *ret = NULL; if (!uwsgi_strncmp(key, keylen, "wid", 3)) { ret = uwsgi_num2str(uwsgi.mywid); *vallen = strlen(ret); } else if (!uwsgi_strncmp(key, keylen, "pid", 3)) { ret = uwsgi_num2str(uwsgi.mypid); *vallen = strlen(ret); } else if (!uwsgi_strncmp(key, keylen, "uuid", 4)) { ret = uwsgi_malloc(37); uwsgi_uuid(ret); *vallen = 36; } else if (!uwsgi_strncmp(key, keylen, "status", 6)) { ret = uwsgi_num2str(wsgi_req->status); *vallen = strlen(ret); } else if (!uwsgi_strncmp(key, keylen, "rtime", 5)) { ret = uwsgi_num2str(wsgi_req->end_of_request - wsgi_req->start_of_request); *vallen = strlen(ret); } else if (!uwsgi_strncmp(key, keylen, "lq", 2)) { ret = uwsgi_num2str(uwsgi.shared->backlog); *vallen = strlen(ret); } else if (!uwsgi_strncmp(key, keylen, "rsize", 5)) { ret = uwsgi_64bit2str(wsgi_req->response_size); *vallen = strlen(ret); } else if (!uwsgi_strncmp(key, keylen, "sor", 3)) { ret = uwsgi_64bit2str(wsgi_req->start_of_request); *vallen = strlen(ret); } return ret; } static char *uwsgi_route_var_mime(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) { char *ret = NULL; uint16_t var_vallen = 0; char *var_value = uwsgi_get_var(wsgi_req, key, keylen, &var_vallen); if (var_value) { size_t mime_type_len = 0; ret = uwsgi_get_mime_type(var_value, var_vallen, &mime_type_len); if (ret) *vallen = mime_type_len; } return ret; } static char *uwsgi_route_var_httptime(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) { // 30+1 char *ht = uwsgi_calloc(31); size_t t = uwsgi_str_num(key, keylen); int len = uwsgi_http_date(uwsgi_now() + t, ht); if (len == 0) { free(ht); return NULL; } *vallen = len; return ht; } static char *uwsgi_route_var_time(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) { char *ret = NULL; if (!uwsgi_strncmp(key, keylen, "unix", 4)) { ret = uwsgi_num2str(uwsgi_now()); *vallen = strlen(ret); } else if (!uwsgi_strncmp(key, keylen, "micros", 6)) { ret = uwsgi_64bit2str(uwsgi_micros()); *vallen = strlen(ret); } return ret; } static char *uwsgi_route_var_base64(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) { char *ret = NULL; uint16_t var_vallen = 0; char *var_value = uwsgi_get_var(wsgi_req, key, keylen, &var_vallen); if (var_value) { size_t b64_len = 0; ret = uwsgi_base64_encode(var_value, var_vallen, &b64_len); *vallen = b64_len; } return ret; } static char *uwsgi_route_var_hex(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) { char *ret = NULL; uint16_t var_vallen = 0; char *var_value = uwsgi_get_var(wsgi_req, key, keylen, &var_vallen); if (var_value) { ret = uwsgi_str_to_hex(var_value, var_vallen); *vallen = var_vallen*2; } return ret; } // register embedded routers void uwsgi_register_embedded_routers() { uwsgi_register_router("continue", uwsgi_router_continue); uwsgi_register_router("last", uwsgi_router_continue); uwsgi_register_router("break", uwsgi_router_break); uwsgi_register_router("return", uwsgi_router_return); uwsgi_register_router("break-with-status", uwsgi_router_return); uwsgi_register_router("log", uwsgi_router_log); uwsgi_register_router("donotlog", uwsgi_router_donotlog); uwsgi_register_router("donotoffload", uwsgi_router_donotoffload); uwsgi_register_router("logvar", uwsgi_router_logvar); uwsgi_register_router("goto", uwsgi_router_goto); uwsgi_register_router("addvar", uwsgi_router_addvar); uwsgi_register_router("addheader", uwsgi_router_addheader); uwsgi_register_router("delheader", uwsgi_router_remheader); uwsgi_register_router("remheader", uwsgi_router_remheader); uwsgi_register_router("clearheaders", uwsgi_router_clearheaders); uwsgi_register_router("resetheaders", uwsgi_router_clearheaders); uwsgi_register_router("disableheaders", uwsgi_router_disableheaders); uwsgi_register_router("signal", uwsgi_router_signal); uwsgi_register_router("send", uwsgi_router_send); uwsgi_register_router("send-crnl", uwsgi_router_send_crnl); uwsgi_register_router("chdir", uwsgi_router_chdir); uwsgi_register_router("setapp", uwsgi_router_setapp); uwsgi_register_router("setuser", uwsgi_router_setuser); uwsgi_register_router("sethome", uwsgi_router_sethome); uwsgi_register_router("setfile", uwsgi_router_setfile); uwsgi_register_router("setscriptname", uwsgi_router_setscriptname); uwsgi_register_router("setmethod", uwsgi_router_setmethod); uwsgi_register_router("seturi", uwsgi_router_seturi); uwsgi_register_router("setremoteaddr", uwsgi_router_setremoteaddr); uwsgi_register_router("setpathinfo", uwsgi_router_setpathinfo); uwsgi_register_router("fixpathinfo", uwsgi_router_fixpathinfo); uwsgi_register_router("setdocroot", uwsgi_router_setdocroot); uwsgi_register_router("setscheme", uwsgi_router_setscheme); uwsgi_register_router("setprocname", uwsgi_router_setprocname); uwsgi_register_router("alarm", uwsgi_router_alarm); uwsgi_register_router("setmodifier1", uwsgi_router_setmodifier1); uwsgi_register_router("setmodifier2", uwsgi_router_setmodifier2); uwsgi_register_router("+", uwsgi_router_simple_math_plus); uwsgi_register_router("-", uwsgi_router_simple_math_minus); uwsgi_register_router("*", uwsgi_router_simple_math_multiply); uwsgi_register_router("/", uwsgi_router_simple_math_divide); uwsgi_register_router("flush", uwsgi_router_flush); uwsgi_register_router("fixcl", uwsgi_router_fixcl); uwsgi_register_router("forcecl", uwsgi_router_forcecl); uwsgi_register_router("harakiri", uwsgi_router_harakiri); uwsgi_register_route_condition("exists", uwsgi_route_condition_exists); uwsgi_register_route_condition("isfile", uwsgi_route_condition_isfile); uwsgi_register_route_condition("isdir", uwsgi_route_condition_isdir); uwsgi_register_route_condition("islink", uwsgi_route_condition_islink); uwsgi_register_route_condition("isexec", uwsgi_route_condition_isexec); uwsgi_register_route_condition("equal", uwsgi_route_condition_equal); uwsgi_register_route_condition("isequal", uwsgi_route_condition_equal); uwsgi_register_route_condition("eq", uwsgi_route_condition_equal); uwsgi_register_route_condition("==", uwsgi_route_condition_equal); uwsgi_register_route_condition("startswith", uwsgi_route_condition_startswith); uwsgi_register_route_condition("endswith", uwsgi_route_condition_endswith); uwsgi_register_route_condition("regexp", uwsgi_route_condition_regexp); uwsgi_register_route_condition("re", uwsgi_route_condition_regexp); uwsgi_register_route_condition("ishigher", uwsgi_route_condition_higher); uwsgi_register_route_condition(">", uwsgi_route_condition_higher); uwsgi_register_route_condition("islower", uwsgi_route_condition_lower); uwsgi_register_route_condition("<", uwsgi_route_condition_lower); uwsgi_register_route_condition("ishigherequal", uwsgi_route_condition_higherequal); uwsgi_register_route_condition(">=", uwsgi_route_condition_higherequal); uwsgi_register_route_condition("islowerequal", uwsgi_route_condition_lowerequal); uwsgi_register_route_condition("<=", uwsgi_route_condition_lowerequal); uwsgi_register_route_condition("contains", uwsgi_route_condition_contains); uwsgi_register_route_condition("contain", uwsgi_route_condition_contains); uwsgi_register_route_condition("ipv4in", uwsgi_route_condition_ipv4in); uwsgi_register_route_condition("ipv6in", uwsgi_route_condition_ipv6in); #ifdef UWSGI_SSL uwsgi_register_route_condition("lord", uwsgi_route_condition_lord); #endif uwsgi_register_route_condition("empty", uwsgi_route_condition_empty); uwsgi_register_route_var("cookie", uwsgi_get_cookie); uwsgi_register_route_var("qs", uwsgi_get_qs); uwsgi_register_route_var("mime", uwsgi_route_var_mime); struct uwsgi_route_var *urv = uwsgi_register_route_var("uwsgi", uwsgi_route_var_uwsgi); urv->need_free = 1; urv = uwsgi_register_route_var("time", uwsgi_route_var_time); urv->need_free = 1; urv = uwsgi_register_route_var("httptime", uwsgi_route_var_httptime); urv->need_free = 1; urv = uwsgi_register_route_var("base64", uwsgi_route_var_base64); urv->need_free = 1; urv = uwsgi_register_route_var("hex", uwsgi_route_var_hex); urv->need_free = 1; } struct uwsgi_router *uwsgi_register_router(char *name, int (*func) (struct uwsgi_route *, char *)) { struct uwsgi_router *ur = uwsgi.routers; if (!ur) { uwsgi.routers = uwsgi_calloc(sizeof(struct uwsgi_router)); uwsgi.routers->name = name; uwsgi.routers->func = func; return uwsgi.routers; } while (ur) { if (!ur->next) { ur->next = uwsgi_calloc(sizeof(struct uwsgi_router)); ur->next->name = name; ur->next->func = func; return ur->next; } ur = ur->next; } return NULL; } struct uwsgi_route_condition *uwsgi_register_route_condition(char *name, int (*func) (struct wsgi_request *, struct uwsgi_route *)) { struct uwsgi_route_condition *old_urc = NULL,*urc = uwsgi.route_conditions; while(urc) { if (!strcmp(urc->name, name)) { return urc; } old_urc = urc; urc = urc->next; } urc = uwsgi_calloc(sizeof(struct uwsgi_route_condition)); urc->name = name; urc->func = func; if (old_urc) { old_urc->next = urc; } else { uwsgi.route_conditions = urc; } return urc; } void uwsgi_routing_dump() { struct uwsgi_string_list *usl = NULL; struct uwsgi_route *routes = uwsgi.routes; if (!routes) goto next; uwsgi_log("*** dumping internal routing table ***\n"); while(routes) { if (routes->label) { uwsgi_log("[rule: %llu] label: %s\n", (unsigned long long ) routes->pos, routes->label); } else if (!routes->subject_str && !routes->if_func) { uwsgi_log("[rule: %llu] action: %s\n", (unsigned long long ) routes->pos, routes->action); } else { uwsgi_log("[rule: %llu] subject: %s %s: %s%s action: %s\n", (unsigned long long ) routes->pos, routes->subject_str, routes->if_func ? "func" : "regexp", routes->if_negate ? "!" : "", routes->regexp, routes->action); } routes = routes->next; } uwsgi_log("*** end of the internal routing table ***\n"); next: routes = uwsgi.error_routes; if (!routes) goto next2; uwsgi_log("*** dumping internal error routing table ***\n"); while(routes) { if (routes->label) { uwsgi_log("[rule: %llu] label: %s\n", (unsigned long long ) routes->pos, routes->label); } else if (!routes->subject_str && !routes->if_func) { uwsgi_log("[rule: %llu] action: %s\n", (unsigned long long ) routes->pos, routes->action); } else { uwsgi_log("[rule: %llu] subject: %s %s: %s%s action: %s\n", (unsigned long long ) routes->pos, routes->subject_str, routes->if_func ? "func" : "regexp", routes->if_negate ? "!" : "", routes->regexp, routes->action); } routes = routes->next; } uwsgi_log("*** end of the internal error routing table ***\n"); next2: routes = uwsgi.response_routes; if (!routes) goto next3; uwsgi_log("*** dumping internal response routing table ***\n"); while(routes) { if (routes->label) { uwsgi_log("[rule: %llu] label: %s\n", (unsigned long long ) routes->pos, routes->label); } else if (!routes->subject_str && !routes->if_func) { uwsgi_log("[rule: %llu] action: %s\n", (unsigned long long ) routes->pos, routes->action); } else { uwsgi_log("[rule: %llu] subject: %s %s: %s%s action: %s\n", (unsigned long long ) routes->pos, routes->subject_str, routes->if_func ? "func" : "regexp", routes->if_negate ? "!" : "", routes->regexp, routes->action); } routes = routes->next; } uwsgi_log("*** end of the internal response routing table ***\n"); next3: routes = uwsgi.final_routes; if (!routes) goto next4; uwsgi_log("*** dumping internal final routing table ***\n"); while(routes) { if (routes->label) { uwsgi_log("[rule: %llu] label: %s\n", (unsigned long long ) routes->pos, routes->label); } else if (!routes->subject_str && !routes->if_func) { uwsgi_log("[rule: %llu] action: %s\n", (unsigned long long ) routes->pos, routes->action); } else { uwsgi_log("[rule: %llu] subject: %s %s: %s%s action: %s\n", (unsigned long long ) routes->pos, routes->subject_str, routes->if_func ? "func" : "regexp", routes->if_negate ? "!" : "", routes->regexp, routes->action); } routes = routes->next; } uwsgi_log("*** end of the internal final routing table ***\n"); next4: uwsgi_foreach(usl, uwsgi.collect_headers) { char *space = strchr(usl->value, ' '); if (!space) { uwsgi_log("invalid collect header syntax, must be
\n"); exit(1); } *space = 0; usl->custom = strlen(usl->value); *space = ' '; usl->custom_ptr = space+1; usl->custom2 = strlen(space+1); uwsgi_log("collecting header %.*s to var %s\n", usl->custom, usl->value, usl->custom_ptr); } uwsgi_foreach(usl, uwsgi.pull_headers) { char *space = strchr(usl->value, ' '); if (!space) { uwsgi_log("invalid pull header syntax, must be
\n"); exit(1); } *space = 0; usl->custom = strlen(usl->value); *space = ' '; usl->custom_ptr = space+1; usl->custom2 = strlen(space+1); uwsgi_log("pulling header %.*s to var %s\n", usl->custom, usl->value, usl->custom_ptr); } } #endif uwsgi-2.0.29/core/rpc.c000066400000000000000000000123571477626554400146560ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; int uwsgi_register_rpc(char *name, struct uwsgi_plugin *plugin, uint8_t args, void *func) { struct uwsgi_rpc *urpc; int ret = -1; if (uwsgi.mywid == 0 && uwsgi.workers[0].pid != uwsgi.mypid) { uwsgi_log("only the master and the workers can register RPC functions\n"); return -1; } if (strlen(name) >= UMAX8) { uwsgi_log("the supplied RPC name string is too long, max size is %d\n", UMAX8-1); return -1; } uwsgi_lock(uwsgi.rpc_table_lock); // first check if a function is already registered size_t i; for(i=0;irpc_count[uwsgi.mywid];i++) { int pos = (uwsgi.mywid * uwsgi.rpc_max) + i; urpc = &uwsgi.rpc_table[pos]; if (!strcmp(name, urpc->name)) { goto already; } } if (uwsgi.shared->rpc_count[uwsgi.mywid] < uwsgi.rpc_max) { int pos = (uwsgi.mywid * uwsgi.rpc_max) + uwsgi.shared->rpc_count[uwsgi.mywid]; urpc = &uwsgi.rpc_table[pos]; uwsgi.shared->rpc_count[uwsgi.mywid]++; already: memcpy(urpc->name, name, strlen(name)); urpc->plugin = plugin; urpc->args = args; urpc->func = func; urpc->shared = uwsgi.mywid == 0 ? 1 : 0; ret = 0; if (uwsgi.mywid == 0) { uwsgi_log("registered shared/inherited RPC function \"%s\"\n", name); } else { uwsgi_log("registered RPC function \"%s\" on worker %d\n", name, uwsgi.mywid); } } // implement cow if (uwsgi.mywid == 0) { int i; for(i=1;i<=uwsgi.numproc;i++) { uwsgi.shared->rpc_count[i] = uwsgi.shared->rpc_count[0]; int pos = (i * uwsgi.rpc_max); memcpy(&uwsgi.rpc_table[pos], uwsgi.rpc_table, sizeof(struct uwsgi_rpc) * uwsgi.rpc_max); } } uwsgi_unlock(uwsgi.rpc_table_lock); return ret; } uint64_t uwsgi_rpc(char *name, uint8_t argc, char *argv[], uint16_t argvs[], char **output) { struct uwsgi_rpc *urpc = NULL; uint64_t i; uint64_t ret = 0; int pos = (uwsgi.mywid * uwsgi.rpc_max); for (i = 0; i < uwsgi.shared->rpc_count[uwsgi.mywid]; i++) { if (uwsgi.rpc_table[pos + i].name[0] != 0) { if (!strcmp(uwsgi.rpc_table[pos + i].name, name)) { urpc = &uwsgi.rpc_table[pos + i]; break; } } } if (urpc) { if (urpc->plugin->rpc) { ret = urpc->plugin->rpc(urpc->func, argc, argv, argvs, output); } } return ret; } static void rpc_context_hook(char *key, uint16_t kl, char *value, uint16_t vl, void *data) { size_t *r = (size_t *) data; if (!uwsgi_strncmp(key, kl, "CONTENT_LENGTH", 14)) { *r = uwsgi_str_num(value, vl); } } char *uwsgi_do_rpc(char *node, char *func, uint8_t argc, char *argv[], uint16_t argvs[], uint64_t * len) { uint8_t i; uint16_t ulen; struct uwsgi_header *uh = NULL; char *buffer = NULL; *len = 0; if (node == NULL || !strcmp(node, "")) { // allocate the whole buffer if (!uwsgi.rpc_table) { uwsgi_log("local rpc subsystem is still not initialized !!!\n"); return NULL; } *len = uwsgi_rpc(func, argc, argv, argvs, &buffer); if (buffer) return buffer; return NULL; } // connect to node (async way) int fd = uwsgi_connect(node, 0, 1); if (fd < 0) return NULL; // wait for connection; int ret = uwsgi.wait_write_hook(fd, uwsgi.socket_timeout); if (ret <= 0) { close(fd); return NULL; } // prepare a uwsgi array size_t buffer_size = 2 + strlen(func); for (i = 0; i < argc; i++) { buffer_size += 2 + argvs[i]; } if (buffer_size > 0xffff) { uwsgi_log("RPC packet length overflow!!! Must be less than or equal to 65535, have %llu\n", buffer_size); return NULL; } // allocate the whole buffer buffer = uwsgi_malloc(4+buffer_size); // set the uwsgi header uh = (struct uwsgi_header *) buffer; uh->modifier1 = 173; uh->pktsize = (uint16_t) buffer_size; uh->modifier2 = 0; // add func to the array char *bufptr = buffer + 4; ulen = strlen(func); *bufptr++ = (uint8_t) (ulen & 0xff); *bufptr++ = (uint8_t) ((ulen >> 8) & 0xff); memcpy(bufptr, func, ulen); bufptr += ulen; for (i = 0; i < argc; i++) { ulen = argvs[i]; *bufptr++ = (uint8_t) (ulen & 0xff); *bufptr++ = (uint8_t) ((ulen >> 8) & 0xff); memcpy(bufptr, argv[i], ulen); bufptr += ulen; } // ok the request is ready, let's send it in non blocking way if (uwsgi_write_true_nb(fd, buffer, buffer_size+4, uwsgi.socket_timeout)) { goto error; } // ok time to wait for the response in non blocking way size_t rlen = buffer_size+4; uint8_t modifier2 = 0; if (uwsgi_read_with_realloc(fd, &buffer, &rlen, uwsgi.socket_timeout, NULL, &modifier2)) { goto error; } // 64bit response ? if (modifier2 == 5) { size_t content_len = 0; if (uwsgi_hooked_parse(buffer, rlen, rpc_context_hook, &content_len )) goto error; if (content_len > rlen) { char *tmp_buf = realloc(buffer, content_len); if (!tmp_buf) goto error; buffer = tmp_buf; } rlen = content_len; // read the raw value from the socket if (uwsgi_read_whole_true_nb(fd, buffer, rlen, uwsgi.socket_timeout)) { goto error; } } close(fd); *len = rlen; if (*len == 0) { goto error2; } return buffer; error: close(fd); error2: free(buffer); return NULL; } void uwsgi_rpc_init() { uwsgi.rpc_table = uwsgi_calloc_shared((sizeof(struct uwsgi_rpc) * uwsgi.rpc_max) * (uwsgi.numproc+1)); uwsgi.shared->rpc_count = uwsgi_calloc_shared(sizeof(uint64_t) * (uwsgi.numproc+1)); } uwsgi-2.0.29/core/sendfile.c000066400000000000000000000047731477626554400156660ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; // sendfile() abstraction ssize_t uwsgi_sendfile_do(int sockfd, int filefd, size_t pos, size_t len) { // for platform not supporting sendfile we need to rely on boring read/write // generally that platforms have very low memory, so use a 8k buffer char buf[8192]; if (uwsgi.disable_sendfile) goto no_sendfile; #if defined(__FreeBSD__) || defined(__DragonFly__) off_t sf_len = len; int sf_ret = sendfile(filefd, sockfd, pos, len, NULL, &sf_len, 0); if (sf_ret == 0 || (sf_ret == -1 && errno == EAGAIN)) return sf_len; return -1; #elif defined(__APPLE__) && !defined(NO_SENDFILE) off_t sf_len = len; int sf_ret = sendfile(filefd, sockfd, pos, &sf_len, NULL, 0); if (sf_ret == 0 || (sf_ret == -1 && errno == EAGAIN)) return sf_len; return -1; #elif defined(__linux__) || defined(__GNU_kFreeBSD__) off_t off = pos; return sendfile(sockfd, filefd, &off, len); #elif defined(__sun__) off_t off = pos; ssize_t wlen = sendfile(sockfd, filefd, &off, len); if (wlen < 0 && uwsgi_is_again()) { if (off - pos > 0) { return off-pos; } } return wlen; #endif no_sendfile: if (pos > 0) { if (lseek(filefd, pos, SEEK_SET) < 0) { uwsgi_error("uwsgi_sendfile_do()/seek()"); return -1; } } ssize_t rlen = read(filefd, buf, UMIN(len, 8192)); if (rlen <= 0) { uwsgi_error("uwsgi_sendfile_do()/read()"); return -1; } return write(sockfd, buf, rlen); } /* simple non blocking sendfile implementation (generally used as fallback) */ int uwsgi_simple_sendfile(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) { wsgi_req->write_pos = 0; for(;;) { int ret = wsgi_req->socket->proto_sendfile(wsgi_req, fd, pos, len); if (ret < 0) { if (!uwsgi.ignore_write_errors) { uwsgi_error("uwsgi_simple_sendfile()"); } wsgi_req->write_errors++; return -1; } if (ret == UWSGI_OK) { break; } ret = uwsgi_wait_write_req(wsgi_req); if (ret < 0) { wsgi_req->write_errors++; return -1; } if (ret == 0) { uwsgi_log("uwsgi_simple_sendfile() TIMEOUT !!!\n"); wsgi_req->write_errors++; return -1; } } return 0; } uwsgi-2.0.29/core/setup_utils.c000066400000000000000000000100141477626554400164360ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; void uwsgi_setup_systemd() { struct uwsgi_socket *uwsgi_sock = NULL; int i; char *listen_pid = getenv("LISTEN_PID"); if (listen_pid) { if (atoi(listen_pid) == (int) getpid()) { char *listen_fds = getenv("LISTEN_FDS"); if (listen_fds) { int systemd_fds = atoi(listen_fds); if (systemd_fds > 0) { uwsgi_log("- SystemD socket activation detected -\n"); for (i = 3; i < 3 + systemd_fds; i++) { uwsgi_sock = uwsgi_new_socket(NULL); uwsgi_add_socket_from_fd(uwsgi_sock, i); } uwsgi.skip_zero = 1; } unsetenv("LISTEN_PID"); unsetenv("LISTEN_FDS"); } } } } void uwsgi_setup_upstart() { struct uwsgi_socket *uwsgi_sock = NULL; char *upstart_events = getenv("UPSTART_EVENTS"); if (upstart_events && !strcmp(upstart_events, "socket")) { char *upstart_fds = getenv("UPSTART_FDS"); if (upstart_fds) { uwsgi_log("- Upstart socket bridge detected (job: %s) -\n", getenv("UPSTART_JOB")); uwsgi_sock = uwsgi_new_socket(NULL); uwsgi_add_socket_from_fd(uwsgi_sock, atoi(upstart_fds)); uwsgi.skip_zero = 1; } unsetenv("UPSTART_EVENTS"); unsetenv("UPSTART_FDS"); } } void uwsgi_setup_zerg() { struct uwsgi_socket *uwsgi_sock = NULL; int i; struct uwsgi_string_list *zn = uwsgi.zerg_node; while (zn) { if (uwsgi_zerg_attach(zn->value)) { if (!uwsgi.zerg_fallback) { exit(1); } } zn = zn->next; } if (uwsgi.zerg) { #ifdef UWSGI_DEBUG uwsgi_log("attaching zerg sockets...\n"); #endif int zerg_fd; i = 0; for (;;) { zerg_fd = uwsgi.zerg[i]; if (zerg_fd == -1) { break; } uwsgi_sock = uwsgi_new_socket(NULL); uwsgi_add_socket_from_fd(uwsgi_sock, zerg_fd); i++; } uwsgi_log("zerg sockets attached\n"); } } void uwsgi_setup_inherited_sockets() { int j; union uwsgi_sockaddr usa; union uwsgi_sockaddr_ptr gsa; struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { //a bit overengineering if (uwsgi_sock->name[0] != 0 && !uwsgi_sock->bound) { for (j = 3; j < (int) uwsgi.max_fd; j++) { uwsgi_add_socket_from_fd(uwsgi_sock, j); } } uwsgi_sock = uwsgi_sock->next; } //now close all the unbound fd for (j = 3; j < (int) uwsgi.max_fd; j++) { int useless = 1; if (uwsgi_fd_is_safe(j)) continue; if (uwsgi.has_emperor) { if (j == uwsgi.emperor_fd) continue; if (j == uwsgi.emperor_fd_config) continue; } if (uwsgi.shared->worker_log_pipe[0] > -1) { if (j == uwsgi.shared->worker_log_pipe[0]) continue; } if (uwsgi.shared->worker_log_pipe[1] > -1) { if (j == uwsgi.shared->worker_log_pipe[1]) continue; } if (uwsgi.shared->worker_req_log_pipe[0] > -1) { if (j == uwsgi.shared->worker_req_log_pipe[0]) continue; } if (uwsgi.shared->worker_req_log_pipe[1] > -1) { if (j == uwsgi.shared->worker_req_log_pipe[1]) continue; } if (uwsgi.original_log_fd > -1) { if (j == uwsgi.original_log_fd) continue; } struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets; int found = 0; while (ugs) { if (ugs->fd == j) { found = 1; break; } ugs = ugs->next; } if (found) continue; int y; found = 0; for (y = 0; y < ushared->gateways_cnt; y++) { if (ushared->gateways[y].internal_subscription_pipe[0] == j) { found = 1; break; } if (ushared->gateways[y].internal_subscription_pipe[1] == j) { found = 1; break; } } if (found) continue; socklen_t socket_type_len = sizeof(struct sockaddr_un); gsa.sa = (struct sockaddr *) &usa; if (!getsockname(j, gsa.sa, &socket_type_len)) { uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->fd == j && uwsgi_sock->bound) { useless = 0; break; } uwsgi_sock = uwsgi_sock->next; } if (useless) { uwsgi_sock = uwsgi.shared_sockets; while (uwsgi_sock) { if (uwsgi_sock->fd == j && uwsgi_sock->bound) { useless = 0; break; } uwsgi_sock = uwsgi_sock->next; } } } if (useless) { close(j); } } } uwsgi-2.0.29/core/sharedarea.c000066400000000000000000000310071477626554400161620ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; /* This is an high-performance memory area shared by all workers/cores/threads Contrary to the caching subsystem it is 1-copy (caching for non-c apps is 2-copy) Languages not allowing that kind of access should emulate it calling uwsgi_malloc and then copying it back to the language object. The memory areas could be monitored for changes (read: cores can be suspended while waiting for values) You can configure multiple areas specifying multiple --sharedarea options This is a very low-level api, try to use it to build higher-level primitives or rely on the caching subsystem */ struct uwsgi_sharedarea *uwsgi_sharedarea_get_by_id(int id, uint64_t pos) { if (id > uwsgi.sharedareas_cnt-1) return NULL; struct uwsgi_sharedarea *sa = uwsgi.sharedareas[id]; if (pos > sa->max_pos) return NULL; return sa; } int uwsgi_sharedarea_update(int id) { struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, 0); if (!sa) return -1; sa->updates++; return 0; } int uwsgi_sharedarea_rlock(int id) { struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, 0); if (!sa) return -1; uwsgi_rlock(sa->lock); return 0; } int uwsgi_sharedarea_wlock(int id) { struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, 0); if (!sa) return -1; uwsgi_wlock(sa->lock); return 0; } int uwsgi_sharedarea_unlock(int id) { struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, 0); if (!sa) return -1; uwsgi_rwunlock(sa->lock); return 0; } int64_t uwsgi_sharedarea_read(int id, uint64_t pos, char *blob, uint64_t len) { struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, pos); if (!sa) return -1; if (pos + len > sa->max_pos + 1) return -1; if (len == 0) len = (sa->max_pos + 1) - pos; if (sa->honour_used && sa->used-pos < len) len = sa->used-pos ; uwsgi_rlock(sa->lock); memcpy(blob, sa->area + pos, len); sa->hits++; uwsgi_rwunlock(sa->lock); return len; } int uwsgi_sharedarea_write(int id, uint64_t pos, char *blob, uint64_t len) { struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, pos); if (!sa) return -1; if (pos + len > sa->max_pos + 1) return -1; uwsgi_wlock(sa->lock); memcpy(sa->area + pos, blob, len); sa->updates++; uwsgi_rwunlock(sa->lock); return 0; } int uwsgi_sharedarea_read64(int id, uint64_t pos, int64_t *value) { int64_t rlen = uwsgi_sharedarea_read(id, pos, (char *) value, 8); return rlen == 8 ? 0 : -1; } int uwsgi_sharedarea_write64(int id, uint64_t pos, int64_t *value) { return uwsgi_sharedarea_write(id, pos, (char *) value, 8); } int uwsgi_sharedarea_read8(int id, uint64_t pos, int8_t *value) { int64_t rlen = uwsgi_sharedarea_read(id, pos, (char *) value, 1); return rlen == 1 ? 0 : -1; } int uwsgi_sharedarea_write8(int id, uint64_t pos, int8_t *value) { return uwsgi_sharedarea_write(id, pos, (char *) value, 1); } int uwsgi_sharedarea_read16(int id, uint64_t pos, int16_t *value) { int64_t rlen = uwsgi_sharedarea_read(id, pos, (char *) value, 2); return rlen == 2 ? 0 : -1; } int uwsgi_sharedarea_write16(int id, uint64_t pos, int16_t *value) { return uwsgi_sharedarea_write(id, pos, (char *) value, 2); } int uwsgi_sharedarea_read32(int id, uint64_t pos, int32_t *value) { int64_t rlen = uwsgi_sharedarea_read(id, pos, (char *) value, 4); return rlen == 4 ? 0 : -1; } int uwsgi_sharedarea_write32(int id, uint64_t pos, int32_t *value) { return uwsgi_sharedarea_write(id, pos, (char *) value, 4); } int uwsgi_sharedarea_inc8(int id, uint64_t pos, int8_t amount) { struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, pos); if (!sa) return -1; if (pos + 1 > sa->max_pos + 1) return -1; uwsgi_wlock(sa->lock); int8_t *n_ptr = (int8_t *) (sa->area + pos); *n_ptr+=amount; sa->updates++; uwsgi_rwunlock(sa->lock); return 0; } int uwsgi_sharedarea_inc16(int id, uint64_t pos, int16_t amount) { struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, pos); if (!sa) return -1; if (pos + 2 > sa->max_pos + 1) return -1; uwsgi_wlock(sa->lock); int16_t *n_ptr = (int16_t *) (sa->area + pos); *n_ptr+=amount; sa->updates++; uwsgi_rwunlock(sa->lock); return 0; } int uwsgi_sharedarea_inc32(int id, uint64_t pos, int32_t amount) { struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, pos); if (!sa) return -1; if (pos + 4 > sa->max_pos + 1) return -1; uwsgi_wlock(sa->lock); int32_t *n_ptr = (int32_t *) (sa->area + pos); *n_ptr+=amount; sa->updates++; uwsgi_rwunlock(sa->lock); return 0; } int uwsgi_sharedarea_inc64(int id, uint64_t pos, int64_t amount) { struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, pos); if (!sa) return -1; if (pos + 4 > sa->max_pos + 1) return -1; uwsgi_wlock(sa->lock); int64_t *n_ptr = (int64_t *) (sa->area + pos); *n_ptr+=amount; sa->updates++; uwsgi_rwunlock(sa->lock); return 0; } int uwsgi_sharedarea_dec8(int id, uint64_t pos, int8_t amount) { struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, pos); if (!sa) return -1; if (pos + 1 > sa->max_pos + 1) return -1; uwsgi_wlock(sa->lock); int8_t *n_ptr = (int8_t *) (sa->area + pos); *n_ptr-=amount; sa->updates++; uwsgi_rwunlock(sa->lock); return 0; } int uwsgi_sharedarea_dec16(int id, uint64_t pos, int16_t amount) { struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, pos); if (!sa) return -1; if (pos + 2 > sa->max_pos + 1) return -1; uwsgi_wlock(sa->lock); int16_t *n_ptr = (int16_t *) (sa->area + pos); *n_ptr-=amount; sa->updates++; uwsgi_rwunlock(sa->lock); return 0; } int uwsgi_sharedarea_dec32(int id, uint64_t pos, int32_t amount) { struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, pos); if (!sa) return -1; if (pos + 4 > sa->max_pos + 1) return -1; uwsgi_wlock(sa->lock); int32_t *n_ptr = (int32_t *) (sa->area + pos); *n_ptr-=amount; sa->updates++; uwsgi_rwunlock(sa->lock); return 0; } int uwsgi_sharedarea_dec64(int id, uint64_t pos, int64_t amount) { struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, pos); if (!sa) return -1; if (pos + 4 > sa->max_pos + 1) return -1; uwsgi_wlock(sa->lock); int64_t *n_ptr = (int64_t *) (sa->area + pos); *n_ptr-=amount; sa->updates++; uwsgi_rwunlock(sa->lock); return 0; } /* returns: 0 -> on updates -1 -> on error -2 -> on timeout */ int uwsgi_sharedarea_wait(int id, int freq, int timeout) { int waiting = 0; struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, 0); if (!sa) return -1; if (!freq) freq = 100; uwsgi_rlock(sa->lock); uint64_t updates = sa->updates; uwsgi_rwunlock(sa->lock); while(timeout == 0 || waiting == 0 || (timeout > 0 && waiting > 0 && (waiting/1000) < timeout)) { if (uwsgi.wait_milliseconds_hook(freq)) { uwsgi_rwunlock(sa->lock); return -1; } waiting += freq; // lock sa uwsgi_rlock(sa->lock); if (sa->updates != updates) { uwsgi_rwunlock(sa->lock); return 0; } // unlock sa uwsgi_rwunlock(sa->lock); } return -2; } int uwsgi_sharedarea_new_id() { int id = uwsgi.sharedareas_cnt; uwsgi.sharedareas_cnt++; if (!uwsgi.sharedareas) { uwsgi.sharedareas = uwsgi_malloc(sizeof(struct uwsgi_sharedarea *)); } else { struct uwsgi_sharedarea **usa = realloc(uwsgi.sharedareas, ((sizeof(struct uwsgi_sharedarea *)) * uwsgi.sharedareas_cnt)); if (!usa) { uwsgi_error("uwsgi_sharedarea_init()/realloc()"); exit(1); } uwsgi.sharedareas = usa; } return id; } static struct uwsgi_sharedarea *announce_sa(struct uwsgi_sharedarea *sa) { uwsgi_log("sharedarea %d created at %p (%d pages, area at %p)\n", sa->id, sa, sa->pages, sa->area); return sa; } struct uwsgi_sharedarea *uwsgi_sharedarea_init_fd(int fd, uint64_t len, off_t offset) { int id = uwsgi_sharedarea_new_id(); uwsgi.sharedareas[id] = uwsgi_calloc_shared(sizeof(struct uwsgi_sharedarea)); uwsgi.sharedareas[id]->area = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset); if (uwsgi.sharedareas[id]->area == MAP_FAILED) { uwsgi_error("uwsgi_sharedarea_init_fd()/mmap()"); exit(1); } uwsgi.sharedareas[id]->id = id; uwsgi.sharedareas[id]->fd = fd; uwsgi.sharedareas[id]->pages = len / (size_t) uwsgi.page_size; if (len % (size_t) uwsgi.page_size != 0) uwsgi.sharedareas[id]->pages++; uwsgi.sharedareas[id]->max_pos = len-1; char *id_str = uwsgi_num2str(id); uwsgi.sharedareas[id]->lock = uwsgi_rwlock_init(uwsgi_concat2("sharedarea", id_str)); free(id_str); return announce_sa(uwsgi.sharedareas[id]); } struct uwsgi_sharedarea *uwsgi_sharedarea_init(int pages) { int id = uwsgi_sharedarea_new_id(); uwsgi.sharedareas[id] = uwsgi_calloc_shared((size_t)uwsgi.page_size * (size_t)(pages + 1)); uwsgi.sharedareas[id]->area = ((char *) uwsgi.sharedareas[id]) + (size_t) uwsgi.page_size; uwsgi.sharedareas[id]->id = id; uwsgi.sharedareas[id]->fd = -1; uwsgi.sharedareas[id]->pages = pages; uwsgi.sharedareas[id]->max_pos = ((size_t)uwsgi.page_size * (size_t)pages) -1; char *id_str = uwsgi_num2str(id); uwsgi.sharedareas[id]->lock = uwsgi_rwlock_init(uwsgi_concat2("sharedarea", id_str)); free(id_str); return announce_sa(uwsgi.sharedareas[id]); } struct uwsgi_sharedarea *uwsgi_sharedarea_init_ptr(char *area, uint64_t len) { int id = uwsgi_sharedarea_new_id(); uwsgi.sharedareas[id] = uwsgi_calloc_shared(sizeof(struct uwsgi_sharedarea)); uwsgi.sharedareas[id]->area = area; uwsgi.sharedareas[id]->id = id; uwsgi.sharedareas[id]->fd = -1; uwsgi.sharedareas[id]->pages = len / (size_t) uwsgi.page_size; if (len % (size_t) uwsgi.page_size != 0) uwsgi.sharedareas[id]->pages++; uwsgi.sharedareas[id]->max_pos = len-1; char *id_str = uwsgi_num2str(id); uwsgi.sharedareas[id]->lock = uwsgi_rwlock_init(uwsgi_concat2("sharedarea", id_str)); free(id_str); return announce_sa(uwsgi.sharedareas[id]); } struct uwsgi_sharedarea *uwsgi_sharedarea_init_keyval(char *arg) { char *s_pages = NULL; char *s_file = NULL; char *s_fd = NULL; char *s_ptr = NULL; char *s_size = NULL; char *s_offset = NULL; if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=', "pages", &s_pages, "file", &s_file, "fd", &s_fd, "ptr", &s_ptr, "size", &s_size, "offset", &s_offset, NULL)) { uwsgi_log("invalid sharedarea keyval syntax\n"); exit(1); } uint64_t len = 0; off_t offset = 0; int pages = 0; if (s_size) { if (strlen(s_size) > 2 && s_size[0] == '0' && s_size[1] == 'x') { len = strtoul(s_size+2, NULL, 16); } else { len = uwsgi_n64(s_size); } pages = len / (size_t) uwsgi.page_size; if (len % (size_t) uwsgi.page_size != 0) pages++; } if (s_offset) { if (strlen(s_offset) > 2 && s_offset[0] == '0' && s_offset[1] == 'x') { offset = strtoul(s_offset+2, NULL, 16); } else { offset = uwsgi_n64(s_offset); } } if (s_pages) { pages = atoi(s_pages); } char *area = NULL; struct uwsgi_sharedarea *sa = NULL; int fd = -1; if (s_file) { fd = open(s_file, O_RDWR|O_SYNC); if (fd < 0) { uwsgi_error_open(s_file); exit(1); } } else if (s_fd) { fd = atoi(s_fd); } else if (s_ptr) { } if (pages) { if (fd > -1) { sa = uwsgi_sharedarea_init_fd(fd, len, offset); } else if (area) { sa = uwsgi_sharedarea_init_ptr(area, len); } else { sa = uwsgi_sharedarea_init(pages); } } else { uwsgi_log("you need to set a size for a sharedarea !!! [%s]\n", arg); exit(1); } if (s_pages) free(s_pages); if (s_file) free(s_file); if (s_fd) free(s_fd); if (s_ptr) free(s_ptr); if (s_size) free(s_size); if (s_offset) free(s_offset); return sa; } void uwsgi_sharedareas_init() { struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, uwsgi.sharedareas_list) { char *is_keyval = strchr(usl->value, '='); if (!is_keyval) { uwsgi_sharedarea_init(atoi(usl->value)); } else { uwsgi_sharedarea_init_keyval(usl->value); } } } uwsgi-2.0.29/core/signal.c000066400000000000000000000324371477626554400153500ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; int uwsgi_signal_handler(uint8_t sig) { struct uwsgi_signal_entry *use = NULL; int pos = (uwsgi.mywid * 256) + sig; use = &uwsgi.shared->signal_table[pos]; if (!use->handler) return -1; if (!uwsgi.p[use->modifier1]->signal_handler) { return -1; } // check for COW if (uwsgi.master_process) { if (use->wid != 0 && use->wid != uwsgi.mywid) { uwsgi_log("[uwsgi-signal] you have registered this signal in worker %d memory area, only that process will be able to run it\n", use->wid); return -1; } } // in lazy mode (without a master), only the same worker will be able to run handlers else if (uwsgi.lazy) { if (use->wid != uwsgi.mywid) { uwsgi_log("[uwsgi-signal] you have registered this signal in worker %d memory area, only that process will be able to run it\n", use->wid); return -1; } } else { // when master is not active, worker1 is the COW-leader if (use->wid != 1 && use->wid != uwsgi.mywid) { uwsgi_log("[uwsgi-signal] you have registered this signal in worker %d memory area, only that process will be able to run it\n", use->wid); return -1; } } // set harakiri here (if required and if i am a worker) if (uwsgi.mywid > 0) { uwsgi.workers[uwsgi.mywid].sig = 1; uwsgi.workers[uwsgi.mywid].signum = sig; uwsgi.workers[uwsgi.mywid].signals++; if (uwsgi.harakiri_options.workers > 0) { set_harakiri(uwsgi.harakiri_options.workers); } } else if (uwsgi.muleid > 0) { uwsgi.mules[uwsgi.muleid - 1].sig = 1; uwsgi.mules[uwsgi.muleid - 1].signum = sig; uwsgi.mules[uwsgi.muleid - 1].signals++; if (uwsgi.harakiri_options.mules > 0) { set_mule_harakiri(uwsgi.harakiri_options.mules); } } else if (uwsgi.i_am_a_spooler && (getpid() == uwsgi.i_am_a_spooler->pid)) { if (uwsgi.harakiri_options.spoolers > 0) { set_spooler_harakiri(uwsgi.harakiri_options.spoolers); } } int ret = uwsgi.p[use->modifier1]->signal_handler(sig, use->handler); if (uwsgi.mywid > 0) { uwsgi.workers[uwsgi.mywid].sig = 0; if (uwsgi.workers[uwsgi.mywid].harakiri > 0) { set_harakiri(0); } } else if (uwsgi.muleid > 0) { uwsgi.mules[uwsgi.muleid - 1].sig = 0; if (uwsgi.mules[uwsgi.muleid - 1].harakiri > 0) { set_mule_harakiri(0); } } else if (uwsgi.i_am_a_spooler && (getpid() == uwsgi.i_am_a_spooler->pid)) { if (uwsgi.harakiri_options.spoolers > 0) { set_spooler_harakiri(0); } } return ret; } int uwsgi_signal_registered(uint8_t sig) { int pos = (uwsgi.mywid * 256) + sig; if (uwsgi.shared->signal_table[pos].handler != NULL) return 1; return 0; } int uwsgi_register_signal(uint8_t sig, char *receiver, void *handler, uint8_t modifier1) { struct uwsgi_signal_entry *use = NULL; size_t receiver_len; if (!uwsgi.master_process) { uwsgi_log("you cannot register signals without a master\n"); return -1; } if (uwsgi.mywid == 0 && uwsgi.workers[0].pid != uwsgi.mypid) { uwsgi_log("only the master and the workers can register signal handlers\n"); return -1; } receiver_len = strlen(receiver); if (receiver_len > 63) return -1; uwsgi_lock(uwsgi.signal_table_lock); int pos = (uwsgi.mywid * 256) + sig; use = &uwsgi.shared->signal_table[pos]; if (use->handler && uwsgi.mywid == 0) { uwsgi_log("[uwsgi-signal] you cannot re-register a signal as the master !!!\n"); uwsgi_unlock(uwsgi.signal_table_lock); return -1; } strncpy(use->receiver, receiver, receiver_len + 1); use->handler = handler; use->modifier1 = modifier1; use->wid = uwsgi.mywid; if (use->receiver[0] == 0) { uwsgi_log("[uwsgi-signal] signum %d registered (wid: %d modifier1: %d target: default, any worker)\n", sig, uwsgi.mywid, modifier1); } else { uwsgi_log("[uwsgi-signal] signum %d registered (wid: %d modifier1: %d target: %s)\n", sig, uwsgi.mywid, modifier1, receiver); } // check for cow if (uwsgi.mywid == 0) { int i; for(i=1;i<=uwsgi.numproc;i++) { int pos = (i * 256); memcpy(&uwsgi.shared->signal_table[pos], &uwsgi.shared->signal_table[0], sizeof(struct uwsgi_signal_entry) * 256); } } uwsgi_unlock(uwsgi.signal_table_lock); return 0; } int uwsgi_add_file_monitor(uint8_t sig, char *filename) { if (strlen(filename) > (0xff - 1)) { uwsgi_log("uwsgi_add_file_monitor: invalid filename length\n"); return -1; } uwsgi_lock(uwsgi.fmon_table_lock); if (ushared->files_monitored_cnt < 64) { // fill the fmon table, the master will use it to add items to the event queue memcpy(ushared->files_monitored[ushared->files_monitored_cnt].filename, filename, strlen(filename)); ushared->files_monitored[ushared->files_monitored_cnt].registered = 0; ushared->files_monitored[ushared->files_monitored_cnt].sig = sig; ushared->files_monitored_cnt++; } else { uwsgi_log("you can register max 64 file monitors !!!\n"); uwsgi_unlock(uwsgi.fmon_table_lock); return -1; } uwsgi_unlock(uwsgi.fmon_table_lock); return 0; } int uwsgi_add_timer(uint8_t sig, int secs) { if (!uwsgi.master_process) return -1; uwsgi_lock(uwsgi.timer_table_lock); if (ushared->timers_cnt < 64) { // fill the timer table, the master will use it to add items to the event queue ushared->timers[ushared->timers_cnt].value = secs; ushared->timers[ushared->timers_cnt].registered = 0; ushared->timers[ushared->timers_cnt].sig = sig; ushared->timers_cnt++; } else { uwsgi_log("you can register max 64 timers !!!\n"); uwsgi_unlock(uwsgi.timer_table_lock); return -1; } uwsgi_unlock(uwsgi.timer_table_lock); return 0; } int uwsgi_signal_add_rb_timer(uint8_t sig, int secs, int iterations) { if (!uwsgi.master_process) return -1; uwsgi_lock(uwsgi.rb_timer_table_lock); if (ushared->rb_timers_cnt < 64) { // fill the timer table, the master will use it to add items to the event queue ushared->rb_timers[ushared->rb_timers_cnt].value = secs; ushared->rb_timers[ushared->rb_timers_cnt].registered = 0; ushared->rb_timers[ushared->rb_timers_cnt].iterations = iterations; ushared->rb_timers[ushared->rb_timers_cnt].iterations_done = 0; ushared->rb_timers[ushared->rb_timers_cnt].sig = sig; ushared->rb_timers_cnt++; } else { uwsgi_log("you can register max 64 rb_timers !!!\n"); uwsgi_unlock(uwsgi.rb_timer_table_lock); return -1; } uwsgi_unlock(uwsgi.rb_timer_table_lock); return 0; } void create_signal_pipe(int *sigpipe) { if (socketpair(AF_UNIX, SOCK_STREAM, 0, sigpipe)) { uwsgi_error("socketpair()\n"); exit(1); } uwsgi_socket_nb(sigpipe[0]); uwsgi_socket_nb(sigpipe[1]); if (uwsgi.signal_bufsize) { if (setsockopt(sigpipe[0], SOL_SOCKET, SO_SNDBUF, &uwsgi.signal_bufsize, sizeof(int))) { uwsgi_error("setsockopt()"); } if (setsockopt(sigpipe[0], SOL_SOCKET, SO_RCVBUF, &uwsgi.signal_bufsize, sizeof(int))) { uwsgi_error("setsockopt()"); } if (setsockopt(sigpipe[1], SOL_SOCKET, SO_SNDBUF, &uwsgi.signal_bufsize, sizeof(int))) { uwsgi_error("setsockopt()"); } if (setsockopt(sigpipe[1], SOL_SOCKET, SO_RCVBUF, &uwsgi.signal_bufsize, sizeof(int))) { uwsgi_error("setsockopt()"); } } } int uwsgi_remote_signal_send(char *addr, uint8_t sig) { struct uwsgi_header uh; uh.modifier1 = 110; uh.pktsize = 0; uh.modifier2 = sig; int fd = uwsgi_connect(addr, 0, 1); if (fd < 0) return -1; // wait for connection if (uwsgi.wait_write_hook(fd, uwsgi.socket_timeout) <= 0) goto end; if (uwsgi_write_true_nb(fd, (char *) &uh, 4, uwsgi.socket_timeout)) goto end; if (uwsgi_read_whole_true_nb(fd, (char *) &uh, 4, uwsgi.socket_timeout)) goto end; close(fd); return uh.modifier2; end: close(fd); return -1; } int uwsgi_signal_send(int fd, uint8_t sig) { socklen_t so_bufsize_len = sizeof(int); int so_bufsize = 0; if (write(fd, &sig, 1) != 1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &so_bufsize, &so_bufsize_len)) { uwsgi_error("getsockopt()"); } uwsgi_log("*** SIGNAL QUEUE IS FULL: buffer size %d bytes (you can tune it with --signal-bufsize) ***\n", so_bufsize); } else { uwsgi_error("uwsgi_signal_send()"); } uwsgi.shared->unrouted_signals++; return -1; } uwsgi.shared->routed_signals++; return 0; } void uwsgi_route_signal(uint8_t sig) { int pos = (uwsgi.mywid * 256) + sig; struct uwsgi_signal_entry *use = &ushared->signal_table[pos]; int i; // send to first available worker if (use->receiver[0] == 0 || !strcmp(use->receiver, "worker") || !strcmp(use->receiver, "worker0")) { if (uwsgi_signal_send(ushared->worker_signal_pipe[0], sig)) { uwsgi_log("could not deliver signal %d to workers pool\n", sig); } } // send to all workers else if (!strcmp(use->receiver, "workers")) { for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi_signal_send(uwsgi.workers[i].signal_pipe[0], sig)) { uwsgi_log("could not deliver signal %d to worker %d\n", sig, i); } } } // send to al lactive workers else if (!strcmp(use->receiver, "active-workers")) { for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].pid > 0 && !uwsgi.workers[i].cheaped && !uwsgi.workers[i].suspended) { if (uwsgi_signal_send(uwsgi.workers[i].signal_pipe[0], sig)) { uwsgi_log("could not deliver signal %d to worker %d\n", sig, i); } } } } // route to specific worker else if (!strncmp(use->receiver, "worker", 6)) { i = atoi(use->receiver + 6); if (i > uwsgi.numproc) { uwsgi_log("invalid signal target: %s\n", use->receiver); } if (uwsgi_signal_send(uwsgi.workers[i].signal_pipe[0], sig)) { uwsgi_log("could not deliver signal %d to worker %d\n", sig, i); } } // route to subscribed else if (!strcmp(use->receiver, "subscribed")) { } // route to spooler else if (!strcmp(use->receiver, "spooler")) { if (ushared->worker_signal_pipe[0] != -1) { if (uwsgi_signal_send(ushared->spooler_signal_pipe[0], sig)) { uwsgi_log("could not deliver signal %d to the spooler\n", sig); } } } else if (!strcmp(use->receiver, "mules")) { for (i = 0; i < uwsgi.mules_cnt; i++) { if (uwsgi_signal_send(uwsgi.mules[i].signal_pipe[0], sig)) { uwsgi_log("could not deliver signal %d to mule %d\n", sig, i + 1); } } } else if (!strncmp(use->receiver, "mule", 4)) { i = atoi(use->receiver + 4); if (i > uwsgi.mules_cnt) { uwsgi_log("invalid signal target: %s\n", use->receiver); } else if (i == 0) { if (uwsgi_signal_send(ushared->mule_signal_pipe[0], sig)) { uwsgi_log("could not deliver signal %d to a mule\n", sig); } } else { if (uwsgi_signal_send(uwsgi.mules[i - 1].signal_pipe[0], sig)) { uwsgi_log("could not deliver signal %d to mule %d\n", sig, i); } } } else if (!strncmp(use->receiver, "farm_", 5)) { char *name = use->receiver + 5; struct uwsgi_farm *uf = get_farm_by_name(name); if (!uf) { uwsgi_log("unknown farm: %s\n", name); return; } if (uwsgi_signal_send(uf->signal_pipe[0], sig)) { uwsgi_log("could not deliver signal %d to farm %d (%s)\n", sig, uf->id, uf->name); } } else if (!strncmp(use->receiver, "farm", 4)) { i = atoi(use->receiver + 4); if (i > uwsgi.farms_cnt || i <= 0) { uwsgi_log("invalid signal target: %s\n", use->receiver); } else { if (uwsgi_signal_send(uwsgi.farms[i - 1].signal_pipe[0], sig)) { uwsgi_log("could not deliver signal %d to farm %d (%s)\n", sig, i, uwsgi.farms[i - 1].name); } } } else { // unregistered signal, sending it to all the workers uwsgi_log("^^^ UNSUPPORTED SIGNAL TARGET: %s ^^^\n", use->receiver); } } int uwsgi_signal_wait(int signum) { int wait_for_specific_signal = 0; uint8_t uwsgi_signal = 0; int received_signal = -1; int ret; struct pollfd pfd[2]; if (signum > -1) { wait_for_specific_signal = 1; } pfd[0].fd = uwsgi.signal_socket; pfd[0].events = POLLIN; pfd[1].fd = uwsgi.my_signal_socket; pfd[1].events = POLLIN; cycle: ret = poll(pfd, 2, -1); if (ret > 0) { if (pfd[0].revents == POLLIN) { if (read(uwsgi.signal_socket, &uwsgi_signal, 1) != 1) { uwsgi_error("read()"); } else { (void) uwsgi_signal_handler(uwsgi_signal); if (wait_for_specific_signal) { if (signum != uwsgi_signal) goto cycle; } received_signal = uwsgi_signal; } } if (pfd[1].revents == POLLIN) { if (read(uwsgi.my_signal_socket, &uwsgi_signal, 1) != 1) { uwsgi_error("read()"); } else { (void) uwsgi_signal_handler(uwsgi_signal); if (wait_for_specific_signal) { if (signum != uwsgi_signal) goto cycle; } } received_signal = uwsgi_signal; } } return received_signal; } void uwsgi_receive_signal(int fd, char *name, int id) { uint8_t uwsgi_signal; ssize_t ret = read(fd, &uwsgi_signal, 1); if (ret == 0) { goto destroy; } else if (ret < 0 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) { uwsgi_error("[uwsgi-signal] read()"); goto destroy; } else if (ret > 0) { #ifdef UWSGI_DEBUG uwsgi_log_verbose("master sent signal %d to %s %d\n", uwsgi_signal, name, id); #endif if (uwsgi_signal_handler(uwsgi_signal)) { uwsgi_log_verbose("error managing signal %d on %s %d\n", uwsgi_signal, name, id); } } return; destroy: // better to kill the whole worker... uwsgi_log_verbose("uWSGI %s %d error: the master disconnected from this worker. Shutting down the worker.\n", name, id); end_me(0); } uwsgi-2.0.29/core/skel.c000066400000000000000000000003261477626554400150210ustar00rootroot00000000000000/* this is a skeleton to use libuwsgi in external projects */ extern char **environ; int uwsgi_init(int, char **, char **); int main(int argc, char **argv, char **environ) { uwsgi_init(argc, argv, environ); } uwsgi-2.0.29/core/snmp.c000066400000000000000000000225311477626554400150420ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; #define SNMP_SEQUENCE 0x30 #define SNMP_INTEGER 0x02 #define SNMP_STRING 0x04 #define SNMP_NULL 0x05 #define SNMP_GET 0xA0 #define SNMP_RES 0xA2 #define SNMP_OID 0x06 #define SNMP_WATERMARK (127-8) /* 1.3.6.1.4.1.35156.17.X.X */ #define SNMP_UWSGI_BASE "\x2B\x06\x01\x04\x01\x82\x92\x54\x11" static int get_snmp_integer(uint8_t *, uint64_t *); static uint64_t get_uwsgi_snmp_value(uint64_t, uint8_t *); static uint64_t get_uwsgi_custom_snmp_value(uint64_t, uint8_t *); static uint8_t snmp_int_to_snmp(uint64_t, uint8_t, uint8_t *); static ssize_t build_snmp_response(uint8_t, uint8_t, uint8_t *, int, uint8_t *, uint8_t *, uint8_t *); static ssize_t build_snmp_metric_response(int64_t, uint8_t, uint8_t *, int, uint8_t *, uint8_t *, uint8_t *); void manage_snmp(int fd, uint8_t * buffer, int size, struct sockaddr_in *client_addr) { uint16_t asnlen; uint16_t oidlen; uint8_t oid_part[2]; int ptrdelta; uint8_t *ptr = buffer, *seq1, *seq2, *seq3; uint8_t community_len; uint64_t snmp_int = 0; uint64_t request_id = 0; uint64_t version = 0; // KISS for memory management if (size > SNMP_WATERMARK) return; ptr++; // check total sequence size if (*ptr > SNMP_WATERMARK || *ptr < 13) return; ptr++; #ifdef UWSGI_DEBUG uwsgi_debug("SNMP packet size: %d\n", size); #endif // check snmp version if (*ptr != SNMP_INTEGER) return; ptr++; ptrdelta = get_snmp_integer(ptr, &version); if (version > 2) return; ptr += ptrdelta; #ifdef UWSGI_DEBUG uwsgi_debug("SNMP version: %d\n", version); #endif // check for community string (this must be set from the api using uwsgi.snmp_community or with --snmp-community arg) if (*ptr != SNMP_STRING) return; ptr++; community_len = *ptr; if (community_len > 72 || community_len < 1) return; ptr++; // check for community string if (strlen(uwsgi.shared->snmp_community) != community_len) return; if (memcmp(ptr, uwsgi.shared->snmp_community, community_len)) return; #ifdef UWSGI_DEBUG uwsgi_debug("SNMP community: %.*s\n", community_len, ptr); #endif ptr += community_len; // check for get request if (*ptr != SNMP_GET) return; *ptr = SNMP_RES; ptr++; seq1 = ptr; if (*ptr != ((size - community_len) - 9)) return; ptr++; // get request_id if (*ptr != SNMP_INTEGER) return; ptr++; ptrdelta = get_snmp_integer(ptr, &request_id); if (ptrdelta <= 0) return; #ifdef UWSGI_DEBUG uwsgi_debug("SNMP request id: %d %p\n", request_id, ptr); #endif // check here if (ptr + ptrdelta >= buffer + size) return; ptr += ptrdelta; // get error if (*ptr != SNMP_INTEGER) return; ptr++; snmp_int = 0; ptrdelta = get_snmp_integer(ptr, &snmp_int); if (ptrdelta <= 0) return; if (ptr + ptrdelta >= buffer + size) return; if (snmp_int != 0) return; ptr += ptrdelta; // get index if (*ptr != SNMP_INTEGER) return; ptr++; snmp_int = 0; ptrdelta = get_snmp_integer(ptr, &snmp_int); if (ptrdelta <= 0) return; if (ptr + ptrdelta >= buffer + size) return; if (snmp_int != 0) return; ptr += ptrdelta; #ifdef UWSGI_DEBUG uwsgi_debug("SNMP int [1]: %d\n", snmp_int); #endif // check for sequence if (*ptr != SNMP_SEQUENCE) return; ptr++; if (*ptr > SNMP_WATERMARK) return; seq2 = ptr; ptr++; // now the interesting stuff: OID management if (*ptr != SNMP_SEQUENCE) return; ptr++; // check for normal OID uWSGI size: |1.3|.6|.1|.4|.1.|35156|.17|.1/2|.x| + OID_NULL asnlen = *ptr; if (asnlen < 15) return; seq3 = ptr; ptr++; #ifdef UWSGI_DEBUG uwsgi_debug("SNMP ASN len: %d\n", asnlen); #endif // is it an OID ? if (*ptr != SNMP_OID) return; ptr++; oidlen = *ptr; if (oidlen < 11) return; ptr++; // and now parse the OID !!! if (memcmp(ptr, SNMP_UWSGI_BASE, 9)) return; ptr += 9; oid_part[0] = *ptr; // old-style SNMP metrics if (oid_part[0] == 1 || oid_part[0] == 2) { ptr++; oid_part[1] = *ptr; if (oid_part[1] < 1 || oid_part[1] > 100) return; ptr++; // check for null if (memcmp((char *) ptr, "\x05\x00", 2)) return; ptr += 2; size = build_snmp_response(oid_part[0], oid_part[1], buffer, size, seq1, seq2, seq3); } // metrics subsystem else { size_t metric_asn_len = oidlen - 9; char *metric_asn = (char *) ptr; struct uwsgi_metric *um = uwsgi_metric_find_by_asn(metric_asn, metric_asn_len); if (!um) return; uwsgi_rlock(uwsgi.metrics_lock); int64_t value = *um->value; uwsgi_rwunlock(uwsgi.metrics_lock); size = build_snmp_metric_response(value, um->type, buffer, size, seq1, seq2, seq3); } if (size > 0) { if (sendto(fd, buffer, size, 0, (struct sockaddr *) client_addr, sizeof(struct sockaddr_in)) < 0) { uwsgi_error("sendto()"); } } } static uint64_t get_uwsgi_snmp_value(uint64_t val, uint8_t * oid_t) { val--; if (uwsgi.shared->snmp_gvalue[val].type) { *oid_t = uwsgi.shared->snmp_gvalue[val].type; return *uwsgi.shared->snmp_gvalue[val].val; } *oid_t = SNMP_NULL; return 0; } static uint64_t get_uwsgi_custom_snmp_value(uint64_t val, uint8_t * oid_t) { val--; uwsgi_wlock(uwsgi.snmp_lock); if (uwsgi.shared->snmp_value[val].type) { *oid_t = uwsgi.shared->snmp_value[val].type; uwsgi_rwunlock(uwsgi.snmp_lock); return uwsgi.shared->snmp_value[val].val; } uwsgi_rwunlock(uwsgi.snmp_lock); *oid_t = SNMP_NULL; return 0; } static int get_snmp_integer(uint8_t * ptr, uint64_t * val) { uint16_t tlen; int i, j; uint8_t *cval = (uint8_t *) val; tlen = *ptr; if (tlen > 4) return -1; #ifdef UWSGI_DEBUG uwsgi_debug("SNMP get integer TLEN %d %p\n", tlen, ptr); #endif j = 0; #ifdef __BIG_ENDIAN__ for (i = 0; i < tlen; i++) { #else for (i = tlen - 1; i >= 0; i--) { #endif cval[j] = ptr[1 + i]; j++; } return tlen + 1; } static uint8_t snmp_int_to_snmp(uint64_t snmp_val, uint8_t oid_type, uint8_t * buffer) { uint8_t tlen; int i, j; uint8_t *ptr = (uint8_t *) & snmp_val; int32_t val32 = (int32_t) snmp_val; // check for counter, counter64 or gauge if (oid_type == SNMP_COUNTER64) { tlen = 8; } else if (oid_type == SNMP_NULL || oid_type == 0) { tlen = 0; } else { tlen = 4; ptr = (uint8_t *) &val32; } buffer[0] = tlen; j = 1; #ifdef __BIG_ENDIAN__ for (i = 0; i < tlen; i++) { #else for (i = tlen - 1; i >= 0; i--) { #endif buffer[j] = ptr[i]; j++; } return tlen + 1; } static ssize_t build_snmp_response(uint8_t oid1, uint8_t oid2, uint8_t * buffer, int size, uint8_t * seq1, uint8_t * seq2, uint8_t * seq3) { uint64_t snmp_val; uint8_t oid_sz; uint8_t oid_type; if (oid1 == 1) { snmp_val = get_uwsgi_snmp_value(oid2, &oid_type); } else if (oid1 == 2) { snmp_val = get_uwsgi_custom_snmp_value(oid2, &oid_type); } else { return -1; } buffer[size - 2] = oid_type; oid_sz = snmp_int_to_snmp(snmp_val, oid_type, buffer + (size - 1)); if (oid_sz < 1) return -1; oid_sz--; buffer[1] += oid_sz; *seq1 += oid_sz; *seq2 += oid_sz; *seq3 += oid_sz; return size + oid_sz; } static ssize_t build_snmp_metric_response(int64_t value, uint8_t type, uint8_t * buffer, int size, uint8_t * seq1, uint8_t * seq2, uint8_t * seq3) { uint8_t oid_sz; if (type == UWSGI_METRIC_GAUGE) { buffer[size - 2] = SNMP_GAUGE; oid_sz = snmp_int_to_snmp(value, SNMP_GAUGE, buffer + (size - 1)); } else { buffer[size - 2] = SNMP_COUNTER64; oid_sz = snmp_int_to_snmp(value, SNMP_COUNTER64, buffer + (size - 1)); } if (oid_sz < 1) return -1; oid_sz--; buffer[1] += oid_sz; *seq1 += oid_sz; *seq2 += oid_sz; *seq3 += oid_sz; return size + oid_sz; } void uwsgi_opt_snmp(char *opt, char *value, void *foobar) { uwsgi.snmp = 1; if (value) { uwsgi.snmp_addr = value; uwsgi.master_process = 1; } } void uwsgi_opt_snmp_community(char *opt, char *value, void *foobar) { uwsgi.snmp = 1; uwsgi.snmp_community = value; } int uwsgi_setup_snmp(void) { int snmp_fd = -1; int i; if (uwsgi.snmp) { if (uwsgi.snmp_community) { if (strlen(uwsgi.snmp_community) > 72) { uwsgi_log("*** warning the supplied SNMP community string will be truncated to 72 chars ***\n"); memcpy(uwsgi.shared->snmp_community, uwsgi.snmp_community, 72); } else { memcpy(uwsgi.shared->snmp_community, uwsgi.snmp_community, strlen(uwsgi.snmp_community) + 1); } } uwsgi.shared->snmp_gvalue[0].type = SNMP_COUNTER64; uwsgi.shared->snmp_gvalue[0].val = &uwsgi.workers[0].requests; for (i = 0; i < uwsgi.numproc; i++) { uwsgi.shared->snmp_gvalue[30 + i].type = SNMP_COUNTER64; uwsgi.shared->snmp_gvalue[30 + i].val = &uwsgi.workers[i + 1].requests; } if (uwsgi.snmp_addr) { snmp_fd = bind_to_udp(uwsgi.snmp_addr, 0, 0); if (snmp_fd < 0) { uwsgi_log("unable to bind to udp socket. SNMP service will be disabled.\n"); } else { uwsgi_log("SNMP server enabled on %s\n", uwsgi.snmp_addr); event_queue_add_fd_read(uwsgi.master_queue, snmp_fd); } } else { uwsgi_log("SNMP agent enabled.\n"); } } return snmp_fd; } void uwsgi_master_manage_snmp(int snmp_fd) { struct sockaddr_in udp_client; socklen_t udp_len = sizeof(udp_client); ssize_t rlen = recvfrom(snmp_fd, uwsgi.wsgi_req->buffer, uwsgi.buffer_size, 0, (struct sockaddr *) &udp_client, &udp_len); if (rlen < 0) { uwsgi_error("recvfrom()"); } else if (rlen > 0) { manage_snmp(snmp_fd, (uint8_t *) uwsgi.wsgi_req->buffer, rlen, &udp_client); } } uwsgi-2.0.29/core/socket.c000066400000000000000000001440631477626554400153620ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; static int connect_to_unix(char *, int, int); static int connect_to_tcp(char *, int, int, int); static int connect_to_udp(char *, int); void uwsgi_socket_setup_protocol(struct uwsgi_socket *uwsgi_sock, char *protocol) { if (!protocol) protocol = "uwsgi"; struct uwsgi_protocol *up = uwsgi.protocols; while(up) { if (!strcmp(protocol, up->name)) { up->func(uwsgi_sock); return; } up = up->next; } uwsgi_log("unable to find protocol %s\n", protocol); exit(1); } static int uwsgi_socket_strcmp(char *sock1, char *sock2) { size_t sock1_len = strlen(sock1); size_t sock2_len = strlen(sock2); if (!uwsgi_starts_with(sock1, sock1_len, "0.0.0.0:", 8)) { sock1 += 7; sock1_len = strlen(sock1); } if (!uwsgi_starts_with(sock2, sock2_len, "0.0.0.0:", 8)) { sock2 += 7; sock2_len = strlen(sock2); } return uwsgi_strncmp(sock1, sock1_len, sock2, sock2_len); } char *uwsgi_getsockname(int fd) { socklen_t socket_type_len = sizeof(struct sockaddr_un); union uwsgi_sockaddr usa; union uwsgi_sockaddr_ptr gsa; char computed_port[6]; char ipv4a[INET_ADDRSTRLEN + 1]; gsa.sa = (struct sockaddr *) &usa; if (!getsockname(fd, gsa.sa, &socket_type_len)) { if (gsa.sa->sa_family == AF_UNIX) { if (usa.sa_un.sun_path[0] == 0) { return uwsgi_concat2("@", usa.sa_un.sun_path + 1); } else { return uwsgi_str(usa.sa_un.sun_path); } } else { memset(ipv4a, 0, INET_ADDRSTRLEN + 1); memset(computed_port, 0, 6); if (snprintf(computed_port, 6, "%d", ntohs(gsa.sa_in->sin_port)) > 0) { if (inet_ntop(AF_INET, (const void *) &gsa.sa_in->sin_addr.s_addr, ipv4a, INET_ADDRSTRLEN)) { if (!strcmp("0.0.0.0", ipv4a)) { return uwsgi_concat2(":", computed_port); } else { return uwsgi_concat3(ipv4a, ":", computed_port); } } } } } return NULL; } static int create_server_socket(int domain, int type) { int serverfd = socket(domain, type, 0); if (serverfd < 0) { uwsgi_error("socket()"); uwsgi_nuclear_blast(); return -1; } if (uwsgi.close_on_exec2 && fcntl(serverfd, F_SETFD, FD_CLOEXEC) < 0) uwsgi_error("fcntl()"); if (domain != AF_UNIX) { int reuse = 1; if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) { uwsgi_error("SO_REUSEADDR setsockopt()"); uwsgi_nuclear_blast(); return -1; } } if (type == SOCK_STREAM) { if (uwsgi.so_sndbuf) { socklen_t sndbuf = (socklen_t) uwsgi.so_sndbuf; if (setsockopt(serverfd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(socklen_t)) < 0) { uwsgi_error("SO_SNDBUF setsockopt()"); uwsgi_nuclear_blast(); return -1; } } if (uwsgi.so_rcvbuf) { socklen_t rcvbuf = (socklen_t) uwsgi.so_rcvbuf; if (setsockopt(serverfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(socklen_t)) < 0) { uwsgi_error("SO_RCVBUF setsockopt()"); uwsgi_nuclear_blast(); return -1; } } #ifdef __linux__ long somaxconn = uwsgi_num_from_file("/proc/sys/net/core/somaxconn", 1); if (somaxconn > 0 && uwsgi.listen_queue > somaxconn) { uwsgi_log("Listen queue size is greater than the system max net.core.somaxconn (%li).\n", somaxconn); uwsgi_nuclear_blast(); return -1; } #endif } return serverfd; } int bind_to_unix_dgram(char *socket_name) { int serverfd; struct sockaddr_un *uws_addr; socklen_t len; serverfd = create_server_socket(AF_UNIX, SOCK_DGRAM); if (serverfd < 0) return -1; if (unlink(socket_name) != 0 && errno != ENOENT) { uwsgi_error("error removing unix socket, unlink()"); } uws_addr = uwsgi_calloc(sizeof(struct sockaddr_un)); uws_addr->sun_family = AF_UNIX; memcpy(uws_addr->sun_path, socket_name, UMIN(strlen(socket_name), 102)); len = strlen(socket_name); #ifdef __HAIKU__ if (bind(serverfd, (struct sockaddr *) uws_addr, sizeof(struct sockaddr_un))) { #else if (bind(serverfd, (struct sockaddr *) uws_addr, len + ((void *) uws_addr->sun_path - (void *) uws_addr)) != 0) { #endif uwsgi_error("bind()"); uwsgi_nuclear_blast(); return -1; } return serverfd; } int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abstract_socket) { int serverfd; struct sockaddr_un *uws_addr; socklen_t len; // leave 1 byte for abstract namespace (108 linux -> 104 bsd/mac) if (strlen(socket_name) > 102) { uwsgi_log("invalid socket name\n"); uwsgi_nuclear_blast(); return -1; } if (socket_name[0] == '@') { abstract_socket = 1; } else if (strlen(socket_name) > 1 && socket_name[0] == '\\' && socket_name[1] == '0') { abstract_socket = 1; } uws_addr = malloc(sizeof(struct sockaddr_un)); if (uws_addr == NULL) { uwsgi_error("malloc()"); uwsgi_nuclear_blast(); return -1; } memset(uws_addr, 0, sizeof(struct sockaddr_un)); serverfd = create_server_socket(AF_UNIX, SOCK_STREAM); if (serverfd < 0) { free(uws_addr); return -1; } if (abstract_socket == 0) { if (unlink(socket_name) != 0 && errno != ENOENT) { uwsgi_error("error removing unix socket, unlink()"); } } if (abstract_socket == 1) { uwsgi_log("setting abstract socket mode (warning: only Linux supports this)\n"); } uws_addr->sun_family = AF_UNIX; if (socket_name[0] == '@') { memcpy(uws_addr->sun_path + abstract_socket, socket_name + 1, UMIN(strlen(socket_name + 1), 101)); len = strlen(socket_name) + 1; } else if (strlen(socket_name) > 1 && socket_name[0] == '\\' && socket_name[1] == '0') { memcpy(uws_addr->sun_path + abstract_socket, socket_name + 2, UMIN(strlen(socket_name + 2), 101)); len = strlen(socket_name + 1) + 1; } else if (abstract_socket) { memcpy(uws_addr->sun_path + 1, socket_name, UMIN(strlen(socket_name), 101)); len = strlen(socket_name) + 1; } else { memcpy(uws_addr->sun_path + abstract_socket, socket_name, UMIN(strlen(socket_name), 102)); len = strlen(socket_name); } #ifdef __HAIKU__ if (bind(serverfd, (struct sockaddr *) uws_addr, sizeof(struct sockaddr_un))) { #else if (bind(serverfd, (struct sockaddr *) uws_addr, len + ((void *) uws_addr->sun_path - (void *) uws_addr)) != 0) { #endif uwsgi_error("bind()"); uwsgi_nuclear_blast(); return -1; } if (listen(serverfd, listen_queue) != 0) { uwsgi_error("listen()"); uwsgi_nuclear_blast(); return -1; } // chmod unix socket for lazy users if (chmod_socket == 1 && abstract_socket == 0) { if (uwsgi.chmod_socket_value) { if (chmod(socket_name, uwsgi.chmod_socket_value) != 0) { uwsgi_error("chmod()"); } } else { uwsgi_log("chmod() socket to 666 for lazy and brave users\n"); if (chmod(socket_name, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) != 0) { uwsgi_error("chmod()"); } } } free(uws_addr); return serverfd; } int bind_to_udp(char *socket_name, int multicast, int broadcast) { int serverfd; struct sockaddr_in uws_addr; char *udp_port; int bcast = 1; struct ip_mreq mc; udp_port = strchr(socket_name, ':'); if (udp_port == NULL) { return -1; } udp_port[0] = 0; if (socket_name[0] == 0 && multicast) { uwsgi_log("invalid multicast address\n"); return -1; } memset(&uws_addr, 0, sizeof(struct sockaddr_in)); uws_addr.sin_family = AF_INET; uws_addr.sin_port = htons(atoi(udp_port + 1)); if (!broadcast && !multicast) { char quad[4]; char *first_part = strchr(socket_name, '.'); if (first_part && first_part - socket_name < 4) { memset(quad, 0, 4); memcpy(quad, socket_name, first_part - socket_name); if (atoi(quad) >= 224 && atoi(quad) <= 239) { multicast = 1; } } if (!strcmp(socket_name, "255.255.255.255")) { broadcast = 1; } } if (broadcast) { uws_addr.sin_addr.s_addr = INADDR_BROADCAST; } else if (socket_name[0] != 0) { uws_addr.sin_addr.s_addr = inet_addr(socket_name); } else { uws_addr.sin_addr.s_addr = INADDR_ANY; } serverfd = create_server_socket(AF_INET, SOCK_DGRAM); if (serverfd < 0) return -1; if (multicast) { // if multicast is enabled remember to bind to INADDR_ANY uws_addr.sin_addr.s_addr = INADDR_ANY; mc.imr_multiaddr.s_addr = inet_addr(socket_name); mc.imr_interface.s_addr = INADDR_ANY; } if (broadcast) { if (setsockopt(serverfd, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast))) { perror("setsockopt"); close(serverfd); return -1; } } if (bind(serverfd, (struct sockaddr *) &uws_addr, sizeof(uws_addr)) != 0) { uwsgi_error("bind()"); close(serverfd); return -1; } if (multicast) { uwsgi_log("[uwsgi-mcast] joining multicast group: %s:%d\n", socket_name, ntohs(uws_addr.sin_port)); if (setsockopt(serverfd, IPPROTO_IP, IP_MULTICAST_LOOP, &uwsgi.multicast_loop, sizeof(uwsgi.multicast_loop))) { uwsgi_error("setsockopt()"); } if (setsockopt(serverfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mc, sizeof(mc))) { uwsgi_error("setsockopt()"); } if (setsockopt(serverfd, IPPROTO_IP, IP_MULTICAST_TTL, &uwsgi.multicast_ttl, sizeof(uwsgi.multicast_ttl))) { uwsgi_error("setsockopt()"); } } udp_port[0] = ':'; return serverfd; } static int uwsgi_connect_do(char *socket_name, int timeout, int async) { char *tcp_port = strchr(socket_name, ':'); if (tcp_port) { tcp_port[0] = 0; tcp_port++; return connect_to_tcp(socket_name, atoi(tcp_port), timeout, async); } return connect_to_unix(socket_name, timeout, async); } int uwsgi_connectn(char *socket_name, uint16_t len, int timeout, int async) { char *zeroed_socket_name = uwsgi_concat2n(socket_name, len, "", 0); int fd = uwsgi_connect_do(zeroed_socket_name, timeout, async); free(zeroed_socket_name); return fd; } int uwsgi_connect(char *socket_name, int timeout, int async) { char *zeroed_socket_name = uwsgi_str(socket_name); int fd = uwsgi_connect_do(zeroed_socket_name, timeout, async); free(zeroed_socket_name); return fd; } int uwsgi_connect_udp(char *socket_name) { int fd = -1; char *zeroed_socket_name = uwsgi_str(socket_name); char *udp_port = strchr(zeroed_socket_name, ':'); if (!udp_port) goto end; *udp_port = 0; udp_port++; fd = connect_to_udp(zeroed_socket_name, atoi(udp_port)); end: free(zeroed_socket_name); return fd; } static int connect_to_unix(char *socket_name, int timeout, int async) { struct pollfd uwsgi_poll; struct sockaddr_un uws_addr; socklen_t un_size = sizeof(struct sockaddr_un); memset(&uws_addr, 0, sizeof(struct sockaddr_un)); uws_addr.sun_family = AF_UNIX; if (socket_name[0] == '@') { un_size = sizeof(uws_addr.sun_family) + strlen(socket_name) + 1; memcpy(uws_addr.sun_path + 1, socket_name + 1, UMIN(strlen(socket_name + 1), 101)); } else if (strlen(socket_name) > 1 && socket_name[0] == '\\' && socket_name[1] == '0') { un_size = sizeof(uws_addr.sun_family) + strlen(socket_name + 1) + 1; memcpy(uws_addr.sun_path + 1, socket_name + 2, UMIN(strlen(socket_name + 2), 101)); } else { memcpy(uws_addr.sun_path, socket_name, UMIN(strlen(socket_name), 102)); } #if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL) uwsgi_poll.fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); #else uwsgi_poll.fd = socket(AF_UNIX, SOCK_STREAM, 0); #endif if (uwsgi_poll.fd < 0) { uwsgi_error("socket()"); return -1; } uwsgi_poll.events = POLLIN; if (timed_connect(&uwsgi_poll, (const struct sockaddr *) &uws_addr, un_size, timeout, async)) { // avoid error storm //uwsgi_error("connect()"); close(uwsgi_poll.fd); return -1; } return uwsgi_poll.fd; } static int connect_to_tcp(char *socket_name, int port, int timeout, int async) { struct pollfd uwsgi_poll; struct sockaddr_in uws_addr; memset(&uws_addr, 0, sizeof(struct sockaddr_in)); uws_addr.sin_family = AF_INET; uws_addr.sin_port = htons(port); if (socket_name[0] == 0) { uws_addr.sin_addr.s_addr = INADDR_ANY; } else { uws_addr.sin_addr.s_addr = inet_addr(socket_name); } #if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL) uwsgi_poll.fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); #else uwsgi_poll.fd = socket(AF_INET, SOCK_STREAM, 0); #endif if (uwsgi_poll.fd < 0) { uwsgi_error("connect_to_tcp()/socket()"); return -1; } uwsgi_poll.events = POLLIN; if (timed_connect(&uwsgi_poll, (const struct sockaddr *) &uws_addr, sizeof(struct sockaddr_in), timeout, async)) { //uwsgi_error("connect()"); close(uwsgi_poll.fd); return -1; } return uwsgi_poll.fd; } static int connect_to_udp(char *socket_name, int port) { struct sockaddr_in uws_addr; memset(&uws_addr, 0, sizeof(struct sockaddr_in)); uws_addr.sin_family = AF_INET; uws_addr.sin_port = htons(port); if (socket_name[0] == 0) { uws_addr.sin_addr.s_addr = INADDR_ANY; } else { uws_addr.sin_addr.s_addr = inet_addr(socket_name); } int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { uwsgi_error("connect_to_udp()/socket()"); return -1; } if (connect(fd, (const struct sockaddr *) &uws_addr, sizeof(struct sockaddr_in))) { close(fd); return -1; } return fd; } char *generate_socket_name(char *socket_name) { char *asterisk = strchr(socket_name, '*'); char *tcp_port; int i; char *ptr = socket_name; // ltrim spaces for (i = 0; i < (int) strlen(socket_name); i++) { if (isspace((int) socket_name[i])) { ptr++; } else { break; } } socket_name = ptr; if (socket_name[0] == 0) { uwsgi_log("invalid/empty uwsgi socket name\n"); exit(1); } tcp_port = strchr(socket_name, ':'); if (!tcp_port) return socket_name; if (asterisk) { #ifndef UWSGI_HAS_IFADDRS uwsgi_log("your system does not support ifaddrs subsystem\n"); #else char *new_socket; #ifdef UWSGI_DEBUG uwsgi_log("generate_socket_name(%s)\n", socket_name); #endif // get all the AF_INET addresses available struct ifaddrs *ifap = NULL, *ifa, *ifaf; if (getifaddrs(&ifap)) { uwsgi_error("getifaddrs()"); uwsgi_nuclear_blast(); } // here socket_name will be truncated asterisk[0] = 0; #ifdef UWSGI_DEBUG uwsgi_log("asterisk found\n"); #endif char new_addr[16]; struct sockaddr_in *sin; ifa = ifap; while (ifa) { memset(new_addr, 0, 16); if (!ifa->ifa_addr) goto next; sin = (struct sockaddr_in *) ifa->ifa_addr; if (inet_ntop(AF_INET, (void *) &sin->sin_addr.s_addr, new_addr, 16)) { if (!strncmp(socket_name, new_addr, strlen(socket_name))) { asterisk[0] = '*'; new_socket = uwsgi_concat3(new_addr, ":", tcp_port + 1); uwsgi_log("[uwsgi-autoip] found %s for %s on interface %s\n", new_socket, socket_name, ifa->ifa_name); freeifaddrs(ifap); return new_socket; } } next: ifaf = ifa; ifa = ifaf->ifa_next; } uwsgi_log("unable to find a valid socket address\n"); #endif uwsgi_nuclear_blast(); } return socket_name; } socklen_t socket_to_un_addr(char *socket_name, struct sockaddr_un * sun_addr) { size_t len = strlen(socket_name); if (len > 102) { uwsgi_log("invalid UNIX socket address: %s\n", socket_name); uwsgi_nuclear_blast(); } memset(sun_addr, 0, sizeof(struct sockaddr_un)); sun_addr->sun_family = AF_UNIX; // abstract socket if (socket_name[0] == '@') { memcpy(sun_addr->sun_path + 1, socket_name + 1, UMIN(len - 1, 101)); len = strlen(socket_name) + 1; } else if (len > 1 && socket_name[0] == '\\' && socket_name[1] == '0') { memcpy(sun_addr->sun_path + 1, socket_name + 2, UMIN(len - 2, 101)); len = strlen(socket_name + 1) + 1; } else { memcpy(sun_addr->sun_path, socket_name, UMIN(len, 102)); } return sizeof(sun_addr->sun_family) + len; } socklen_t socket_to_in_addr(char *socket_name, char *port, int portn, struct sockaddr_in *sin_addr) { memset(sin_addr, 0, sizeof(struct sockaddr_in)); sin_addr->sin_family = AF_INET; if (port) { *port = 0; sin_addr->sin_port = htons(atoi(port + 1)); } else { sin_addr->sin_port = htons(portn); } if (socket_name[0] == 0) { sin_addr->sin_addr.s_addr = INADDR_ANY; } else { char *resolved = uwsgi_resolve_ip(socket_name); if (resolved) { sin_addr->sin_addr.s_addr = inet_addr(resolved); } else { sin_addr->sin_addr.s_addr = inet_addr(socket_name); } } if (port) { *port = ':'; } return sizeof(struct sockaddr_in); } int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) { int serverfd; #ifdef AF_INET6 struct sockaddr_in6 uws_addr; #else struct sockaddr_in uws_addr; #endif int family = AF_INET; socklen_t addr_len = sizeof(struct sockaddr_in); #ifdef AF_INET6 if (socket_name[0] == '[' && tcp_port[-1] == ']') { family = AF_INET6; socket_to_in_addr6(socket_name, tcp_port, 0, &uws_addr); addr_len = sizeof(struct sockaddr_in6); } else { #endif socket_to_in_addr(socket_name, tcp_port, 0, (struct sockaddr_in *) &uws_addr); #ifdef AF_INET6 } #endif serverfd = create_server_socket(family, SOCK_STREAM); if (serverfd < 0) return -1; #ifdef __linux__ #ifndef IP_FREEBIND #define IP_FREEBIND 15 #endif if (uwsgi.freebind) { if (setsockopt(serverfd, SOL_IP, IP_FREEBIND, (const void *) &uwsgi.freebind, sizeof(int)) < 0) { uwsgi_error("IP_FREEBIND setsockopt()"); uwsgi_nuclear_blast(); return -1; } } #endif if (uwsgi.reuse_port) { #ifdef SO_REUSEPORT if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEPORT, (const void *) &uwsgi.reuse_port, sizeof(int)) < 0) { uwsgi_error("SO_REUSEPORT setsockopt()"); uwsgi_nuclear_blast(); return -1; } #else uwsgi_log("!!! your system does not support SO_REUSEPORT !!!\n"); #endif } if (uwsgi.tcp_fast_open) { #ifdef TCP_FASTOPEN #ifndef SOL_TCP #define SOL_TCP IPPROTO_TCP #endif if (setsockopt(serverfd, SOL_TCP, TCP_FASTOPEN, (const void *) &uwsgi.tcp_fast_open, sizeof(int)) < 0) { uwsgi_error("TCP_FASTOPEN setsockopt()"); } else { uwsgi_log("TCP_FASTOPEN enabled on %s\n", socket_name); } #else uwsgi_log("!!! your system does not support TCP_FASTOPEN !!!\n"); #endif } if (uwsgi.so_send_timeout) { struct timeval tv; tv.tv_sec = uwsgi.so_send_timeout; tv.tv_usec = 0; if (setsockopt(serverfd, SOL_SOCKET, SO_SNDTIMEO, (const void *) &tv, sizeof(struct timeval)) < 0) { uwsgi_error("SO_SNDTIMEO setsockopt()"); uwsgi_nuclear_blast(); return -1; } } if (!uwsgi.no_defer_accept) { #ifdef __linux__ if (setsockopt(serverfd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &uwsgi.socket_timeout, sizeof(int))) { uwsgi_error("TCP_DEFER_ACCEPT setsockopt()"); } // OSX has no SO_ACCEPTFILTER !!! #elif defined(__freebsd__) struct accept_filter_arg afa; strcpy(afa.af_name, "dataready"); afa.af_arg[0] = 0; if (setsockopt(serverfd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(struct accept_filter_arg))) { uwsgi_error("SO_ACCEPTFILTER setsockopt()"); } #endif } if (uwsgi.so_keepalive) { if (setsockopt(serverfd, SOL_SOCKET, SO_KEEPALIVE, &uwsgi.so_keepalive, sizeof(int))) { uwsgi_error("SO_KEEPALIVE setsockopt()"); } } if (bind(serverfd, (struct sockaddr *) &uws_addr, addr_len) != 0) { if (errno == EADDRINUSE) { uwsgi_log("probably another instance of uWSGI is running on the same address (%s).\n", socket_name); } uwsgi_error("bind()"); uwsgi_nuclear_blast(); return -1; } if (listen(serverfd, listen_queue) != 0) { uwsgi_error("listen()"); uwsgi_nuclear_blast(); return -1; } if (tcp_port) tcp_port[0] = ':'; return serverfd; } // set non-blocking socket void uwsgi_socket_nb(int fd) { int arg; arg = fcntl(fd, F_GETFL, NULL); if (arg < 0) { uwsgi_error("fcntl()"); return; } arg |= O_NONBLOCK; if (fcntl(fd, F_SETFL, arg) < 0) { uwsgi_error("fcntl()"); return; } } // set blocking socket void uwsgi_socket_b(int fd) { int arg; arg = fcntl(fd, F_GETFL, NULL); if (arg < 0) { uwsgi_error("fcntl()"); return; } arg &= (~O_NONBLOCK); if (fcntl(fd, F_SETFL, arg) < 0) { uwsgi_error("fcntl()"); return; } } int timed_connect(struct pollfd *fdpoll, const struct sockaddr *addr, int addr_size, int timeout, int async) { int ret; int soopt = 0; socklen_t solen = sizeof(int); int cnt; /* set non-blocking socket */ #if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL) // hmm, nothing to do, as we are already non-blocking #else int arg = fcntl(fdpoll->fd, F_GETFL, NULL); if (arg < 0) { uwsgi_error("fcntl()"); return -1; } arg |= O_NONBLOCK; if (fcntl(fdpoll->fd, F_SETFL, arg) < 0) { uwsgi_error("fcntl()"); return -1; } #endif #ifdef MSG_FASTOPEN if (addr->sa_family == AF_INET && uwsgi.tcp_fast_open_client) { ret = sendto(fdpoll->fd, "", 0, MSG_FASTOPEN, addr, addr_size); } else { #endif ret = connect(fdpoll->fd, addr, addr_size); #ifdef MSG_FASTOPEN } #endif if (async) { if (ret < 0 && errno != EINPROGRESS) { return -1; } return 0; } #if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL) uwsgi_socket_b(fdpoll->fd); #else /* re-set blocking socket */ arg &= (~O_NONBLOCK); if (fcntl(fdpoll->fd, F_SETFL, arg) < 0) { uwsgi_error("fcntl()"); return -1; } #endif if (ret < 0) { /* check what happened */ // in progress ? if (errno == EINPROGRESS) { if (timeout < 1) timeout = 3; fdpoll->events = POLLOUT; cnt = poll(fdpoll, 1, timeout * 1000); /* check for errors */ if (cnt < 0 && errno != EINTR) { uwsgi_error("poll()"); return -1; } /* something hapened on the socket ... */ else if (cnt > 0) { if (getsockopt(fdpoll->fd, SOL_SOCKET, SO_ERROR, (void *) (&soopt), &solen) < 0) { uwsgi_error("getsockopt()"); return -1; } /* is something bad ? */ if (soopt) { return -1; } } /* timeout */ else { return -1; } } else { return -1; } } return 0; } int uwsgi_count_sockets(struct uwsgi_socket *uwsgi_sock) { int count = 0; while (uwsgi_sock) { count++; uwsgi_sock = uwsgi_sock->next; } return count; } int uwsgi_get_socket_num(struct uwsgi_socket *uwsgi_sock) { int count = 0; struct uwsgi_socket *current_sock = uwsgi.sockets; while (current_sock) { if (uwsgi_sock == current_sock) { return count; } count++; current_sock = current_sock->next; } return -1; } int uwsgi_get_shared_socket_num(struct uwsgi_socket *uwsgi_sock) { int count = 0; struct uwsgi_socket *current_sock = uwsgi.shared_sockets; while (current_sock) { if (uwsgi_sock == current_sock) { return count; } count++; current_sock = current_sock->next; } return -1; } struct uwsgi_socket *uwsgi_new_shared_socket(char *name) { struct uwsgi_socket *uwsgi_sock = uwsgi.shared_sockets, *old_uwsgi_sock; if (!uwsgi_sock) { uwsgi.shared_sockets = uwsgi_malloc(sizeof(struct uwsgi_socket)); uwsgi_sock = uwsgi.shared_sockets; } else { while (uwsgi_sock) { old_uwsgi_sock = uwsgi_sock; uwsgi_sock = uwsgi_sock->next; } uwsgi_sock = uwsgi_malloc(sizeof(struct uwsgi_socket)); old_uwsgi_sock->next = uwsgi_sock; } memset(uwsgi_sock, 0, sizeof(struct uwsgi_socket)); uwsgi_sock->name = name; uwsgi_sock->fd = -1; return uwsgi_sock; } struct uwsgi_socket *uwsgi_new_socket(char *name) { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets, *old_uwsgi_sock; struct sockaddr_in sin; socklen_t socket_type_len; if (!uwsgi_sock) { uwsgi.sockets = uwsgi_malloc(sizeof(struct uwsgi_socket)); uwsgi_sock = uwsgi.sockets; } else { while (uwsgi_sock) { old_uwsgi_sock = uwsgi_sock; uwsgi_sock = uwsgi_sock->next; } uwsgi_sock = uwsgi_malloc(sizeof(struct uwsgi_socket)); old_uwsgi_sock->next = uwsgi_sock; } memset(uwsgi_sock, 0, sizeof(struct uwsgi_socket)); uwsgi_sock->name = name; uwsgi_sock->fd = -1; if (!name) return uwsgi_sock; if (name[0] == '=') { int shared_socket = atoi(uwsgi_sock->name + 1); if (shared_socket >= 0) { struct uwsgi_socket *uss = uwsgi_get_shared_socket_by_num(shared_socket); if (!uss) { uwsgi_log("unable to use shared socket %d\n", shared_socket); exit(1); } uwsgi_sock->bound = 1; uwsgi_sock->shared = 1; uwsgi_sock->from_shared = shared_socket; return uwsgi_sock; } } if (!uwsgi_startswith(name, "fd://", 5)) { uwsgi_add_socket_from_fd(uwsgi_sock, atoi(name + 5)); return uwsgi_sock; } char *tcp_port = strrchr(name, ':'); if (tcp_port) { // INET socket, check for 0 port if (tcp_port[1] == 0 || tcp_port[1] == '0') { uwsgi_sock->fd = bind_to_tcp(name, uwsgi.listen_queue, tcp_port); uwsgi_sock->family = AF_INET; uwsgi_sock->bound = 1; uwsgi_sock->auto_port = 1; socket_type_len = sizeof(struct sockaddr_in); if (getsockname(uwsgi_sock->fd, (struct sockaddr *) &sin, &socket_type_len)) { uwsgi_error("getsockname()"); exit(1); } char *auto_port = uwsgi_num2str(ntohs(sin.sin_port)); uwsgi_sock->name = uwsgi_concat3n(name, tcp_port - name, ":", 1, auto_port, strlen(auto_port)); } // is it fd 0 ? else if (tcp_port[1] == ':') { uwsgi_sock->fd = 0; uwsgi_sock->family = AF_INET; uwsgi_sock->bound = 1; socket_type_len = sizeof(struct sockaddr_in); if (getsockname(0, (struct sockaddr *) &sin, &socket_type_len)) { uwsgi_error("getsockname()"); exit(1); } char *auto_port = uwsgi_num2str(ntohs(sin.sin_port)); char *auto_ip = inet_ntoa(sin.sin_addr); uwsgi_sock->name = uwsgi_concat3n(auto_ip, strlen(auto_ip), ":", 1, auto_port, strlen(auto_port)); free(auto_port); } } return uwsgi_sock; } void uwsgi_add_socket_from_fd(struct uwsgi_socket *uwsgi_sock, int fd) { socklen_t socket_type_len; union uwsgi_sockaddr_ptr gsa, isa; union uwsgi_sockaddr usa; int abstract = 0; memset(&usa, 0, sizeof(usa)); socket_type_len = sizeof(struct sockaddr_un); gsa.sa = &usa.sa; if (!getsockname(fd, gsa.sa, &socket_type_len)) { if (socket_type_len <= 2) { // unbound socket return; } if (gsa.sa->sa_family == AF_UNIX) { if (usa.sa_un.sun_path[0] == 0) abstract = 1; // is it a zerg ? if (uwsgi_sock->name == NULL) { uwsgi_sock->fd = fd; uwsgi_sock->family = AF_UNIX; uwsgi_sock->bound = 1; uwsgi_sock->name = uwsgi_concat2(usa.sa_un.sun_path + abstract, ""); if (uwsgi.zerg) { uwsgi_log("uwsgi zerg socket %d attached to UNIX address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), usa.sa_un.sun_path + abstract, uwsgi_sock->fd); } else { uwsgi_log("uwsgi socket %d attached to UNIX address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), usa.sa_un.sun_path + abstract, uwsgi_sock->fd); } return; } if (!uwsgi_startswith(uwsgi_sock->name, "fd://", 5)) { if (atoi(uwsgi_sock->name + 5) == fd) { uwsgi_sock->fd = fd; uwsgi_sock->family = AF_UNIX; uwsgi_sock->bound = 1; uwsgi_sock->name = uwsgi_str(usa.sa_un.sun_path + abstract); uwsgi_log("uwsgi socket %d inherited UNIX address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); } } else if (!strcmp(usa.sa_un.sun_path + abstract, uwsgi_sock->name + abstract)) { uwsgi_sock->fd = fd; uwsgi_sock->family = AF_UNIX; uwsgi_sock->bound = 1; uwsgi_log("uwsgi socket %d inherited UNIX address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); } } else if (gsa.sa->sa_family == AF_INET) { char *computed_addr; char computed_port[6]; isa.sa_in = (struct sockaddr_in *) &usa; char ipv4a[INET_ADDRSTRLEN + 1]; memset(ipv4a, 0, INET_ADDRSTRLEN + 1); memset(computed_port, 0, 6); if (snprintf(computed_port, 6, "%d", ntohs(isa.sa_in->sin_port)) > 0) { if (inet_ntop(AF_INET, (const void *) &isa.sa_in->sin_addr.s_addr, ipv4a, INET_ADDRSTRLEN)) { if (!strcmp("0.0.0.0", ipv4a)) { computed_addr = uwsgi_concat2(":", computed_port); } else { computed_addr = uwsgi_concat3(ipv4a, ":", computed_port); } // is it a zerg ? if (uwsgi_sock->name == NULL) { uwsgi_sock->fd = fd; uwsgi_sock->family = AF_INET; uwsgi_sock->bound = 1; uwsgi_sock->name = uwsgi_concat2(computed_addr, ""); if (uwsgi.zerg) { uwsgi_log("uwsgi zerg socket %d attached to INET address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), computed_addr, uwsgi_sock->fd); } else { uwsgi_log("uwsgi socket %d attached to INET address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), computed_addr, uwsgi_sock->fd); } free(computed_addr); return; } char *asterisk = strchr(uwsgi_sock->name, '*'); int match = 1; if (asterisk) { asterisk[0] = 0; match = strncmp(computed_addr, uwsgi_sock->name, strlen(uwsgi_sock->name)); asterisk[0] = '*'; } else { if (!uwsgi_startswith(uwsgi_sock->name, "fd://", 5)) { if (atoi(uwsgi_sock->name + 5) == fd) { uwsgi_sock->fd = fd; uwsgi_sock->family = AF_INET; uwsgi_sock->bound = 1; uwsgi_sock->name = uwsgi_str(computed_addr); uwsgi_log("uwsgi socket %d inherited INET address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); match = 1; } } else { match = uwsgi_socket_strcmp(computed_addr, uwsgi_sock->name); } } if (!match) { uwsgi_sock->fd = fd; uwsgi_sock->family = AF_INET; uwsgi_sock->bound = 1; uwsgi_log("uwsgi socket %d inherited INET address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); } free(computed_addr); } } } #ifdef AF_INET6 else if (gsa.sa->sa_family == AF_INET6) { char *computed_addr; char computed_port[6]; isa.sa_in6 = (struct sockaddr_in6 *) &usa; char ipv6a[INET6_ADDRSTRLEN + 1]; memset(ipv6a, 0, INET_ADDRSTRLEN + 1); memset(computed_port, 0, 6); int match = 0; if (snprintf(computed_port, 6, "%d", ntohs(isa.sa_in6->sin6_port)) > 0) { if (inet_ntop(AF_INET6, (const void *) &isa.sa_in6->sin6_addr.s6_addr, ipv6a, INET6_ADDRSTRLEN)) { uwsgi_log("ipv6a = %s\n", ipv6a); if (!strcmp("::", ipv6a)) { computed_addr = uwsgi_concat2("[::]:", computed_port); } else { computed_addr = uwsgi_concat4("[", ipv6a, "]:", computed_port); } // is it a zerg ? if (uwsgi_sock->name == NULL) { uwsgi_sock->fd = fd; uwsgi_sock->family = AF_INET6; uwsgi_sock->bound = 1; uwsgi_sock->name = uwsgi_concat2(computed_addr, ""); if (uwsgi.zerg) { uwsgi_log("uwsgi zerg socket %d attached to INET6 address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), computed_addr, uwsgi_sock->fd); } else { uwsgi_log("uwsgi socket %d attached to INET6 address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), computed_addr, uwsgi_sock->fd); } free(computed_addr); return; } if (!uwsgi_startswith(uwsgi_sock->name, "fd://", 5)) { if (atoi(uwsgi_sock->name + 5) == fd) { uwsgi_sock->fd = fd; uwsgi_sock->family = AF_INET6; uwsgi_sock->bound = 1; uwsgi_sock->name = uwsgi_str(computed_addr); uwsgi_log("uwsgi socket %d inherited INET address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); match = 1; } } else { match = strcmp(computed_addr, uwsgi_sock->name); } if (!match) { uwsgi_sock->fd = fd; uwsgi_sock->family = AF_INET; uwsgi_sock->bound = 1; uwsgi_log("uwsgi socket %d inherited INET6 address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); } free(computed_addr); } } } #endif } } void uwsgi_close_all_sockets() { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->bound) close(uwsgi_sock->fd); uwsgi_sock = uwsgi_sock->next; } } void uwsgi_shutdown_all_sockets() { uwsgi_log_verbose("shutting down all sockets...\n"); struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->bound) { shutdown(uwsgi_sock->fd, SHUT_RDWR); close(uwsgi_sock->fd); } uwsgi_sock = uwsgi_sock->next; } } void uwsgi_close_all_unshared_sockets() { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->bound && !uwsgi_sock->shared) close(uwsgi_sock->fd); uwsgi_sock = uwsgi_sock->next; } } struct uwsgi_socket *uwsgi_del_socket(struct uwsgi_socket *uwsgi_sock) { struct uwsgi_socket *uwsgi_current_sock = uwsgi.sockets, *old_sock = NULL; while (uwsgi_current_sock) { if (uwsgi_current_sock == uwsgi_sock) { // parent instance ? if (old_sock == NULL) { uwsgi.sockets = uwsgi_current_sock->next; free(uwsgi_current_sock); return uwsgi.sockets; } else { old_sock->next = uwsgi_current_sock->next; free(uwsgi_current_sock); return old_sock->next; } } old_sock = uwsgi_current_sock; uwsgi_current_sock = uwsgi_current_sock->next; } return NULL; } int uwsgi_get_shared_socket_fd_by_num(int num) { int counter = 0; struct uwsgi_socket *found_sock = NULL, *uwsgi_sock = uwsgi.shared_sockets; while (uwsgi_sock) { if (counter == num) { found_sock = uwsgi_sock; break; } counter++; uwsgi_sock = uwsgi_sock->next; } if (found_sock) { return found_sock->fd; } return -1; } struct uwsgi_socket *uwsgi_get_shared_socket_by_num(int num) { int counter = 0; struct uwsgi_socket *found_sock = NULL, *uwsgi_sock = uwsgi.shared_sockets; while (uwsgi_sock) { if (counter == num) { found_sock = uwsgi_sock; break; } counter++; uwsgi_sock = uwsgi_sock->next; } if (found_sock) { return found_sock; } return NULL; } struct uwsgi_socket *uwsgi_get_socket_by_num(int num) { int counter = 0; struct uwsgi_socket *found_sock = NULL, *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (counter == num) { found_sock = uwsgi_sock; break; } counter++; uwsgi_sock = uwsgi_sock->next; } if (found_sock) { return found_sock; } return NULL; } void uwsgi_add_sockets_to_queue(int queue, int async_id) { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->fd_threads && async_id > -1 && uwsgi_sock->fd_threads[async_id] > -1) { event_queue_add_fd_read(queue, uwsgi_sock->fd_threads[async_id]); } else if (uwsgi_sock->fd > -1) { event_queue_add_fd_read(queue, uwsgi_sock->fd); } uwsgi_sock = uwsgi_sock->next; } } void uwsgi_del_sockets_from_queue(int queue) { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->fd == -1) goto nextsock; event_queue_del_fd(queue, uwsgi_sock->fd, event_queue_read()); nextsock: uwsgi_sock = uwsgi_sock->next; } } int uwsgi_is_bad_connection(int fd) { int soopt = 0; socklen_t solen = sizeof(int); if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *) (&soopt), &solen) < 0) { return -1; } // will be 0 if all ok return soopt; } int uwsgi_socket_is_already_bound(char *name) { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->name && !strcmp(uwsgi_sock->name, name) && uwsgi_sock->bound) { return 1; } uwsgi_sock = uwsgi_sock->next; } return 0; } int uwsgi_socket_uniq(struct uwsgi_socket *list, struct uwsgi_socket *item) { int found = 0; if (list == item) return 0; struct uwsgi_socket *uwsgi_sock = list; while (uwsgi_sock && uwsgi_sock != item) { if (uwsgi_sock->fd == -1) goto nextsock; if (!strcmp(uwsgi_sock->name, item->name)) { found = 1; break; } nextsock: uwsgi_sock = uwsgi_sock->next; } return found; } void uwsgi_manage_zerg(int fd, int num_sockets, int *sockets) { struct sockaddr_un zsun; socklen_t zsun_len = sizeof(struct sockaddr_un); int zerg_client = accept(fd, (struct sockaddr *) &zsun, &zsun_len); if (zerg_client < 0) { uwsgi_error("zerg: accept()"); return; } if (!num_sockets) { num_sockets = uwsgi_count_sockets(uwsgi.sockets); } struct msghdr zerg_msg; void *zerg_msg_control = uwsgi_malloc(CMSG_SPACE(sizeof(int) * num_sockets)); struct iovec zerg_iov[2]; struct cmsghdr *cmsg; zerg_iov[0].iov_base = "uwsgi-zerg"; zerg_iov[0].iov_len = 10; zerg_iov[1].iov_base = &num_sockets; zerg_iov[1].iov_len = sizeof(int); zerg_msg.msg_name = NULL; zerg_msg.msg_namelen = 0; zerg_msg.msg_iov = zerg_iov; zerg_msg.msg_iovlen = 2; zerg_msg.msg_flags = 0; zerg_msg.msg_control = zerg_msg_control; zerg_msg.msg_controllen = CMSG_SPACE(sizeof(int) * num_sockets); cmsg = CMSG_FIRSTHDR(&zerg_msg); cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_sockets); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; unsigned char *zerg_fd_ptr = CMSG_DATA(cmsg); if (!sockets) { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; int uniq_count = 0; while (uwsgi_sock) { if (uwsgi_sock->fd == -1) goto nextsock; if (!uwsgi_socket_uniq(uwsgi.sockets, uwsgi_sock)) { memcpy(zerg_fd_ptr, &uwsgi_sock->fd, sizeof(int)); zerg_fd_ptr += sizeof(int); uniq_count++; } nextsock: uwsgi_sock = uwsgi_sock->next; } zerg_iov[1].iov_base = &uniq_count; cmsg->cmsg_len = CMSG_LEN(sizeof(int) * uniq_count); } else { memcpy(zerg_fd_ptr, sockets, sizeof(int) * num_sockets); } if (sendmsg(zerg_client, &zerg_msg, 0) < 0) { uwsgi_error("sendmsg()"); } free(zerg_msg_control); close(zerg_client); } #ifdef AF_INET6 socklen_t socket_to_in_addr6(char *socket_name, char *port, int portn, struct sockaddr_in6 * sin_addr) { memset(sin_addr, 0, sizeof(struct sockaddr_in6)); sin_addr->sin6_family = AF_INET6; if (port) { *port = 0; sin_addr->sin6_port = htons(atoi(port + 1)); } else { sin_addr->sin6_port = htons(portn); } if (!strcmp(socket_name, "[::]")) { sin_addr->sin6_addr = in6addr_any; } else { char *sanitized_sn = uwsgi_concat2n(socket_name + 1, strlen(socket_name + 1) - 1, "", 0); char *resolved = uwsgi_resolve_ip(sanitized_sn); if (resolved) { inet_pton(AF_INET6, resolved, sin_addr->sin6_addr.s6_addr); } else { inet_pton(AF_INET6, sanitized_sn, sin_addr->sin6_addr.s6_addr); } free(sanitized_sn); } if (port) { *port = ':'; } return sizeof(struct sockaddr_in6); } #endif void uwsgi_setup_shared_sockets() { int i; struct uwsgi_socket *shared_sock = uwsgi.shared_sockets; while (shared_sock) { if (!uwsgi.is_a_reload) { char *tcp_port = strrchr(shared_sock->name, ':'); int current_defer_accept = uwsgi.no_defer_accept; if (shared_sock->no_defer) { uwsgi.no_defer_accept = 1; } if (tcp_port == NULL) { shared_sock->fd = bind_to_unix(shared_sock->name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); shared_sock->family = AF_UNIX; uwsgi_log("uwsgi shared socket %d bound to UNIX address %s fd %d\n", uwsgi_get_shared_socket_num(shared_sock), shared_sock->name, shared_sock->fd); if (uwsgi.chown_socket) { uwsgi_chown(shared_sock->name, uwsgi.chown_socket); } } else { #ifdef AF_INET6 if (shared_sock->name[0] == '[' && tcp_port[-1] == ']') { shared_sock->fd = bind_to_tcp(shared_sock->name, uwsgi.listen_queue, tcp_port); shared_sock->family = AF_INET6; // fix socket name shared_sock->name = uwsgi_getsockname(shared_sock->fd); uwsgi_log("uwsgi shared socket %d bound to TCP6 address %s fd %d\n", uwsgi_get_shared_socket_num(shared_sock), shared_sock->name, shared_sock->fd); } else { #endif shared_sock->fd = bind_to_tcp(shared_sock->name, uwsgi.listen_queue, tcp_port); shared_sock->family = AF_INET; // fix socket name shared_sock->name = uwsgi_getsockname(shared_sock->fd); uwsgi_log("uwsgi shared socket %d bound to TCP address %s fd %d\n", uwsgi_get_shared_socket_num(shared_sock), shared_sock->name, shared_sock->fd); #ifdef AF_INET6 } #endif } if (shared_sock->fd < 0) { uwsgi_log("unable to create shared socket on: %s\n", shared_sock->name); exit(1); } if (shared_sock->no_defer) { uwsgi.no_defer_accept = current_defer_accept; } } else { for (i = 3; i < (int) uwsgi.max_fd; i++) { char *sock = uwsgi_getsockname(i); if (sock) { if (!uwsgi_socket_strcmp(sock, shared_sock->name)) { if (strchr(sock, ':')) { uwsgi_log("uwsgi shared socket %d inherited TCP address %s fd %d\n", uwsgi_get_shared_socket_num(shared_sock), sock, i); shared_sock->family = AF_INET; } else { uwsgi_log("uwsgi shared socket %d inherited UNIX address %s fd %d\n", uwsgi_get_shared_socket_num(shared_sock), sock, i); shared_sock->family = AF_UNIX; } shared_sock->fd = i; } free(sock); } } } shared_sock->bound = 1; shared_sock = shared_sock->next; } struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->shared) { shared_sock = uwsgi_get_shared_socket_by_num(uwsgi_sock->from_shared); if (!shared_sock) { uwsgi_log("unable to find shared socket %d\n", uwsgi_sock->from_shared); exit(1); } uwsgi_sock->fd = shared_sock->fd; uwsgi_sock->family = shared_sock->family; uwsgi_sock->name = shared_sock->name; uwsgi_log("uwsgi socket %d mapped to shared socket %d (%s) fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_get_shared_socket_num(shared_sock), shared_sock->name, uwsgi_sock->fd); } uwsgi_sock = uwsgi_sock->next; } } void uwsgi_map_sockets() { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { struct uwsgi_string_list *usl = uwsgi.map_socket; int enabled = 1; while (usl) { char *colon = strchr(usl->value, ':'); if (!colon) { uwsgi_log("invalid socket mapping, must be socket:worker[,worker...]\n"); exit(1); } if ((int) uwsgi_str_num(usl->value, colon - usl->value) == uwsgi_get_socket_num(uwsgi_sock)) { enabled = 0; char *p, *ctx = NULL; uwsgi_foreach_token(colon + 1, ",", p, ctx) { int w = atoi(p); if (w < 1 || w > uwsgi.numproc) { uwsgi_log("invalid worker num: %d\n", w); exit(1); } if (w == uwsgi.mywid) { enabled = 1; uwsgi_log("mapped socket %d (%s) to worker %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi.mywid); break; } } } usl = usl->next; } if (!enabled) { close(uwsgi_sock->fd); uwsgi_remap_fd(uwsgi_sock->fd, "/dev/null"); uwsgi_sock->disabled = 1; } uwsgi_sock = uwsgi_sock->next; } uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->disabled) { uwsgi_sock = uwsgi_del_socket(uwsgi_sock); } else { uwsgi_sock = uwsgi_sock->next; } } } void uwsgi_bind_sockets() { socklen_t socket_type_len; union uwsgi_sockaddr usa; union uwsgi_sockaddr_ptr gsa; struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (!uwsgi_sock->bound && !uwsgi_socket_is_already_bound(uwsgi_sock->name)) { char *tcp_port = strrchr(uwsgi_sock->name, ':'); int current_defer_accept = uwsgi.no_defer_accept; if (uwsgi_sock->no_defer) { uwsgi.no_defer_accept = 1; } if (tcp_port == NULL) { uwsgi_sock->fd = bind_to_unix(uwsgi_sock->name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); uwsgi_sock->family = AF_UNIX; if (uwsgi.chown_socket) { uwsgi_chown(uwsgi_sock->name, uwsgi.chown_socket); } uwsgi_log("uwsgi socket %d bound to UNIX address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); struct stat st; if (uwsgi_sock->name[0] != '@' && !stat(uwsgi_sock->name, &st)) { uwsgi_sock->inode = st.st_ino; } } else { #ifdef AF_INET6 if (uwsgi_sock->name[0] == '[' && tcp_port[-1] == ']') { uwsgi_sock->fd = bind_to_tcp(uwsgi_sock->name, uwsgi.listen_queue, tcp_port); uwsgi_log("uwsgi socket %d bound to TCP6 address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); uwsgi_sock->family = AF_INET6; } else { #endif uwsgi_sock->fd = bind_to_tcp(uwsgi_sock->name, uwsgi.listen_queue, tcp_port); uwsgi_log("uwsgi socket %d bound to TCP address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); uwsgi_sock->family = AF_INET; #ifdef AF_INET6 } #endif } if (uwsgi_sock->fd < 0 && !uwsgi_sock->per_core) { uwsgi_log("unable to create server socket on: %s\n", uwsgi_sock->name); exit(1); } uwsgi.no_defer_accept = current_defer_accept; } uwsgi_sock->bound = 1; uwsgi_sock = uwsgi_sock->next; } int zero_used = 0; uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->bound && uwsgi_sock->fd == 0) { zero_used = 1; break; } uwsgi_sock = uwsgi_sock->next; } if (!zero_used) { socket_type_len = sizeof(struct sockaddr_un); gsa.sa = (struct sockaddr *) &usa; if (!uwsgi.skip_zero && !getsockname(0, gsa.sa, &socket_type_len)) { if (gsa.sa->sa_family == AF_UNIX) { uwsgi_sock = uwsgi_new_socket(uwsgi_getsockname(0)); uwsgi_sock->family = AF_UNIX; uwsgi_sock->fd = 0; uwsgi_sock->bound = 1; uwsgi_log("uwsgi socket %d inherited UNIX address %s fd 0\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name); if (!uwsgi.is_a_reload) { if (uwsgi.chown_socket) { uwsgi_chown(uwsgi_sock->name, uwsgi.chown_socket); } if (uwsgi.chmod_socket) { if (uwsgi.chmod_socket_value) { if (chmod(uwsgi_sock->name, uwsgi.chmod_socket_value) != 0) { uwsgi_error("inherit fd0: chmod()"); } } else { uwsgi_log("chmod() fd0 socket to 666 for lazy and brave users\n"); if (chmod(uwsgi_sock->name, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) != 0) { uwsgi_error("inherit fd0: chmod()"); } } } } } else { uwsgi_sock = uwsgi_new_socket(uwsgi_getsockname(0)); uwsgi_sock->family = AF_INET; uwsgi_sock->fd = 0; uwsgi_sock->bound = 1; uwsgi_log("uwsgi socket %d inherited INET address %s fd 0\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name); } } else if (!uwsgi.honour_stdin) { int fd = open("/dev/null", O_RDONLY); if (fd < 0) { uwsgi_error_open("/dev/null"); uwsgi_log("WARNING: unable to remap stdin, /dev/null not available\n"); goto stdin_done; } if (fd != 0) { if (dup2(fd, 0) < 0) { uwsgi_error("dup2()"); exit(1); } close(fd); } } else if (uwsgi.honour_stdin) { if (!tcgetattr(0, &uwsgi.termios)) { uwsgi.restore_tc = 1; } } } stdin_done: // check for auto_port socket uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->auto_port) { #ifdef AF_INET6 if (uwsgi_sock->family == AF_INET6) { uwsgi_log("uwsgi socket %d bound to TCP6 address %s (port auto-assigned) fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); } else { #endif uwsgi_log("uwsgi socket %d bound to TCP address %s (port auto-assigned) fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); #ifdef AF_INET6 } #endif } uwsgi_sock = uwsgi_sock->next; } } void uwsgi_set_sockets_protocols() { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { char *requested_protocol = uwsgi_sock->proto_name; if (uwsgi_sock->lazy) goto setup_proto; if (!uwsgi_sock->bound || uwsgi_sock->fd == -1) goto nextsock; if (!uwsgi_sock->per_core) { uwsgi_sock->arg = fcntl(uwsgi_sock->fd, F_GETFL, NULL); if (uwsgi_sock->arg < 0) { uwsgi_error("fcntl()"); exit(1); } uwsgi_sock->arg |= O_NONBLOCK; if (fcntl(uwsgi_sock->fd, F_SETFL, uwsgi_sock->arg) < 0) { uwsgi_error("fcntl()"); exit(1); } } setup_proto: if (!requested_protocol) requested_protocol = uwsgi.protocol; uwsgi_socket_setup_protocol(uwsgi_sock, requested_protocol); nextsock: uwsgi_sock = uwsgi_sock->next; } } void uwsgi_tcp_nodelay(int fd) { #ifdef TCP_NODELAY int flag = 1; if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int))) { uwsgi_error("uwsgi_tcp_nodelay()/setsockopt()"); } #endif } int uwsgi_accept(int server_fd) { struct sockaddr_un client_src; memset(&client_src, 0, sizeof(struct sockaddr_un)); socklen_t client_src_len = 0; #if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL) return accept4(server_fd, (struct sockaddr *) &client_src, &client_src_len, SOCK_NONBLOCK); #elif defined(__linux__) int client_fd = accept(server_fd, (struct sockaddr *) &client_src, &client_src_len); if (client_fd >= 0) { uwsgi_socket_nb(client_fd); } return client_fd; #else return accept(server_fd, (struct sockaddr *) &client_src, &client_src_len); #endif } struct uwsgi_protocol *uwsgi_register_protocol(char *name, void (*func)(struct uwsgi_socket *)) { struct uwsgi_protocol *old_up = NULL, *up = uwsgi.protocols; while(up) { if (!strcmp(name, up->name)) { goto found; } old_up = up; up = up->next; } up = uwsgi_calloc(sizeof(struct uwsgi_protocol)); up->name = name; if (old_up) { old_up->next = up; } else { uwsgi.protocols = up; } found: up->func = func; return up; } int uwsgi_socket_passcred(int fd) { #ifdef SO_PASSCRED int optval = 1; if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) < 0) { uwsgi_error("uwsgi_socket_passcred()/setsockopt()"); return -1; } return 0; #else return -1; #endif } void uwsgi_protocols_register() { uwsgi_register_protocol("uwsgi", uwsgi_proto_uwsgi_setup); uwsgi_register_protocol("puwsgi", uwsgi_proto_puwsgi_setup); uwsgi_register_protocol("http", uwsgi_proto_http_setup); uwsgi_register_protocol("http11", uwsgi_proto_http11_setup); #ifdef UWSGI_SSL uwsgi_register_protocol("suwsgi", uwsgi_proto_suwsgi_setup); uwsgi_register_protocol("https", uwsgi_proto_https_setup); #endif uwsgi_register_protocol("fastcgi", uwsgi_proto_fastcgi_setup); uwsgi_register_protocol("fastcgi-nph", uwsgi_proto_fastcgi_nph_setup); uwsgi_register_protocol("scgi", uwsgi_proto_scgi_setup); uwsgi_register_protocol("scgi-nph", uwsgi_proto_scgi_nph_setup); uwsgi_register_protocol("raw", uwsgi_proto_raw_setup); } uwsgi-2.0.29/core/spooler.c000066400000000000000000000414531477626554400155540ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; static void spooler_readdir(struct uwsgi_spooler *, char *dir); #ifdef __linux__ static void spooler_scandir(struct uwsgi_spooler *, char *dir); #endif static void spooler_manage_task(struct uwsgi_spooler *, char *, char *); // increment it whenever a signal is raised static uint64_t wakeup = 0; // function to allow waking up the spooler if blocked in event_wait void spooler_wakeup(int signum) { wakeup++; } void uwsgi_opt_add_spooler(char *opt, char *directory, void *mode) { int i; struct uwsgi_spooler *us; if (access(directory, R_OK | W_OK | X_OK) && mkdir(directory, S_IRWXU | S_IXGRP | S_IRGRP)) { uwsgi_error("[spooler directory] access()"); exit(1); } if (uwsgi.spooler_numproc > 0) { for (i = 0; i < uwsgi.spooler_numproc; i++) { us = uwsgi_new_spooler(directory); if (mode) us->mode = (long) mode; } } else { us = uwsgi_new_spooler(directory); if (mode) us->mode = (long) mode; } } struct uwsgi_spooler *uwsgi_new_spooler(char *dir) { struct uwsgi_spooler *uspool = uwsgi.spoolers; if (!uspool) { uwsgi.spoolers = uwsgi_calloc_shared(sizeof(struct uwsgi_spooler)); uspool = uwsgi.spoolers; } else { while (uspool) { if (uspool->next == NULL) { uspool->next = uwsgi_calloc_shared(sizeof(struct uwsgi_spooler)); uspool = uspool->next; break; } uspool = uspool->next; } } if (!realpath(dir, uspool->dir)) { uwsgi_error("[spooler] realpath()"); exit(1); } uspool->next = NULL; return uspool; } struct uwsgi_spooler *uwsgi_get_spooler_by_name(char *name, size_t name_len) { struct uwsgi_spooler *uspool = uwsgi.spoolers; while (uspool) { if (!uwsgi_strncmp(uspool->dir, strlen(uspool->dir), name, name_len)) { return uspool; } uspool = uspool->next; } return NULL; } pid_t spooler_start(struct uwsgi_spooler * uspool) { int i; pid_t pid = uwsgi_fork("uWSGI spooler"); if (pid < 0) { uwsgi_error("fork()"); exit(1); } else if (pid == 0) { signal(SIGALRM, SIG_IGN); signal(SIGHUP, SIG_IGN); signal(SIGINT, end_me); signal(SIGTERM, end_me); // USR1 will be used to wake up the spooler uwsgi_unix_signal(SIGUSR1, spooler_wakeup); signal(SIGUSR2, SIG_IGN); signal(SIGPIPE, SIG_IGN); signal(SIGSTOP, SIG_IGN); signal(SIGTSTP, SIG_IGN); uwsgi.mypid = getpid(); uspool->pid = uwsgi.mypid; // avoid race conditions !!! uwsgi.i_am_a_spooler = uspool; uwsgi_fixup_fds(0, 0, NULL); uwsgi_close_all_sockets(); for (i = 0; i < 256; i++) { if (uwsgi.p[i]->post_fork) { uwsgi.p[i]->post_fork(); } } uwsgi_spooler_run(); } else if (pid > 0) { uwsgi_log("spawned the uWSGI spooler on dir %s with pid %d\n", uspool->dir, pid); } return pid; } void uwsgi_spooler_run() { int i; struct uwsgi_spooler *uspool = uwsgi.i_am_a_spooler; uwsgi.signal_socket = uwsgi.shared->spooler_signal_pipe[1]; for (i = 0; i < 256; i++) { if (uwsgi.p[i]->spooler_init) { uwsgi.p[i]->spooler_init(); } } for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->spooler_init) { uwsgi.gp[i]->spooler_init(); } } spooler(uspool); } void destroy_spool(char *dir, char *file) { if (chdir(dir)) { uwsgi_error("chdir()"); uwsgi_log("[spooler] something horrible happened to the spooler. Better to kill it.\n"); exit(1); } if (unlink(file)) { uwsgi_error("unlink()"); uwsgi_log("[spooler] something horrible happened to the spooler. Better to kill it.\n"); exit(1); } } struct spooler_req { char *spooler; size_t spooler_len; char *priority; size_t priority_len; time_t at; }; static void spooler_req_parser_hook(char *key, uint16_t key_len, char *value, uint16_t value_len, void *data) { struct spooler_req *sr = (struct spooler_req *) data; if (!uwsgi_strncmp(key, key_len, "spooler", 7)) { sr->spooler = value; sr->spooler_len = value_len; return; } if (!uwsgi_strncmp(key, key_len, "priority", 8)) { sr->priority = value; sr->priority_len = value_len; return; } if (!uwsgi_strncmp(key, key_len, "at", 2)) { // at can be a float... char *dot = memchr(value, '.', value_len); if (dot) { value_len = dot - value; } sr->at = uwsgi_str_num(value, value_len); return; } } /* CHANGED in 2.0.7: wsgi_req is useless ! */ char *uwsgi_spool_request(struct wsgi_request *wsgi_req, char *buf, size_t len, char *body, size_t body_len) { struct timeval tv; static uint64_t internal_counter = 0; int fd = -1; struct spooler_req sr; if (len > 0xffff) { uwsgi_log("[uwsgi-spooler] args buffer is limited to 64k, use the 'body' for bigger values\n"); return NULL; } // parse the request buffer memset(&sr, 0, sizeof(struct spooler_req)); uwsgi_hooked_parse(buf, len, spooler_req_parser_hook, &sr); struct uwsgi_spooler *uspool = uwsgi.spoolers; if (!uspool) { uwsgi_log("[uwsgi-spooler] no spooler available\n"); return NULL; } // if it is a number, get the spooler by id instead of by name if (sr.spooler && sr.spooler_len) { uspool = uwsgi_get_spooler_by_name(sr.spooler, sr.spooler_len); if (!uspool) { uwsgi_log("[uwsgi-spooler] unable to find spooler \"%.*s\"\n", sr.spooler_len, sr.spooler); return NULL; } } // this lock is for threads, the pid value in filename will avoid multiprocess races uwsgi_lock(uspool->lock); // we increase it even if the request fails internal_counter++; gettimeofday(&tv, NULL); char *filename = NULL; size_t filename_len = 0; if (sr.priority && sr.priority_len) { filename_len = strlen(uspool->dir) + sr.priority_len + strlen(uwsgi.hostname) + 256; filename = uwsgi_malloc(filename_len); int ret = snprintf(filename, filename_len, "%s/%.*s", uspool->dir, (int) sr.priority_len, sr.priority); if (ret <= 0 || ret >= (int) filename_len) { uwsgi_log("[uwsgi-spooler] error generating spooler filename\n"); free(filename); uwsgi_unlock(uspool->lock); return NULL; } // no need to check for errors... (void) mkdir(filename, 0777); ret = snprintf(filename, filename_len, "%s/%.*s/uwsgi_spoolfile_on_%s_%d_%llu_%d_%llu_%llu", uspool->dir, (int)sr.priority_len, sr.priority, uwsgi.hostname, (int) getpid(), (unsigned long long) internal_counter, rand(), (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec); if (ret <= 0 || ret >=(int) filename_len) { uwsgi_log("[uwsgi-spooler] error generating spooler filename\n"); free(filename); uwsgi_unlock(uspool->lock); return NULL; } } else { filename_len = strlen(uspool->dir) + strlen(uwsgi.hostname) + 256; filename = uwsgi_malloc(filename_len); int ret = snprintf(filename, filename_len, "%s/uwsgi_spoolfile_on_%s_%d_%llu_%d_%llu_%llu", uspool->dir, uwsgi.hostname, (int) getpid(), (unsigned long long) internal_counter, rand(), (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec); if (ret <= 0 || ret >= (int) filename_len) { uwsgi_log("[uwsgi-spooler] error generating spooler filename\n"); free(filename); uwsgi_unlock(uspool->lock); return NULL; } } fd = open(filename, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR); if (fd < 0) { uwsgi_error_open(filename); free(filename); uwsgi_unlock(uspool->lock); return NULL; } // now lock the file, it will no be runnable, until the lock is not removed // a race could come if the spooler take the file before fcntl is called // in such case the spooler will detect a zeroed file and will retry later if (uwsgi_fcntl_lock(fd)) { close(fd); free(filename); uwsgi_unlock(uspool->lock); return NULL; } struct uwsgi_header uh; uh.modifier1 = 17; uh.modifier2 = 0; uh.pktsize = (uint16_t) len; #ifdef __BIG_ENDIAN__ uh.pktsize = uwsgi_swap16(uh.pktsize); #endif if (write(fd, &uh, 4) != 4) { uwsgi_log("[spooler] unable to write header for %s\n", filename); goto clear; } if (write(fd, buf, len) != (ssize_t) len) { uwsgi_log("[spooler] unable to write args for %s\n", filename); goto clear; } if (body && body_len > 0) { if ((size_t) write(fd, body, body_len) != body_len) { uwsgi_log("[spooler] unable to write body for %s\n", filename); goto clear; } } if (sr.at > 0) { #ifdef __UCLIBC__ struct timespec ts[2]; ts[0].tv_sec = sr.at; ts[0].tv_nsec = 0; ts[1].tv_sec = sr.at; ts[1].tv_nsec = 0; if (futimens(fd, ts)) { uwsgi_error("uwsgi_spooler_request()/futimens()"); } #else struct timeval tv[2]; tv[0].tv_sec = sr.at; tv[0].tv_usec = 0; tv[1].tv_sec = sr.at; tv[1].tv_usec = 0; #ifdef __sun__ if (futimesat(fd, NULL, tv)) { #else if (futimes(fd, tv)) { #endif uwsgi_error("uwsgi_spooler_request()/futimes()"); } #endif } // here the file will be unlocked too close(fd); if (!uwsgi.spooler_quiet) uwsgi_log("[spooler] written %lu bytes to file %s\n", (unsigned long) len + body_len + 4, filename); // and here waiting threads can continue uwsgi_unlock(uspool->lock); /* wake up the spoolers attached to the specified dir ... (HACKY) no need to fear races, as USR1 is harmless an all of the uWSGI processes... it could be a problem if a new process takes the old pid, but modern systems should avoid that */ struct uwsgi_spooler *spoolers = uwsgi.spoolers; while (spoolers) { if (!strcmp(spoolers->dir, uspool->dir)) { if (spoolers->pid > 0 && spoolers->running == 0) { (void) kill(spoolers->pid, SIGUSR1); } } spoolers = spoolers->next; } return filename; clear: uwsgi_unlock(uspool->lock); uwsgi_error("uwsgi_spool_request()/write()"); if (unlink(filename)) { uwsgi_error("uwsgi_spool_request()/unlink()"); } free(filename); // unlock the file too close(fd); return NULL; } void spooler(struct uwsgi_spooler *uspool) { // prevent process blindly reading stdin to make mess int nullfd; // asked by Marco Beri #ifdef __HAIKU__ #ifdef UWSGI_DEBUG uwsgi_log("lowering spooler priority to %d\n", B_LOW_PRIORITY); #endif set_thread_priority(find_thread(NULL), B_LOW_PRIORITY); #else #ifdef UWSGI_DEBUG uwsgi_log("lowering spooler priority to %d\n", PRIO_MAX); #endif setpriority(PRIO_PROCESS, getpid(), PRIO_MAX); #endif nullfd = open("/dev/null", O_RDONLY); if (nullfd < 0) { uwsgi_error_open("/dev/null"); exit(1); } if (nullfd != 0) { dup2(nullfd, 0); close(nullfd); } int spooler_event_queue = event_queue_init(); int interesting_fd = -1; if (uwsgi.master_process) { event_queue_add_fd_read(spooler_event_queue, uwsgi.shared->spooler_signal_pipe[1]); } // reset the tasks counter uspool->tasks = 0; for (;;) { if (chdir(uspool->dir)) { uwsgi_error("chdir()"); exit(1); } if (uwsgi.spooler_ordered) { #ifdef __linux__ spooler_scandir(uspool, NULL); #else spooler_readdir(uspool, NULL); #endif } else { spooler_readdir(uspool, NULL); } int timeout = uwsgi.shared->spooler_frequency ? uwsgi.shared->spooler_frequency : uwsgi.spooler_frequency; if (wakeup > 0) { timeout = 0; } if (event_queue_wait(spooler_event_queue, timeout, &interesting_fd) > 0) { if (uwsgi.master_process) { if (interesting_fd == uwsgi.shared->spooler_signal_pipe[1]) { uwsgi_receive_signal(interesting_fd, "spooler", (int) getpid()); } } } // avoid races uint64_t tmp_wakeup = wakeup; if (tmp_wakeup > 0) { tmp_wakeup--; } wakeup = tmp_wakeup; } } #ifdef __linux__ static void spooler_scandir(struct uwsgi_spooler *uspool, char *dir) { struct dirent **tasklist; int n, i; if (!dir) dir = uspool->dir; n = scandir(dir, &tasklist, NULL, versionsort); if (n < 0) { uwsgi_error("scandir()"); return; } for (i = 0; i < n; i++) { spooler_manage_task(uspool, dir, tasklist[i]->d_name); free(tasklist[i]); } free(tasklist); } #endif static void spooler_readdir(struct uwsgi_spooler *uspool, char *dir) { DIR *sdir; struct dirent *dp; if (!dir) dir = uspool->dir; sdir = opendir(dir); if (sdir) { while ((dp = readdir(sdir)) != NULL) { spooler_manage_task(uspool, dir, dp->d_name); } closedir(sdir); } else { uwsgi_error("opendir()"); } } int uwsgi_spooler_read_header(char *task, int spool_fd, struct uwsgi_header *uh) { // check if the file is locked by another process if (uwsgi_fcntl_is_locked(spool_fd)) { uwsgi_protected_close(spool_fd); return -1; } // unlink() can destroy the lock !!! if (access(task, R_OK|W_OK)) { uwsgi_protected_close(spool_fd); return -1; } ssize_t rlen = uwsgi_protected_read(spool_fd, uh, 4); if (rlen != 4) { // it could be here for broken file or just opened one if (rlen < 0) uwsgi_error("spooler_manage_task()/read()"); uwsgi_protected_close(spool_fd); return -1; } #ifdef __BIG_ENDIAN__ uh->pktsize = uwsgi_swap16(uh->pktsize); #endif return 0; } int uwsgi_spooler_read_content(int spool_fd, char *spool_buf, char **body, size_t *body_len, struct uwsgi_header *uh, struct stat *sf_lstat) { if (uwsgi_protected_read(spool_fd, spool_buf, uh->pktsize) != uh->pktsize) { uwsgi_error("spooler_manage_task()/read()"); uwsgi_protected_close(spool_fd); return 1; } // body available ? if (sf_lstat->st_size > (uh->pktsize + 4)) { *body_len = sf_lstat->st_size - (uh->pktsize + 4); *body = uwsgi_malloc(*body_len); if ((size_t) uwsgi_protected_read(spool_fd, *body, *body_len) != *body_len) { uwsgi_error("spooler_manage_task()/read()"); uwsgi_protected_close(spool_fd); free(*body); return 1; } } return 0; } void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) { int i, ret; char spool_buf[0xffff]; struct uwsgi_header uh; char *body = NULL; size_t body_len = 0; int spool_fd; if (!dir) dir = uspool->dir; if (!strncmp("uwsgi_spoolfile_on_", task, 19) || (uwsgi.spooler_ordered && is_a_number(task))) { struct stat sf_lstat; if (lstat(task, &sf_lstat)) { return; } // a spool request for the future if (sf_lstat.st_mtime > uwsgi_now()) { return; } #ifdef __linux__ if (S_ISDIR(sf_lstat.st_mode) && uwsgi.spooler_ordered) { if (chdir(task)) { uwsgi_error("chdir()"); return; } char *prio_path = realpath(".", NULL); spooler_scandir(uspool, prio_path); free(prio_path); if (chdir(dir)) { uwsgi_error("chdir()"); } return; } #endif if (!S_ISREG(sf_lstat.st_mode)) { return; } if (!access(task, R_OK | W_OK)) { spool_fd = open(task, O_RDWR); if (spool_fd < 0) { if (errno != ENOENT) uwsgi_error_open(task); return; } if (uwsgi_spooler_read_header(task, spool_fd, &uh)) return; // access lstat second time after getting a lock // first-time lstat could be dirty (for example between writes in master) if (lstat(task, &sf_lstat)) { return; } if (uwsgi_spooler_read_content(spool_fd, spool_buf, &body, &body_len, &uh, &sf_lstat)) { destroy_spool(dir, task); return; } // now the task is running and should not be woken up uspool->running = 1; if (!uwsgi.spooler_quiet) uwsgi_log("[spooler %s pid: %d] managing request %s ...\n", uspool->dir, (int) uwsgi.mypid, task); // chdir before running the task (if requested) if (uwsgi.spooler_chdir) { if (chdir(uwsgi.spooler_chdir)) { uwsgi_error("chdir()"); } } int callable_found = 0; for (i = 0; i < 256; i++) { if (uwsgi.p[i]->spooler) { time_t now = uwsgi_now(); if (uwsgi.harakiri_options.spoolers > 0) { set_spooler_harakiri(uwsgi.harakiri_options.spoolers); } ret = uwsgi.p[i]->spooler(task, spool_buf, uh.pktsize, body, body_len); if (uwsgi.harakiri_options.spoolers > 0) { set_spooler_harakiri(0); } if (ret == 0) continue; callable_found = 1; // increase task counter uspool->tasks++; if (ret == -2) { if (!uwsgi.spooler_quiet) uwsgi_log("[spooler %s pid: %d] done with task %s after %lld seconds\n", uspool->dir, (int) uwsgi.mypid, task, (long long) uwsgi_now() - now); destroy_spool(dir, task); } // re-spool it break; } } if (body) free(body); // here we free and unlock the task uwsgi_protected_close(spool_fd); uspool->running = 0; // need to recycle ? if (uwsgi.spooler_max_tasks > 0 && uspool->tasks >= (uint64_t) uwsgi.spooler_max_tasks) { uwsgi_log("[spooler %s pid: %d] maximum number of tasks reached (%d) recycling ...\n", uspool->dir, (int) uwsgi.mypid, uwsgi.spooler_max_tasks); end_me(0); } if (chdir(dir)) { uwsgi_error("chdir()"); uwsgi_log("[spooler] something horrible happened to the spooler. Better to kill it.\n"); exit(1); } if (!callable_found) { uwsgi_log("unable to find the spooler function, have you loaded it into the spooler process ?\n"); } } } } uwsgi-2.0.29/core/ssl.c000066400000000000000000000535221477626554400146720ustar00rootroot00000000000000#include "uwsgi.h" #include #include #include extern struct uwsgi_server uwsgi; /* ssl additional datas are retrieved via indexes. You can create an index with SSL_CTX_get_ex_new_index and set data in it with SSL_CTX_set_ex_data */ void uwsgi_ssl_init(void) { #if OPENSSL_VERSION_NUMBER < 0x10100000L OPENSSL_config(NULL); #endif SSL_library_init(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); uwsgi.ssl_initialized = 1; } #if OPENSSL_VERSION_NUMBER < 0x10100000L void uwsgi_ssl_info_cb(const SSL *ssl, int where, int ret) { if (where & SSL_CB_HANDSHAKE_DONE) { if (ssl->s3) { ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS; } } } #endif int uwsgi_ssl_verify_callback(int ok, X509_STORE_CTX * x509_store) { if (!ok && uwsgi.ssl_verbose) { char buf[256]; X509 *err_cert; int depth; int err; depth = X509_STORE_CTX_get_error_depth(x509_store); err_cert = X509_STORE_CTX_get_current_cert(x509_store); X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256); err = X509_STORE_CTX_get_error(x509_store); uwsgi_log("[uwsgi-ssl] client certificate verify error: num=%d:%s:depth=%d:%s\n", err, X509_verify_cert_error_string(err), depth, buf); } return ok; } #ifdef UWSGI_SSL_SESSION_CACHE int uwsgi_ssl_session_new_cb(SSL *ssl, SSL_SESSION *sess) { char session_blob[4096]; int len = i2d_SSL_SESSION(sess, NULL); if (len > 4096) { if (uwsgi.ssl_verbose) { uwsgi_log("[uwsgi-ssl] unable to store session of size %d\n", len); } return 0; } unsigned char *p = (unsigned char *) session_blob; i2d_SSL_SESSION(sess, &p); // ok let's write the value to the cache uwsgi_wlock(uwsgi.ssl_sessions_cache->lock); if (uwsgi_cache_set2(uwsgi.ssl_sessions_cache, (char *) sess->session_id, sess->session_id_length, session_blob, len, uwsgi.ssl_sessions_timeout, 0)) { if (uwsgi.ssl_verbose) { uwsgi_log("[uwsgi-ssl] unable to store session of size %d in the cache\n", len); } } uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock); return 0; } SSL_SESSION *uwsgi_ssl_session_get_cb(SSL *ssl, unsigned char *key, int keylen, int *copy) { uint64_t valsize = 0; *copy = 0; uwsgi_rlock(uwsgi.ssl_sessions_cache->lock); char *value = uwsgi_cache_get2(uwsgi.ssl_sessions_cache, (char *)key, keylen, &valsize); if (!value) { uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock); if (uwsgi.ssl_verbose) { uwsgi_log("[uwsgi-ssl] cache miss\n"); } return NULL; } #if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) SSL_SESSION *sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&value, valsize); #else SSL_SESSION *sess = d2i_SSL_SESSION(NULL, (unsigned char **)&value, valsize); #endif uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock); return sess; } void uwsgi_ssl_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess) { uwsgi_wlock(uwsgi.ssl_sessions_cache->lock); if (uwsgi_cache_del2(uwsgi.ssl_sessions_cache, (char *) sess->session_id, sess->session_id_length, 0, 0)) { if (uwsgi.ssl_verbose) { uwsgi_log("[uwsgi-ssl] error removing cache item\n"); } } uwsgi_rwunlock(uwsgi.ssl_sessions_cache->lock); } #endif #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME static int uwsgi_sni_cb(SSL *ssl, int *ad, void *arg) { const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if (!servername) return SSL_TLSEXT_ERR_NOACK; size_t servername_len = strlen(servername); // reduce DOS attempts int count = 5; while(count > 0) { struct uwsgi_string_list *usl = uwsgi.sni; while(usl) { if (!uwsgi_strncmp(usl->value, usl->len, (char *)servername, servername_len)) { SSL_set_SSL_CTX(ssl, (SSL_CTX *) usl->custom_ptr); // the following steps are taken from nginx SSL_set_verify(ssl, SSL_CTX_get_verify_mode((SSL_CTX *)usl->custom_ptr), SSL_CTX_get_verify_callback((SSL_CTX *)usl->custom_ptr)); SSL_set_verify_depth(ssl, SSL_CTX_get_verify_depth((SSL_CTX *)usl->custom_ptr)); #ifdef SSL_CTRL_CLEAR_OPTIONS SSL_clear_options(ssl, SSL_get_options(ssl) & ~SSL_CTX_get_options((SSL_CTX *)usl->custom_ptr)); #endif SSL_set_options(ssl, SSL_CTX_get_options((SSL_CTX *)usl->custom_ptr)); return SSL_TLSEXT_ERR_OK; } usl = usl->next; } if (!uwsgi.subscription_dotsplit) break; char *next = memchr(servername+1, '.', servername_len-1); if (next) { servername_len -= next - servername; servername = next; count--; continue; } break; } if (uwsgi.subscription_dotsplit) goto end; #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) struct uwsgi_regexp_list *url = uwsgi.sni_regexp; while(url) { if (uwsgi_regexp_match(url->pattern, (char *)servername, servername_len) >= 0) { SSL_set_SSL_CTX(ssl, url->custom_ptr); return SSL_TLSEXT_ERR_OK; } url = url->next; } #endif if (uwsgi.sni_dir) { size_t sni_dir_len = strlen(uwsgi.sni_dir); char *sni_dir_cert = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".crt", 4); char *sni_dir_key = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".key", 4); char *sni_dir_client_ca = uwsgi_concat4n(uwsgi.sni_dir, sni_dir_len, "/", 1, (char *) servername, servername_len, ".ca", 3); if (uwsgi_file_exists(sni_dir_cert) && uwsgi_file_exists(sni_dir_key)) { char *client_ca = NULL; if (uwsgi_file_exists(sni_dir_client_ca)) { client_ca = sni_dir_client_ca; } struct uwsgi_string_list *usl = uwsgi_ssl_add_sni_item(uwsgi_str((char *)servername), sni_dir_cert, sni_dir_key, uwsgi.sni_dir_ciphers, client_ca); if (!usl) goto done; free(sni_dir_cert); free(sni_dir_key); free(sni_dir_client_ca); SSL_set_SSL_CTX(ssl, usl->custom_ptr); return SSL_TLSEXT_ERR_OK; } done: free(sni_dir_cert); free(sni_dir_key); free(sni_dir_client_ca); } end: return SSL_TLSEXT_ERR_NOACK; } #endif char *uwsgi_write_pem_to_file(char *name, char *buf, size_t len, char *ext) { if (!uwsgi.ssl_tmp_dir) return NULL; char *filename = uwsgi_concat4(uwsgi.ssl_tmp_dir, "/", name, ext); int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR); if (fd < 0) { uwsgi_error_open(filename); free(filename); return NULL; } if (write(fd, buf, len) != (ssize_t) len) { uwsgi_log("unable to write pem data in file %s\n", filename); uwsgi_error("uwsgi_write_pem_to_file()/write()"); free(filename); close(fd); return NULL; } close(fd); return filename; } SSL_CTX *uwsgi_ssl_new_server_context(char *name, char *crt, char *key, char *ciphers, char *client_ca) { int crt_need_free = 0; int key_need_free = 0; int client_ca_need_free = 0; SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method()); if (!ctx) { uwsgi_log("[uwsgi-ssl] unable to initialize context \"%s\"\n", name); return NULL; } // this part is taken from nginx and stud, removing unneeded functionality // stud (for me) has made the best choice on choosing DH approach long ssloptions = SSL_OP_NO_SSLv2 | SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION; // disable compression (if possibile) #ifdef SSL_OP_NO_COMPRESSION ssloptions |= SSL_OP_NO_COMPRESSION; #endif if (!uwsgi.sslv3) { ssloptions |= SSL_OP_NO_SSLv3; } if (!uwsgi.tlsv1) { ssloptions |= SSL_OP_NO_TLSv1; } // release/reuse buffers as soon as possibile #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); #endif /* we need to support both file-based certs and stream based as dealing with openssl memory bio for keys is really overkill, we store them in a tmp directory */ if (uwsgi.ssl_tmp_dir && !uwsgi_starts_with(crt, strlen(crt), "-----BEGIN ", 11)) { crt = uwsgi_write_pem_to_file(name, crt, strlen(crt), ".crt"); if (!crt) { SSL_CTX_free(ctx); return NULL; } crt_need_free = 1; } if (SSL_CTX_use_certificate_chain_file(ctx, crt) <= 0) { uwsgi_log("[uwsgi-ssl] unable to assign certificate %s for context \"%s\"\n", crt, name); SSL_CTX_free(ctx); if (crt_need_free) free(crt); return NULL; } // this part is based from stud BIO *bio = BIO_new_file(crt, "r"); if (bio) { DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); BIO_free(bio); if (dh) { SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE); SSL_CTX_set_tmp_dh(ctx, dh); DH_free(dh); } } #if OPENSSL_VERSION_NUMBER >= 0x0090800fL #ifndef OPENSSL_NO_ECDH #ifdef NID_X9_62_prime256v1 EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); if (ecdh) { SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE); SSL_CTX_set_tmp_ecdh(ctx, ecdh); EC_KEY_free(ecdh); } #endif #endif #endif if (crt_need_free) free(crt); if (uwsgi.ssl_tmp_dir && !uwsgi_starts_with(key, strlen(key), "-----BEGIN ", 11)) { key = uwsgi_write_pem_to_file(name, key, strlen(key), ".key"); if (!key) { SSL_CTX_free(ctx); return NULL; } key_need_free = 1; } if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) <= 0) { uwsgi_log("[uwsgi-ssl] unable to assign key %s for context \"%s\"\n", key, name); SSL_CTX_free(ctx); if (key_need_free) free(key); return NULL; } if (key_need_free) free(key); // if ciphers are specified, prefer server ciphers if (ciphers && strlen(ciphers) > 0) { if (SSL_CTX_set_cipher_list(ctx, ciphers) == 0) { uwsgi_log("[uwsgi-ssl] unable to set requested ciphers (%s) for context \"%s\"\n", ciphers, name); SSL_CTX_free(ctx); return NULL; } ssloptions |= SSL_OP_CIPHER_SERVER_PREFERENCE; } // set session context (if possibile), this is required for client certificate authentication if (name) { SSL_CTX_set_session_id_context(ctx, (unsigned char *) name, strlen(name)); } if (client_ca) { if (client_ca[0] == '!') { SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, uwsgi_ssl_verify_callback); client_ca++; } else { SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, uwsgi_ssl_verify_callback); } SSL_CTX_set_verify_depth(ctx, uwsgi.ssl_verify_depth); if (uwsgi.ssl_tmp_dir && !uwsgi_starts_with(client_ca, strlen(client_ca), "-----BEGIN ", 11)) { if (!name) { SSL_CTX_free(ctx); return NULL; } client_ca = uwsgi_write_pem_to_file(name, client_ca, strlen(client_ca), ".ca"); if (!client_ca) { SSL_CTX_free(ctx); return NULL; } client_ca_need_free = 1; } if (SSL_CTX_load_verify_locations(ctx, client_ca, NULL) == 0) { uwsgi_log("[uwsgi-ssl] unable to set ssl verify locations (%s) for context \"%s\"\n", client_ca, name); SSL_CTX_free(ctx); if (client_ca_need_free) free(client_ca); return NULL; } STACK_OF(X509_NAME) * list = SSL_load_client_CA_file(client_ca); if (!list) { uwsgi_log("unable to load client CA certificate (%s) for context \"%s\"\n", client_ca, name); SSL_CTX_free(ctx); if (client_ca_need_free) free(client_ca); return NULL; } SSL_CTX_set_client_CA_list(ctx, list); if (client_ca_need_free) free(client_ca); } #if OPENSSL_VERSION_NUMBER < 0x10100000L SSL_CTX_set_info_callback(ctx, uwsgi_ssl_info_cb); #endif #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME SSL_CTX_set_tlsext_servername_callback(ctx, uwsgi_sni_cb); #endif // disable session caching by default SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); #ifdef UWSGI_SSL_SESSION_CACHE if (uwsgi.ssl_sessions_use_cache) { // we need to early initialize locking and caching uwsgi_setup_locking(); uwsgi_cache_create_all(); uwsgi.ssl_sessions_cache = uwsgi_cache_by_name(uwsgi.ssl_sessions_use_cache); if (!uwsgi.ssl_sessions_cache) { // check for default cache if (!strcmp(uwsgi.ssl_sessions_use_cache, "true") && uwsgi.caches) { uwsgi.ssl_sessions_cache = uwsgi.caches; } else { uwsgi_log("unable to find cache \"%s\"\n", uwsgi.ssl_sessions_use_cache ? uwsgi.ssl_sessions_use_cache : "default"); exit(1); } } if (!uwsgi.ssl_sessions_cache->max_items) { uwsgi_log("you have to enable uWSGI cache to use it as SSL session store !!!\n"); exit(1); } if (uwsgi.ssl_sessions_cache->blocksize < 4096) { uwsgi_log("cache blocksize for SSL session store must be at least 4096 bytes\n"); exit(1); } SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER| SSL_SESS_CACHE_NO_INTERNAL| SSL_SESS_CACHE_NO_AUTO_CLEAR); #ifdef SSL_OP_NO_TICKET ssloptions |= SSL_OP_NO_TICKET; #endif // just for fun SSL_CTX_sess_set_cache_size(ctx, 0); // set the callback for ssl sessions SSL_CTX_sess_set_new_cb(ctx, uwsgi_ssl_session_new_cb); SSL_CTX_sess_set_get_cb(ctx, uwsgi_ssl_session_get_cb); SSL_CTX_sess_set_remove_cb(ctx, uwsgi_ssl_session_remove_cb); } #endif SSL_CTX_set_timeout(ctx, uwsgi.ssl_sessions_timeout); struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, uwsgi.ssl_options) { ssloptions |= atoi(usl->value); } SSL_CTX_set_options(ctx, ssloptions); return ctx; } char *uwsgi_rsa_sign(char *algo_key, char *message, size_t message_len, unsigned int *s_len) { // openssl could not be initialized if (!uwsgi.ssl_initialized) { uwsgi_ssl_init(); } *s_len = 0; EVP_PKEY *pk = NULL; char *algo = uwsgi_str(algo_key); char *colon = strchr(algo, ':'); if (!colon) { uwsgi_log("invalid RSA signature syntax, must be: :\n"); free(algo); return NULL; } *colon = 0; char *keyfile = colon + 1; char *signature = NULL; FILE *kf = fopen(keyfile, "r"); if (!kf) { uwsgi_error_open(keyfile); free(algo); return NULL; } if (PEM_read_PrivateKey(kf, &pk, NULL, NULL) == 0) { uwsgi_log("unable to load private key: %s\n", keyfile); free(algo); fclose(kf); return NULL; } fclose(kf); EVP_MD_CTX *ctx = EVP_MD_CTX_create(); if (!ctx) { free(algo); EVP_PKEY_free(pk); return NULL; } const EVP_MD *md = EVP_get_digestbyname(algo); if (!md) { uwsgi_log("unknown digest algo: %s\n", algo); free(algo); EVP_PKEY_free(pk); EVP_MD_CTX_destroy(ctx); return NULL; } *s_len = EVP_PKEY_size(pk); signature = uwsgi_malloc(*s_len); if (EVP_SignInit_ex(ctx, md, NULL) == 0) { ERR_print_errors_fp(stderr); free(signature); signature = NULL; *s_len = 0; goto clear; } if (EVP_SignUpdate(ctx, message, message_len) == 0) { ERR_print_errors_fp(stderr); free(signature); signature = NULL; *s_len = 0; goto clear; } if (EVP_SignFinal(ctx, (unsigned char *) signature, s_len, pk) == 0) { ERR_print_errors_fp(stderr); free(signature); signature = NULL; *s_len = 0; goto clear; } clear: free(algo); EVP_PKEY_free(pk); EVP_MD_CTX_destroy(ctx); return signature; } char *uwsgi_sanitize_cert_filename(char *base, char *key, uint16_t keylen) { uint16_t i; char *filename = uwsgi_concat4n(base, strlen(base), "/", 1, key, keylen, ".pem\0", 5); for (i = strlen(base) + 1; i < (strlen(base) + 1) + keylen; i++) { if (filename[i] >= '0' && filename[i] <= '9') continue; if (filename[i] >= 'A' && filename[i] <= 'Z') continue; if (filename[i] >= 'a' && filename[i] <= 'z') continue; if (filename[i] == '.') continue; if (filename[i] == '-') continue; if (filename[i] == '_') continue; filename[i] = '_'; } return filename; } char *uwsgi_ssl_rand(size_t len) { unsigned char *buf = uwsgi_calloc(len); if (RAND_bytes(buf, len) <= 0) { free(buf); return NULL; } return (char *) buf; } char *uwsgi_sha1(char *src, size_t len, char *dst) { SHA_CTX sha; SHA1_Init(&sha); SHA1_Update(&sha, src, len); SHA1_Final((unsigned char *)dst, &sha); return dst; } char *uwsgi_md5(char *src, size_t len, char *dst) { MD5_CTX md5; MD5_Init(&md5); MD5_Update(&md5, src, len); MD5_Final((unsigned char *)dst, &md5); return dst; } char *uwsgi_sha1_2n(char *s1, size_t len1, char *s2, size_t len2, char *dst) { SHA_CTX sha; SHA1_Init(&sha); SHA1_Update(&sha, s1, len1); SHA1_Update(&sha, s2, len2); SHA1_Final((unsigned char *)dst, &sha); return dst; } void uwsgi_opt_sni(char *opt, char *value, void *foobar) { char *client_ca = NULL; char *v = uwsgi_str(value); char *space = strchr(v, ' '); if (!space) { uwsgi_log("invalid %s syntax, must be sni_keycrt,key[,ciphers,client_ca]\n", opt); exit(1); } *space = 0; char *crt = space+1; char *key = strchr(crt, ','); if (!key) { uwsgi_log("invalid %s syntax, must be sni_keycrt,key[,ciphers,client_ca]\n", opt); exit(1); } *key = '\0'; key++; char *ciphers = strchr(key, ','); if (ciphers) { *ciphers = '\0'; ciphers++; client_ca = strchr(ciphers, ','); if (client_ca) { *client_ca = '\0'; client_ca++; } } if (!uwsgi.ssl_initialized) { uwsgi_ssl_init(); } SSL_CTX *ctx = uwsgi_ssl_new_server_context(v, crt, key, ciphers, client_ca); if (!ctx) { uwsgi_log("[uwsgi-ssl] DANGER unable to initialize context for \"%s\"\n", v); free(v); return; } #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) if (!strcmp(opt, "sni-regexp")) { struct uwsgi_regexp_list *url = uwsgi_regexp_new_list(&uwsgi.sni_regexp, v); url->custom_ptr = ctx; } else { #endif struct uwsgi_string_list *usl = uwsgi_string_new_list(&uwsgi.sni, v); usl->custom_ptr = ctx; #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) } #endif } struct uwsgi_string_list *uwsgi_ssl_add_sni_item(char *name, char *crt, char *key, char *ciphers, char *client_ca) { if (!uwsgi.ssl_initialized) { uwsgi_ssl_init(); } SSL_CTX *ctx = uwsgi_ssl_new_server_context(name, crt, key, ciphers, client_ca); if (!ctx) { uwsgi_log("[uwsgi-ssl] DANGER unable to initialize context for \"%s\"\n", name); free(name); return NULL; } struct uwsgi_string_list *usl = uwsgi_string_new_list(&uwsgi.sni, name); usl->custom_ptr = ctx; // mark it as dynamic usl->custom = 1; uwsgi_log_verbose("[uwsgi-sni for pid %d] added SSL context for %s\n", (int) getpid(), name); return usl; } void uwsgi_ssl_del_sni_item(char *name, uint16_t name_len) { struct uwsgi_string_list *usl = NULL, *last_sni = NULL, *sni_item = NULL; uwsgi_foreach(usl, uwsgi.sni) { if (!uwsgi_strncmp(usl->value, usl->len, name, name_len) && usl->custom) { sni_item = usl; break; } last_sni = usl; } if (!sni_item) return; if (last_sni) { last_sni->next = sni_item->next; } else { uwsgi.sni = sni_item->next; } // we are free to destroy it as no more clients are using it SSL_CTX_free((SSL_CTX *) sni_item->custom_ptr); free(sni_item->value); free(sni_item); uwsgi_log_verbose("[uwsgi-sni for pid %d] destroyed SSL context for %s\n",(int) getpid(), name); } uwsgi-2.0.29/core/static.c000066400000000000000000000450131477626554400153540ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; int uwsgi_static_want_gzip(struct wsgi_request *wsgi_req, char *filename, size_t *filename_len, struct stat *st) { char can_gzip = 0, can_br = 0; // check for filename size if (*filename_len + 4 > PATH_MAX) return 0; // check for supported encodings can_br = uwsgi_contains_n(wsgi_req->encoding, wsgi_req->encoding_len, "br", 2); can_gzip = uwsgi_contains_n(wsgi_req->encoding, wsgi_req->encoding_len, "gzip", 4); if(!can_br && !can_gzip) return 0; // check for 'all' if (uwsgi.static_gzip_all) goto gzip; // check for dirs/prefix struct uwsgi_string_list *usl = uwsgi.static_gzip_dir; while(usl) { if (!uwsgi_starts_with(filename, *filename_len, usl->value, usl->len)) { goto gzip; } usl = usl->next; } // check for ext/suffix usl = uwsgi.static_gzip_ext; while(usl) { if (!uwsgi_strncmp(filename + (*filename_len - usl->len), usl->len, usl->value, usl->len)) { goto gzip; } usl = usl->next; } #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) // check for regexp struct uwsgi_regexp_list *url = uwsgi.static_gzip; while(url) { if (uwsgi_regexp_match(url->pattern, filename, *filename_len) >= 0) { goto gzip; } url = url->next; } #endif return 0; gzip: if (can_br) { memcpy(filename + *filename_len, ".br\0", 4); *filename_len += 3; if (!stat(filename, st)) return 2; *filename_len -= 3; filename[*filename_len] = 0; } if (can_gzip) { memcpy(filename + *filename_len, ".gz\0", 4); *filename_len += 3; if (!stat(filename, st)) return 1; *filename_len -= 3; filename[*filename_len] = 0; } return 0; } int uwsgi_http_date(time_t t, char *dst) { static char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; struct tm *hdtm = gmtime(&t); int ret = snprintf(dst, 31, "%s, %02d %s %4d %02d:%02d:%02d GMT", week[hdtm->tm_wday], hdtm->tm_mday, months[hdtm->tm_mon], hdtm->tm_year + 1900, hdtm->tm_hour, hdtm->tm_min, hdtm->tm_sec); if (ret <= 0 || ret > 31) { return 0; } return ret; } // only RFC 1123 is supported static time_t parse_http_date(char *date, uint16_t len) { struct tm hdtm; if (len != 29 && date[3] != ',') return 0; hdtm.tm_mday = uwsgi_str2_num(date + 5); switch (date[8]) { case 'J': if (date[9] == 'a') { hdtm.tm_mon = 0; break; } if (date[9] == 'u') { if (date[10] == 'n') { hdtm.tm_mon = 5; break; } if (date[10] == 'l') { hdtm.tm_mon = 6; break; } return 0; } return 0; case 'F': hdtm.tm_mon = 1; break; case 'M': if (date[9] != 'a') return 0; if (date[10] == 'r') { hdtm.tm_mon = 2; break; } if (date[10] == 'y') { hdtm.tm_mon = 4; break; } return 0; case 'A': if (date[10] == 'r') { hdtm.tm_mon = 3; break; } if (date[10] == 'g') { hdtm.tm_mon = 7; break; } return 0; case 'S': hdtm.tm_mon = 8; break; case 'O': hdtm.tm_mon = 9; break; case 'N': hdtm.tm_mon = 10; break; case 'D': hdtm.tm_mon = 11; break; default: return 0; } hdtm.tm_year = uwsgi_str4_num(date + 12) - 1900; hdtm.tm_hour = uwsgi_str2_num(date + 17); hdtm.tm_min = uwsgi_str2_num(date + 20); hdtm.tm_sec = uwsgi_str2_num(date + 23); return timegm(&hdtm); } int uwsgi_add_expires_type(struct wsgi_request *wsgi_req, char *mime_type, int mime_type_len, struct stat *st) { struct uwsgi_dyn_dict *udd = uwsgi.static_expires_type; time_t now = wsgi_req->start_of_request / 1000000; // 30+1 char expires[31]; while (udd) { if (!uwsgi_strncmp(udd->key, udd->keylen, mime_type, mime_type_len)) { int delta = uwsgi_str_num(udd->value, udd->vallen); int size = uwsgi_http_date(now + delta, expires); if (size > 0) { if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1; } return 0; } udd = udd->next; } udd = uwsgi.static_expires_type_mtime; while (udd) { if (!uwsgi_strncmp(udd->key, udd->keylen, mime_type, mime_type_len)) { int delta = uwsgi_str_num(udd->value, udd->vallen); int size = uwsgi_http_date(st->st_mtime + delta, expires); if (size > 0) { if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1; } return 0; } udd = udd->next; } return 0; } #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) int uwsgi_add_expires(struct wsgi_request *wsgi_req, char *filename, int filename_len, struct stat *st) { struct uwsgi_dyn_dict *udd = uwsgi.static_expires; time_t now = wsgi_req->start_of_request / 1000000; // 30+1 char expires[31]; while (udd) { if (uwsgi_regexp_match(udd->pattern, filename, filename_len) >= 0) { int delta = uwsgi_str_num(udd->value, udd->vallen); int size = uwsgi_http_date(now + delta, expires); if (size > 0) { if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1; } return 0; } udd = udd->next; } udd = uwsgi.static_expires_mtime; while (udd) { if (uwsgi_regexp_match(udd->pattern, filename, filename_len) >= 0) { int delta = uwsgi_str_num(udd->value, udd->vallen); int size = uwsgi_http_date(st->st_mtime + delta, expires); if (size > 0) { if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1; } return 0; } udd = udd->next; } return 0; } int uwsgi_add_expires_path_info(struct wsgi_request *wsgi_req, struct stat *st) { struct uwsgi_dyn_dict *udd = uwsgi.static_expires_path_info; time_t now = wsgi_req->start_of_request / 1000000; // 30+1 char expires[31]; while (udd) { if (uwsgi_regexp_match(udd->pattern, wsgi_req->path_info, wsgi_req->path_info_len) >= 0) { int delta = uwsgi_str_num(udd->value, udd->vallen); int size = uwsgi_http_date(now + delta, expires); if (size > 0) { if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1; } return 0; } udd = udd->next; } udd = uwsgi.static_expires_path_info_mtime; while (udd) { if (uwsgi_regexp_match(udd->pattern, wsgi_req->path_info, wsgi_req->path_info_len) >= 0) { int delta = uwsgi_str_num(udd->value, udd->vallen); int size = uwsgi_http_date(st->st_mtime + delta, expires); if (size > 0) { if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1; } return 0; } udd = udd->next; } return 0; } int uwsgi_add_expires_uri(struct wsgi_request *wsgi_req, struct stat *st) { struct uwsgi_dyn_dict *udd = uwsgi.static_expires_uri; time_t now = wsgi_req->start_of_request / 1000000; // 30+1 char expires[31]; while (udd) { if (uwsgi_regexp_match(udd->pattern, wsgi_req->uri, wsgi_req->uri_len) >= 0) { int delta = uwsgi_str_num(udd->value, udd->vallen); int size = uwsgi_http_date(now + delta, expires); if (size > 0) { if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1; } return 0; } udd = udd->next; } udd = uwsgi.static_expires_uri_mtime; while (udd) { if (uwsgi_regexp_match(udd->pattern, wsgi_req->uri, wsgi_req->uri_len) >= 0) { int delta = uwsgi_str_num(udd->value, udd->vallen); int size = uwsgi_http_date(st->st_mtime + delta, expires); if (size > 0) { if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1; } return 0; } udd = udd->next; } return 0; } #endif char *uwsgi_get_mime_type(char *name, int namelen, size_t *size) { int i; int count = 0; char *ext = NULL; for (i = namelen - 1; i >= 0; i--) { if (!isalnum((int) name[i])) { if (name[i] == '.') { ext = name + (namelen - count); break; } } count++; } if (!ext) return NULL; if (uwsgi.threads > 1) pthread_mutex_lock(&uwsgi.lock_static); struct uwsgi_dyn_dict *udd = uwsgi.mimetypes; while (udd) { if (!uwsgi_strncmp(ext, count, udd->key, udd->keylen)) { udd->hits++; // auto optimization if (udd->prev) { if (udd->hits > udd->prev->hits) { struct uwsgi_dyn_dict *udd_parent = udd->prev->prev, *udd_prev = udd->prev; if (udd_parent) { udd_parent->next = udd; } if (udd->next) { udd->next->prev = udd_prev; } udd_prev->prev = udd; udd_prev->next = udd->next; udd->prev = udd_parent; udd->next = udd_prev; if (udd->prev == NULL) { uwsgi.mimetypes = udd; } } } *size = udd->vallen; if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.lock_static); return udd->value; } udd = udd->next; } if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.lock_static); return NULL; } ssize_t uwsgi_append_static_path(char *dir, size_t dir_len, char *file, size_t file_len) { size_t len = dir_len; if (len + 1 + file_len > PATH_MAX) { return -1; } if (dir[len - 1] == '/') { memcpy(dir + len, file, file_len); dir[len + file_len] = 0; len += file_len; } else { dir[len] = '/'; memcpy(dir + len + 1, file, file_len); dir[len + 1 + file_len] = 0; len += 1 + file_len; } return len; } static int uwsgi_static_stat(struct wsgi_request *wsgi_req, char *filename, size_t *filename_len, struct stat *st, struct uwsgi_string_list **index) { int ret = stat(filename, st); // if non-existant return -1 if (ret < 0) return -1; if (S_ISREG(st->st_mode)) return 0; // check for index if (S_ISDIR(st->st_mode)) { struct uwsgi_string_list *usl = uwsgi.static_index; while (usl) { ssize_t new_len = uwsgi_append_static_path(filename, *filename_len, usl->value, usl->len); if (new_len >= 0) { #ifdef UWSGI_DEBUG uwsgi_log("checking for %s\n", filename); #endif if (uwsgi_is_file2(filename, st)) { *index = usl; *filename_len = new_len; return 0; } // reset to original name filename[*filename_len] = 0; } usl = usl->next; } } return -1; } void uwsgi_request_fix_range_for_size(struct wsgi_request *wsgi_req, int64_t size) { uwsgi_fix_range_for_size(&wsgi_req->range_parsed, &wsgi_req->range_from, &wsgi_req->range_to, size); } int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, size_t real_filename_len, struct stat *st) { size_t mime_type_size = 0; char http_last_modified[49]; int use_gzip = 0; char *mime_type = uwsgi_get_mime_type(real_filename, real_filename_len, &mime_type_size); // here we need to choose if we want the gzip variant; use_gzip = uwsgi_static_want_gzip(wsgi_req, real_filename, &real_filename_len, st); if (wsgi_req->if_modified_since_len) { time_t ims = parse_http_date(wsgi_req->if_modified_since, wsgi_req->if_modified_since_len); if (st->st_mtime <= ims) { if (uwsgi_response_prepare_headers(wsgi_req, "304 Not Modified", 16)) return -1; return uwsgi_response_write_headers_do(wsgi_req); } } #ifdef UWSGI_DEBUG uwsgi_log("[uwsgi-fileserve] file %s found\n", real_filename); #endif // static file - don't update avg_rt after request wsgi_req->do_not_account_avg_rt = 1; int64_t fsize = (int64_t)st->st_size; uwsgi_request_fix_range_for_size(wsgi_req, fsize); switch (wsgi_req->range_parsed) { case UWSGI_RANGE_INVALID: if (uwsgi_response_prepare_headers(wsgi_req, "416 Requested Range Not Satisfiable", 35)) return -1; if (uwsgi_response_add_content_range(wsgi_req, -1, -1, st->st_size)) return -1; return 0; case UWSGI_RANGE_VALID: { time_t when = 0; if (wsgi_req->if_range != NULL) { when = parse_http_date(wsgi_req->if_range, wsgi_req->if_range_len); // an ETag will result in when == 0 } if (when < st->st_mtime) { fsize = wsgi_req->range_to - wsgi_req->range_from + 1; if (uwsgi_response_prepare_headers(wsgi_req, "206 Partial Content", 19)) return -1; break; } } /* fallthrough */ default: /* UWSGI_RANGE_NOT_PARSED */ if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1; } #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) uwsgi_add_expires(wsgi_req, real_filename, real_filename_len, st); uwsgi_add_expires_path_info(wsgi_req, st); uwsgi_add_expires_uri(wsgi_req, st); #endif if (use_gzip == 1) { if (uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4)) return -1; } else if (use_gzip == 2) { if (uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "br", 2)) return -1; } // Content-Type (if available) if (mime_type_size > 0 && mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_size)) return -1; // check for content-type related headers uwsgi_add_expires_type(wsgi_req, mime_type, mime_type_size, st); } // increase static requests counter uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].static_requests++; // nginx if (uwsgi.file_serve_mode == 1) { if (uwsgi_response_add_header(wsgi_req, "X-Accel-Redirect", 16, real_filename, real_filename_len)) return -1; // this is the final header (\r\n added) int size = uwsgi_http_date(st->st_mtime, http_last_modified); if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1; } // apache else if (uwsgi.file_serve_mode == 2) { if (uwsgi_response_add_header(wsgi_req, "X-Sendfile", 10, real_filename, real_filename_len)) return -1; // this is the final header (\r\n added) int size = uwsgi_http_date(st->st_mtime, http_last_modified); if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1; } // raw else { // set Content-Length (to fsize NOT st->st_size) if (uwsgi_response_add_content_length(wsgi_req, fsize)) return -1; if (wsgi_req->range_parsed == UWSGI_RANGE_VALID) { // here use the original size !!! if (uwsgi_response_add_content_range(wsgi_req, wsgi_req->range_from, wsgi_req->range_to, st->st_size)) return -1; } int size = uwsgi_http_date(st->st_mtime, http_last_modified); if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1; // if it is a HEAD request just skip transfer if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) { wsgi_req->status = 200; return 0; } // Ok, the file must be transferred from uWSGI // offloading will be automatically managed int fd = open(real_filename, O_RDONLY); if (fd < 0) return -1; // fd will be closed in the following function uwsgi_response_sendfile_do(wsgi_req, fd, wsgi_req->range_from, fsize); } wsgi_req->status = 200; return 0; } int uwsgi_file_serve(struct wsgi_request *wsgi_req, char *document_root, uint16_t document_root_len, char *path_info, uint16_t path_info_len, int is_a_file) { struct stat st; char real_filename[PATH_MAX + 1]; size_t real_filename_len = 0; char *filename = NULL; size_t filename_len = 0; struct uwsgi_string_list *index = NULL; if (!is_a_file) { filename = uwsgi_concat3n(document_root, document_root_len, "/", 1, path_info, path_info_len); filename_len = document_root_len + 1 + path_info_len; } else { filename = uwsgi_concat2n(document_root, document_root_len, "", 0); filename_len = document_root_len; } #ifdef UWSGI_DEBUG uwsgi_log("[uwsgi-fileserve] checking for %s\n", filename); #endif if (uwsgi.static_cache_paths) { uwsgi_rlock(uwsgi.static_cache_paths->lock); uint64_t item_len; char *item = uwsgi_cache_get2(uwsgi.static_cache_paths, filename, filename_len, &item_len); if (item && item_len > 0 && item_len <= PATH_MAX) { memcpy(real_filename, item, item_len); real_filename_len = item_len; real_filename[real_filename_len] = 0; uwsgi_rwunlock(uwsgi.static_cache_paths->lock); goto found; } uwsgi_rwunlock(uwsgi.static_cache_paths->lock); } if (!realpath(filename, real_filename)) { #ifdef UWSGI_DEBUG uwsgi_log("[uwsgi-fileserve] unable to get realpath() of the static file\n"); #endif free(filename); return -1; } real_filename_len = strlen(real_filename); if (uwsgi.static_cache_paths) { uwsgi_wlock(uwsgi.static_cache_paths->lock); uwsgi_cache_set2(uwsgi.static_cache_paths, filename, filename_len, real_filename, real_filename_len, uwsgi.use_static_cache_paths, UWSGI_CACHE_FLAG_UPDATE); uwsgi_rwunlock(uwsgi.static_cache_paths->lock); } found: free(filename); if (uwsgi_starts_with(real_filename, real_filename_len, document_root, document_root_len)) { struct uwsgi_string_list *safe = uwsgi.static_safe; while(safe) { if (!uwsgi_starts_with(real_filename, real_filename_len, safe->value, safe->len)) { goto safe; } safe = safe->next; } uwsgi_log("[uwsgi-fileserve] security error: %s is not under %.*s or a safe path\n", real_filename, document_root_len, document_root); return -1; } safe: if (!uwsgi_static_stat(wsgi_req, real_filename, &real_filename_len, &st, &index)) { if (index) { // if we are here the PATH_INFO need to be changed if (uwsgi_req_append_path_info_with_index(wsgi_req, index->value, index->len)) { return -1; } } // skip methods other than GET and HEAD if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "GET", 3) && uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) { return -1; } // check for skippable ext struct uwsgi_string_list *sse = uwsgi.static_skip_ext; while (sse) { if (real_filename_len >= sse->len) { if (!uwsgi_strncmp(real_filename + (real_filename_len - sse->len), sse->len, sse->value, sse->len)) { return -1; } } sse = sse->next; } #ifdef UWSGI_ROUTING // before sending the file, we need to check if some rule applies if (!wsgi_req->is_routing && uwsgi_apply_routes_do(uwsgi.routes, wsgi_req, NULL, 0) == UWSGI_ROUTE_BREAK) { return 0; } wsgi_req->routes_applied = 1; #endif return uwsgi_real_file_serve(wsgi_req, real_filename, real_filename_len, &st); } return -1; } uwsgi-2.0.29/core/stats.c000066400000000000000000000343551477626554400152320ustar00rootroot00000000000000#include "uwsgi.h" /* utility functions for fast generating json output for the stats subsystem */ extern struct uwsgi_server uwsgi; struct uwsgi_stats *uwsgi_stats_new(size_t chunk_size) { struct uwsgi_stats *us = uwsgi_malloc(sizeof(struct uwsgi_stats)); us->base = uwsgi_malloc(chunk_size); us->base[0] = '{'; us->pos = 1; us->chunk = chunk_size; us->size = chunk_size; us->tabs = 1; us->dirty = 0; us->minified = uwsgi.stats_minified; if (!us->minified) { us->base[1] = '\n'; us->pos++; } return us; } int uwsgi_stats_symbol(struct uwsgi_stats *us, char sym) { char *ptr = us->base + us->pos; char *watermark = us->base + us->size; if (ptr + 1 > watermark) { char *new_base = realloc(us->base, us->size + us->chunk); if (!new_base) return -1; us->base = new_base; us->size += us->chunk; ptr = us->base + us->pos; } *ptr = sym; us->pos++; return 0; } int uwsgi_stats_symbol_nl(struct uwsgi_stats *us, char sym) { if (uwsgi_stats_symbol(us, sym)) { return -1; } if (us->minified) return 0; return uwsgi_stats_symbol(us, '\n'); } int uwsgi_stats_comma(struct uwsgi_stats *us) { return uwsgi_stats_symbol_nl(us, ','); } int uwsgi_stats_apply_tabs(struct uwsgi_stats *us) { if (us->minified) return 0; size_t i; for (i = 0; i < us->tabs; i++) { if (uwsgi_stats_symbol(us, '\t')) return -1; }; return 0; } int uwsgi_stats_object_open(struct uwsgi_stats *us) { if (uwsgi_stats_apply_tabs(us)) return -1; if (!us->minified) us->tabs++; return uwsgi_stats_symbol_nl(us, '{'); } int uwsgi_stats_object_close(struct uwsgi_stats *us) { if (!us->minified) { if (uwsgi_stats_symbol(us, '\n')) return -1; us->tabs--; if (uwsgi_stats_apply_tabs(us)) return -1; } return uwsgi_stats_symbol(us, '}'); } int uwsgi_stats_list_open(struct uwsgi_stats *us) { us->tabs++; return uwsgi_stats_symbol_nl(us, '['); } int uwsgi_stats_list_close(struct uwsgi_stats *us) { if (!us->minified) { if (uwsgi_stats_symbol(us, '\n')) return -1; us->tabs--; if (uwsgi_stats_apply_tabs(us)) return -1; } return uwsgi_stats_symbol(us, ']'); } int uwsgi_stats_keyval(struct uwsgi_stats *us, char *key, char *value) { if (uwsgi_stats_apply_tabs(us)) return -1; char *ptr = us->base + us->pos; char *watermark = us->base + us->size; size_t available = watermark - ptr; int ret = snprintf(ptr, available, "\"%s\":\"%s\"", key, value); if (ret <= 0) return -1; while (ret >= (int) available) { char *new_base = realloc(us->base, us->size + us->chunk); if (!new_base) return -1; us->base = new_base; us->size += us->chunk; ptr = us->base + us->pos; watermark = us->base + us->size; available = watermark - ptr; ret = snprintf(ptr, available, "\"%s\":\"%s\"", key, value); if (ret <= 0) return -1; } us->pos += ret; return 0; } int uwsgi_stats_keyval_comma(struct uwsgi_stats *us, char *key, char *value) { int ret = uwsgi_stats_keyval(us, key, value); if (ret) return -1; return uwsgi_stats_comma(us); } int uwsgi_stats_keyvalnum(struct uwsgi_stats *us, char *key, char *value, unsigned long long num) { if (uwsgi_stats_apply_tabs(us)) return -1; char *ptr = us->base + us->pos; char *watermark = us->base + us->size; size_t available = watermark - ptr; int ret = snprintf(ptr, available, "\"%s\":\"%s%llu\"", key, value, num); if (ret <= 0) return -1; while (ret >= (int) available) { char *new_base = realloc(us->base, us->size + us->chunk); if (!new_base) return -1; us->base = new_base; us->size += us->chunk; ptr = us->base + us->pos; watermark = us->base + us->size; available = watermark - ptr; ret = snprintf(ptr, available, "\"%s\":\"%s%llu\"", key, value, num); if (ret <= 0) return -1; } us->pos += ret; return 0; } int uwsgi_stats_keyvalnum_comma(struct uwsgi_stats *us, char *key, char *value, unsigned long long num) { int ret = uwsgi_stats_keyvalnum(us, key, value, num); if (ret) return -1; return uwsgi_stats_comma(us); } int uwsgi_stats_keyvaln(struct uwsgi_stats *us, char *key, char *value, int vallen) { if (uwsgi_stats_apply_tabs(us)) return -1; char *ptr = us->base + us->pos; char *watermark = us->base + us->size; size_t available = watermark - ptr; int ret = snprintf(ptr, available, "\"%s\":\"%.*s\"", key, vallen, value); if (ret <= 0) return -1; while (ret >= (int) available) { char *new_base = realloc(us->base, us->size + us->chunk); if (!new_base) return -1; us->base = new_base; us->size += us->chunk; ptr = us->base + us->pos; watermark = us->base + us->size; available = watermark - ptr; ret = snprintf(ptr, available, "\"%s\":\"%.*s\"", key, vallen, value); if (ret <= 0) return -1; } us->pos += ret; return 0; } int uwsgi_stats_keyvaln_comma(struct uwsgi_stats *us, char *key, char *value, int vallen) { int ret = uwsgi_stats_keyvaln(us, key, value, vallen); if (ret) return -1; return uwsgi_stats_comma(us); } int uwsgi_stats_key(struct uwsgi_stats *us, char *key) { if (uwsgi_stats_apply_tabs(us)) return -1; char *ptr = us->base + us->pos; char *watermark = us->base + us->size; size_t available = watermark - ptr; int ret = snprintf(ptr, available, "\"%s\":", key); if (ret <= 0) return -1; while (ret >= (int) available) { char *new_base = realloc(us->base, us->size + us->chunk); if (!new_base) return -1; us->base = new_base; us->size += us->chunk; ptr = us->base + us->pos; watermark = us->base + us->size; available = watermark - ptr; ret = snprintf(ptr, available, "\"%s\":", key); if (ret <= 0) return -1; } us->pos += ret; return 0; } int uwsgi_stats_str(struct uwsgi_stats *us, char *str) { char *ptr = us->base + us->pos; char *watermark = us->base + us->size; size_t available = watermark - ptr; int ret = snprintf(ptr, available, "\"%s\"", str); if (ret <= 0) return -1; while (ret >= (int) available) { char *new_base = realloc(us->base, us->size + us->chunk); if (!new_base) return -1; us->base = new_base; us->size += us->chunk; ptr = us->base + us->pos; watermark = us->base + us->size; available = watermark - ptr; ret = snprintf(ptr, available, "\"%s\"", str); if (ret <= 0) return -1; } us->pos += ret; return 0; } int uwsgi_stats_keylong(struct uwsgi_stats *us, char *key, unsigned long long num) { if (uwsgi_stats_apply_tabs(us)) return -1; char *ptr = us->base + us->pos; char *watermark = us->base + us->size; size_t available = watermark - ptr; int ret = snprintf(ptr, available, "\"%s\":%llu", key, num); if (ret <= 0) return -1; while (ret >= (int) available) { char *new_base = realloc(us->base, us->size + us->chunk); if (!new_base) return -1; us->base = new_base; us->size += us->chunk; ptr = us->base + us->pos; watermark = us->base + us->size; available = watermark - ptr; ret = snprintf(ptr, available, "\"%s\":%llu", key, num); if (ret <= 0) return -1; } us->pos += ret; return 0; } int uwsgi_stats_keylong_comma(struct uwsgi_stats *us, char *key, unsigned long long num) { int ret = uwsgi_stats_keylong(us, key, num); if (ret) return -1; return uwsgi_stats_comma(us); } int uwsgi_stats_keyslong(struct uwsgi_stats *us, char *key, long long num) { if (uwsgi_stats_apply_tabs(us)) return -1; char *ptr = us->base + us->pos; char *watermark = us->base + us->size; size_t available = watermark - ptr; int ret = snprintf(ptr, available, "\"%s\":%lld", key, num); if (ret <= 0) return -1; while (ret >= (int) available) { char *new_base = realloc(us->base, us->size + us->chunk); if (!new_base) return -1; us->base = new_base; us->size += us->chunk; ptr = us->base + us->pos; watermark = us->base + us->size; available = watermark - ptr; ret = snprintf(ptr, available, "\"%s\":%lld", key, num); if (ret <= 0) return -1; } us->pos += ret; return 0; } int uwsgi_stats_keyslong_comma(struct uwsgi_stats *us, char *key, long long num) { int ret = uwsgi_stats_keyslong(us, key, num); if (ret) return -1; return uwsgi_stats_comma(us); } void uwsgi_send_stats(int fd, struct uwsgi_stats *(*func) (void)) { struct sockaddr_un client_src; socklen_t client_src_len = 0; int client_fd = accept(fd, (struct sockaddr *) &client_src, &client_src_len); if (client_fd < 0) { uwsgi_error("accept()"); return; } if (uwsgi.stats_http) { if (uwsgi_send_http_stats(client_fd)) { close(client_fd); return; } } struct uwsgi_stats *us = func(); if (!us) goto end; size_t remains = us->pos; off_t pos = 0; while (remains > 0) { int ret = uwsgi_waitfd_write(client_fd, uwsgi.socket_timeout); if (ret <= 0) { goto end0; } ssize_t res = write(client_fd, us->base + pos, remains); if (res <= 0) { if (res < 0) { uwsgi_error("write()"); } goto end0; } pos += res; remains -= res; } end0: free(us->base); free(us); end: close(client_fd); } struct uwsgi_stats_pusher *uwsgi_stats_pusher_get(char *name) { struct uwsgi_stats_pusher *usp = uwsgi.stats_pushers; while (usp) { if (!strcmp(usp->name, name)) { return usp; } usp = usp->next; } return usp; } struct uwsgi_stats_pusher_instance *uwsgi_stats_pusher_add(struct uwsgi_stats_pusher *pusher, char *arg) { struct uwsgi_stats_pusher_instance *old_uspi = NULL, *uspi = uwsgi.stats_pusher_instances; while (uspi) { old_uspi = uspi; uspi = uspi->next; } uspi = uwsgi_calloc(sizeof(struct uwsgi_stats_pusher_instance)); uspi->pusher = pusher; if (arg) { uspi->arg = uwsgi_str(arg); } uspi->raw = pusher->raw; if (old_uspi) { old_uspi->next = uspi; } else { uwsgi.stats_pusher_instances = uspi; } return uspi; } void uwsgi_stats_pusher_loop(struct uwsgi_thread *ut) { void *events = event_queue_alloc(1); for (;;) { int nevents = event_queue_wait_multi(ut->queue, 1, events, 1); if (nevents < 0) { if (errno == EINTR) continue; uwsgi_log_verbose("ending the stats pusher thread...\n"); return; } if (nevents > 0) { int interesting_fd = event_queue_interesting_fd(events, 0); char buf[4096]; ssize_t len = read(interesting_fd, buf, 4096); if (len <= 0) { uwsgi_log("[uwsgi-stats-pusher] goodbye...\n"); return; } uwsgi_log("[uwsgi-stats-pusher] message received from master: %.*s\n", (int) len, buf); continue; } time_t now = uwsgi_now(); struct uwsgi_stats_pusher_instance *uspi = uwsgi.stats_pusher_instances; struct uwsgi_stats *us = NULL; while (uspi) { int delta = uspi->freq ? uspi->freq : uwsgi.stats_pusher_default_freq; if (((uspi->last_run + delta) <= now) || (uspi->needs_retry && (uspi->next_retry <= now))) { if (uspi->needs_retry) uspi->retries++; if (uspi->raw) { uspi->pusher->func(uspi, now, NULL, 0); } else { if (!us) { us = uwsgi_master_generate_stats(); if (!us) goto next; } uspi->pusher->func(uspi, now, us->base, us->pos); } uspi->last_run = now; if (uspi->needs_retry && uspi->max_retries > 0 && uspi->retries < uspi->max_retries) { uwsgi_log("[uwsgi-stats-pusher] %s failed (%d), retry in %ds\n", uspi->pusher->name, uspi->retries, uspi->retry_delay); uspi->next_retry = now + uspi->retry_delay; } else if (uspi->needs_retry && uspi->retries >= uspi->max_retries) { uwsgi_log("[uwsgi-stats-pusher] %s failed and maximum number of retries was reached (%d)\n", uspi->pusher->name, uspi->retries); uspi->needs_retry = 0; uspi->retries = 0; } else if (uspi->retries) { uwsgi_log("[uwsgi-stats-pusher] retry succeeded for %s\n", uspi->pusher->name); uspi->retries = 0; } } next: uspi = uspi->next; } if (us) { free(us->base); free(us); } } } void uwsgi_stats_pusher_setup() { struct uwsgi_string_list *usl = uwsgi.requested_stats_pushers; while (usl) { char *ssp = uwsgi_str(usl->value); struct uwsgi_stats_pusher *pusher = NULL; char *colon = strchr(ssp, ':'); if (colon) { *colon = 0; } pusher = uwsgi_stats_pusher_get(ssp); if (!pusher) { uwsgi_log("unable to find \"%s\" stats_pusher\n", ssp); free(ssp); exit(1); } char *arg = NULL; if (colon) { arg = colon + 1; *colon = ':'; } uwsgi_stats_pusher_add(pusher, arg); usl = usl->next; free(ssp); } } struct uwsgi_stats_pusher *uwsgi_register_stats_pusher(char *name, void (*func) (struct uwsgi_stats_pusher_instance *, time_t, char *, size_t)) { struct uwsgi_stats_pusher *pusher = uwsgi.stats_pushers, *old_pusher = NULL; while (pusher) { old_pusher = pusher; pusher = pusher->next; } pusher = uwsgi_calloc(sizeof(struct uwsgi_stats_pusher)); pusher->name = name; pusher->func = func; if (old_pusher) { old_pusher->next = pusher; } else { uwsgi.stats_pushers = pusher; } return pusher; } static void stats_dump_var(char *k, uint16_t kl, char *v, uint16_t vl, void *data) { struct uwsgi_stats *us = (struct uwsgi_stats *) data; if (us->dirty) return; char *var = uwsgi_concat3n(k, kl, "=", 1, v,vl); char *escaped_var = uwsgi_malloc(((kl+vl+1)*2)+1); escape_json(var, strlen(var), escaped_var); free(var); if (uwsgi_stats_str(us, escaped_var)) { us->dirty = 1; free(escaped_var); return; } free(escaped_var); if (uwsgi_stats_comma(us)) { us->dirty = 1; } return; } int uwsgi_stats_dump_vars(struct uwsgi_stats *us, struct uwsgi_core *uc) { if (!uc->in_request) return 0; struct uwsgi_header *uh = (struct uwsgi_header *) uc->buffer; uint16_t pktsize = uh->pktsize; if (!pktsize) return 0; char *dst = uwsgi.workers[0].cores[0].buffer; memcpy(dst, uc->buffer+4, uwsgi.buffer_size); // ok now check if something changed... if (!uc->in_request) return 0; if (uh->pktsize != pktsize) return 0; if (memcmp(dst, uc->buffer+4, uwsgi.buffer_size)) return 0; // nothing changed let's dump vars int ret = uwsgi_hooked_parse(dst, pktsize, stats_dump_var, us); if (ret) return -1; if (us->dirty) return -1; if (uwsgi_stats_str(us, "")) return -1; return 0; } int uwsgi_stats_dump_request(struct uwsgi_stats *us, struct uwsgi_core *uc) { if (!uc->in_request) return 0; struct wsgi_request req = uc->req; uwsgi_stats_keylong(us, "request_start", req.start_of_request_in_sec); return 0; } uwsgi-2.0.29/core/storage.c000066400000000000000000000022471477626554400155330ustar00rootroot00000000000000#include "../uwsgi.h" /* Storage subsystem: filesystem-like abstraction struct uwsgi_storage_engine { char *name; uint16_t name_len; int64_t (*get)(char *, uint16_t, char *, uint64_t, uint64_t, uint64_t); int64_t (*set)(char *, uint16_t, char *, uint64_t, uint64_t, uint64_t); }; struct uwsgi_storage { char *name; uint16_t name_len; struct uwsgi_storage_engine *engine; }; */ struct uwsgi_storage* uwsgi_storage_by_name(char *name, uint16_t name_len) { if (!name_len) { name_len = strlen(name); } struct uwsgi_storage *s = uwsgi.virtualdisks; while(s) { if (!uwsgi_strncmp(s->name, s->name_len, name, name_len)) { return s; } s = s->next; } return NULL; } int64_t uwsgi_storage_get(struct uwsgi_storage *storage, char *key, uint16_t key_len, char *out_buf, uint64_t pos, uint64_t size, uint64_t flags) { if (!storage->get) return -1; return storage->get(key, key_len, out_buf, pos, size, flags); } int64_t uwsgi_storage_set(struct uwsgi_storage *storage, char *key, uint16_t key_len, char *in_buf, uint64_t pos, uint64_t size, uint64_t flags) { if (!storage->set) return -1; return storage->set(key, key_len, out_buf, pos, size, flags); } uwsgi-2.0.29/core/strings.c000066400000000000000000000232131477626554400155540ustar00rootroot00000000000000#include "uwsgi.h" char *uwsgi_str_split_nget(char *str, size_t len, char what, size_t pos, size_t *rlen) { size_t i; size_t current = 0; char *choosen = str; size_t choosen_len = 0; *rlen = 0; for(i=0;ilen) { if (!memcmp(key, usl->value, keylen)) { return usl; } } usl = usl->next; } return NULL; } // lower a string char *uwsgi_lower(char *str, size_t size) { size_t i; for (i = 0; i < size; i++) { str[i] = tolower((int) str[i]); } return str; } // check if a string is contained in another one char *uwsgi_str_contains(char *str, int slen, char what) { int i; for (i = 0; i < slen; i++) { if (str[i] == what) { return str + i; } } return NULL; } int uwsgi_contains_n(char *s1, size_t s1_len, char *s2, size_t s2_len) { size_t i; char *ptr = s2; for (i = 0; i < s1_len; i++) { if (s1[i] == *ptr) { ptr++; if (ptr == s2 + s2_len) { return 1; } } else { ptr = s2; } } return 0; } // fast compare 2 sized strings int uwsgi_strncmp(char *src, int slen, char *dst, int dlen) { if (slen != dlen) return 1; return memcmp(src, dst, dlen); } // fast compare 2 sized strings (case insensitive) int uwsgi_strnicmp(char *src, int slen, char *dst, int dlen) { if (slen != dlen) return 1; return strncasecmp(src, dst, dlen); } // fast sized check of initial part of a string int uwsgi_starts_with(char *src, int slen, char *dst, int dlen) { if (slen < dlen) return -1; return memcmp(src, dst, dlen); } // unsized check int uwsgi_startswith(char *src, char *what, int wlen) { int i; for (i = 0; i < wlen; i++) { if (src[i] != what[i]) return -1; } return 0; } // concatenate strings char *uwsgi_concatn(int c, ...) { va_list s; char *item; int j = c; char *buf; size_t len = 1; size_t tlen = 1; va_start(s, c); while (j > 0) { item = va_arg(s, char *); if (item == NULL) { break; } len += va_arg(s, int); j--; } va_end(s); buf = uwsgi_malloc(len); memset(buf, 0, len); j = c; len = 0; va_start(s, c); while (j > 0) { item = va_arg(s, char *); if (item == NULL) { break; } tlen = va_arg(s, int); memcpy(buf + len, item, tlen); len += tlen; j--; } va_end(s); return buf; } char *uwsgi_concat2(char *one, char *two) { char *buf; size_t len = strlen(one) + strlen(two) + 1; buf = uwsgi_malloc(len); buf[len - 1] = 0; memcpy(buf, one, strlen(one)); memcpy(buf + strlen(one), two, strlen(two)); return buf; } char *uwsgi_concat4(char *one, char *two, char *three, char *four) { char *buf; size_t len = strlen(one) + strlen(two) + strlen(three) + strlen(four) + 1; buf = uwsgi_malloc(len); buf[len - 1] = 0; memcpy(buf, one, strlen(one)); memcpy(buf + strlen(one), two, strlen(two)); memcpy(buf + strlen(one) + strlen(two), three, strlen(three)); memcpy(buf + strlen(one) + strlen(two) + strlen(three), four, strlen(four)); return buf; } char *uwsgi_concat3(char *one, char *two, char *three) { char *buf; size_t len = strlen(one) + strlen(two) + strlen(three) + 1; buf = uwsgi_malloc(len); buf[len - 1] = 0; memcpy(buf, one, strlen(one)); memcpy(buf + strlen(one), two, strlen(two)); memcpy(buf + strlen(one) + strlen(two), three, strlen(three)); return buf; } char *uwsgi_concat2n(char *one, int s1, char *two, int s2) { char *buf; size_t len = s1 + s2 + 1; buf = uwsgi_malloc(len); buf[len - 1] = 0; memcpy(buf, one, s1); memcpy(buf + s1, two, s2); return buf; } char *uwsgi_concat2nn(char *one, int s1, char *two, int s2, int *len) { char *buf; *len = s1 + s2 + 1; buf = uwsgi_malloc(*len); buf[*len - 1] = 0; memcpy(buf, one, s1); memcpy(buf + s1, two, s2); return buf; } char *uwsgi_concat3n(char *one, int s1, char *two, int s2, char *three, int s3) { char *buf; size_t len = s1 + s2 + s3 + 1; buf = uwsgi_malloc(len); buf[len - 1] = 0; memcpy(buf, one, s1); memcpy(buf + s1, two, s2); memcpy(buf + s1 + s2, three, s3); return buf; } char *uwsgi_concat4n(char *one, int s1, char *two, int s2, char *three, int s3, char *four, int s4) { char *buf; size_t len = s1 + s2 + s3 + s4 + 1; buf = uwsgi_malloc(len); buf[len - 1] = 0; memcpy(buf, one, s1); memcpy(buf + s1, two, s2); memcpy(buf + s1 + s2, three, s3); memcpy(buf + s1 + s2 + s3, four, s4); return buf; } // concat unsized strings char *uwsgi_concat(int c, ...) { va_list s; char *item; size_t len = 1; int j = c; char *buf; va_start(s, c); while (j > 0) { item = va_arg(s, char *); if (item == NULL) { break; } len += (int) strlen(item); j--; } va_end(s); buf = uwsgi_malloc(len); memset(buf, 0, len); j = c; len = 0; va_start(s, c); while (j > 0) { item = va_arg(s, char *); if (item == NULL) { break; } memcpy(buf + len, item, strlen(item)); len += strlen(item); j--; } va_end(s); return buf; } char *uwsgi_strncopy(char *s, int len) { char *buf; buf = uwsgi_malloc(len + 1); buf[len] = 0; memcpy(buf, s, len); return buf; } // this move a string back of one char and put a 0 at the end (used in uwsgi parsers for buffer reusing) char *uwsgi_cheap_string(char *buf, int len) { int i; char *cheap_buf = buf - 1; for (i = 0; i < len; i++) { *cheap_buf++ = buf[i]; } buf[len - 1] = 0; return buf - 1; } /* status 0: append mode status 1: single quote found status 2: double quote found status 3: backslash found (on 0) status 4: backslash found (on 1) status 5: backslash found (on 2) */ char ** uwsgi_split_quoted(char *what, size_t what_len, char *sep, size_t *rlen) { size_t i; int status = 0; char *base = uwsgi_concat2n(what, what_len, "", 0); char *item = NULL; char *ptr = NULL; *rlen = 0; char **ret = (char **) uwsgi_malloc(sizeof(char *) * (what_len+1)); for(i=0;isni_key_len > 0 && usr->sni_crt_len > 0) { if (!current_slot->sni_enabled) { char *sni_key = uwsgi_concat2n(usr->sni_key, usr->sni_key_len, "", 0); char *sni_crt = uwsgi_concat2n(usr->sni_crt, usr->sni_crt_len, "", 0); char *sni_ca = NULL; if (usr->sni_ca_len > 0) { sni_ca = uwsgi_concat2n(usr->sni_ca, usr->sni_ca_len, "", 0); } char *servername = NULL; char *colon = memchr(current_slot->key, ':', current_slot->keylen); if (colon) { servername = uwsgi_concat2n(current_slot->key, colon - current_slot->key, "", 0); } else { servername = uwsgi_concat2n(current_slot->key, current_slot->keylen, "", 0); } if (uwsgi_ssl_add_sni_item(servername, sni_crt, sni_key, uwsgi.sni_dir_ciphers, sni_ca)) { current_slot->sni_enabled = 1; } if (sni_key) free(sni_key); if (sni_crt) free(sni_crt); if (sni_ca) free(sni_ca); } } } #endif int uwsgi_subscription_credentials_check(struct uwsgi_subscribe_slot *slot, struct uwsgi_subscribe_req *usr) { struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, uwsgi.subscriptions_credentials_check_dir) { char *filename = uwsgi_concat2n(usl->value, usl->len, slot->key, slot->keylen); struct stat st; int ret = stat(filename, &st); free(filename); if (ret != 0) continue; if (st.st_uid != usr->uid) continue; if (st.st_gid != usr->gid) continue; // accepted... return 1; } return 0; } struct uwsgi_subscribe_slot *uwsgi_get_subscribe_slot(struct uwsgi_subscribe_slot **slot, char *key, uint16_t keylen) { if (keylen > 0xff) return NULL; uint32_t hash = djb33x_hash(key, keylen); int hash_key = hash % 0xffff; struct uwsgi_subscribe_slot *current_slot = slot[hash_key]; #ifdef UWSGI_DEBUG uwsgi_log("****************************\n"); while (current_slot) { uwsgi_log("slot %.*s %d\n", current_slot->keylen, current_slot->key, current_slot->hits); current_slot = current_slot->next; } uwsgi_log("****************************\n"); current_slot = slot[hash_key]; #endif while (current_slot) { if (!uwsgi_strncmp(key, keylen, current_slot->key, current_slot->keylen)) { // auto optimization if (current_slot->prev) { if (current_slot->hits > current_slot->prev->hits) { struct uwsgi_subscribe_slot *slot_parent = current_slot->prev->prev, *slot_prev = current_slot->prev; if (slot_parent) { slot_parent->next = current_slot; } else { slot[hash_key] = current_slot; } if (current_slot->next) { current_slot->next->prev = slot_prev; } slot_prev->prev = current_slot; slot_prev->next = current_slot->next; current_slot->next = slot_prev; current_slot->prev = slot_parent; } } return current_slot; } current_slot = current_slot->next; // check for loopy optimization if (current_slot == slot[hash_key]) break; } return NULL; } // least reference count static struct uwsgi_subscribe_node *uwsgi_subscription_algo_lrc(struct uwsgi_subscribe_slot *current_slot, struct uwsgi_subscribe_node *node) { // if node is NULL we are in the second step (in lrc mode we do not use the first step) if (node) return NULL; struct uwsgi_subscribe_node *choosen_node = NULL; node = current_slot->nodes; uint64_t min_rc = 0; while (node) { if (!node->death_mark) { if (min_rc == 0 || node->reference < min_rc) { min_rc = node->reference; choosen_node = node; if (min_rc == 0 && !(node->next && node->next->reference <= node->reference && node->next->last_requests <= node->last_requests)) break; } } node = node->next; } if (choosen_node) { choosen_node->reference++; } return choosen_node; } // weighted least reference count static struct uwsgi_subscribe_node *uwsgi_subscription_algo_wlrc(struct uwsgi_subscribe_slot *current_slot, struct uwsgi_subscribe_node *node) { // if node is NULL we are in the second step (in wlrc mode we do not use the first step) if (node) return NULL; struct uwsgi_subscribe_node *choosen_node = NULL; node = current_slot->nodes; double min_rc = 0; while (node) { if (!node->death_mark) { // node->weight is always >= 1, we can safely use it as divider double ref = (double) node->reference / (double) node->weight; double next_node_ref = 0; if (node->next) next_node_ref = (double) node->next->reference / (double) node->next->weight; if (min_rc == 0 || ref < min_rc) { min_rc = ref; choosen_node = node; if (min_rc == 0 && !(node->next && next_node_ref <= ref && node->next->last_requests <= node->last_requests)) break; } } node = node->next; } if (choosen_node) { choosen_node->reference++; } return choosen_node; } // weighted round robin algo static struct uwsgi_subscribe_node *uwsgi_subscription_algo_wrr(struct uwsgi_subscribe_slot *current_slot, struct uwsgi_subscribe_node *node) { // if node is NULL we are in the second step if (node) { if (node->death_mark == 0 && node->wrr > 0) { node->wrr--; node->reference++; return node; } return NULL; } // no wrr > 0 node found, reset them node = current_slot->nodes; uint64_t min_weight = 0; while (node) { if (!node->death_mark) { if (min_weight == 0 || node->weight < min_weight) min_weight = node->weight; } node = node->next; } // now set wrr node = current_slot->nodes; struct uwsgi_subscribe_node *choosen_node = NULL; while (node) { if (!node->death_mark) { node->wrr = node->weight / min_weight; choosen_node = node; } node = node->next; } if (choosen_node) { choosen_node->wrr--; choosen_node->reference++; } return choosen_node; } void uwsgi_subscription_set_algo(char *algo) { if (!algo) goto wrr; if (!strcmp(algo, "wrr")) { uwsgi.subscription_algo = uwsgi_subscription_algo_wrr; return; } if (!strcmp(algo, "lrc")) { uwsgi.subscription_algo = uwsgi_subscription_algo_lrc; return; } if (!strcmp(algo, "wlrc")) { uwsgi.subscription_algo = uwsgi_subscription_algo_wlrc; return; } wrr: uwsgi.subscription_algo = uwsgi_subscription_algo_wrr; } struct uwsgi_subscribe_node *uwsgi_get_subscribe_node(struct uwsgi_subscribe_slot **slot, char *key, uint16_t keylen) { if (keylen > 0xff) return NULL; struct uwsgi_subscribe_slot *current_slot = uwsgi_get_subscribe_slot(slot, key, keylen); if (!current_slot) return NULL; // slot found, move up in the list increasing hits current_slot->hits++; time_t now = uwsgi_now(); struct uwsgi_subscribe_node *node = current_slot->nodes; while (node) { // is the node alive ? if (now - node->last_check > uwsgi.subscription_tolerance) { if (node->death_mark == 0) uwsgi_log("[uwsgi-subscription for pid %d] %.*s => marking %.*s as failed (no announce received in %d seconds)\n", (int) uwsgi.mypid, (int) keylen, key, (int) node->len, node->name, uwsgi.subscription_tolerance); node->failcnt++; node->death_mark = 1; } // do i need to remove the node ? if (node->death_mark && node->reference == 0) { // remove the node and move to next struct uwsgi_subscribe_node *dead_node = node; node = node->next; // if the slot has been removed, return NULL; if (uwsgi_remove_subscribe_node(slot, dead_node) == 1) { return NULL; } continue; } struct uwsgi_subscribe_node *choosen_node = uwsgi.subscription_algo(current_slot, node); if (choosen_node) return choosen_node; node = node->next; } return uwsgi.subscription_algo(current_slot, node); } struct uwsgi_subscribe_node *uwsgi_get_subscribe_node_by_name(struct uwsgi_subscribe_slot **slot, char *key, uint16_t keylen, char *val, uint16_t vallen) { if (keylen > 0xff) return NULL; struct uwsgi_subscribe_slot *current_slot = uwsgi_get_subscribe_slot(slot, key, keylen); if (current_slot) { struct uwsgi_subscribe_node *node = current_slot->nodes; while (node) { if (!uwsgi_strncmp(val, vallen, node->name, node->len)) { return node; } node = node->next; } } return NULL; } int uwsgi_remove_subscribe_node(struct uwsgi_subscribe_slot **slot, struct uwsgi_subscribe_node *node) { int ret = 0; struct uwsgi_subscribe_node *a_node; struct uwsgi_subscribe_slot *node_slot = node->slot; struct uwsgi_subscribe_slot *prev_slot = node_slot->prev; struct uwsgi_subscribe_slot *next_slot = node_slot->next; int hash_key = node_slot->hash; // over-engineering to avoid race conditions node->len = 0; if (node == node_slot->nodes) { node_slot->nodes = node->next; } else { a_node = node_slot->nodes; while (a_node) { if (a_node->next == node) { a_node->next = node->next; break; } a_node = a_node->next; } } free(node); // no more nodes, remove the slot too if (node_slot->nodes == NULL) { ret = 1; // first check if i am the only node if ((!prev_slot && !next_slot) || next_slot == node_slot) { #ifdef UWSGI_SSL if (node_slot->sign_ctx) { EVP_PKEY_free(node_slot->sign_public_key); EVP_MD_CTX_destroy(node_slot->sign_ctx); } #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME // if there is a SNI context active, destroy it if (node_slot->sni_enabled) { uwsgi_ssl_del_sni_item(node_slot->key, node_slot->keylen); } #endif #endif free(node_slot); slot[hash_key] = NULL; goto end; } // if i am the main entry point, set the next value if (node_slot == slot[hash_key]) { slot[hash_key] = next_slot; } if (prev_slot) { prev_slot->next = next_slot; } if (next_slot) { next_slot->prev = prev_slot; } #ifdef UWSGI_SSL if (node_slot->sign_ctx) { EVP_PKEY_free(node_slot->sign_public_key); EVP_MD_CTX_destroy(node_slot->sign_ctx); } #endif free(node_slot); } end: return ret; } #ifdef UWSGI_SSL static int subscription_new_sign_ctx(struct uwsgi_subscribe_slot *, struct uwsgi_subscribe_req *); static int subscription_is_safe(struct uwsgi_subscribe_req *); #endif struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slot **slot, struct uwsgi_subscribe_req *usr) { struct uwsgi_subscribe_slot *current_slot = uwsgi_get_subscribe_slot(slot, usr->key, usr->keylen), *old_slot = NULL, *a_slot; struct uwsgi_subscribe_node *node, *old_node = NULL; if (usr->address_len > 0xff || usr->address_len == 0) return NULL; if (current_slot) { #ifdef UWSGI_SSL if (uwsgi.subscriptions_sign_check_dir && !uwsgi_subscription_sign_check(current_slot, usr)) { return NULL; } #endif if (uwsgi.subscriptions_credentials_check_dir && !uwsgi_subscription_credentials_check(current_slot, usr)) { return NULL; } node = current_slot->nodes; while (node) { if (!uwsgi_strncmp(node->name, node->len, usr->address, usr->address_len)) { #ifdef UWSGI_SSL // this should avoid sending sniffed packets... if (current_slot->sign_ctx && !subscription_is_safe(usr) && usr->unix_check <= node->unix_check) { uwsgi_log("[uwsgi-subscription for pid %d] invalid (sniffed ?) packet sent for slot: %.*s node: %.*s unix_check: %lu\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address, (unsigned long) usr->unix_check); return NULL; } // eventually the packet could be upgraded to sni... uwsgi_subscription_sni_check(current_slot, usr); #endif // remove death mark and update cores and load node->death_mark = 0; node->last_check = uwsgi_now(); node->cores = usr->cores; node->load = usr->load; node->weight = usr->weight; if (!node->weight) node->weight = 1; node->last_requests = 0; return node; } old_node = node; node = node->next; } #ifdef UWSGI_SSL if (current_slot->sign_ctx && !subscription_is_safe(usr) && usr->unix_check < (uwsgi_now() - (time_t) uwsgi.subscriptions_sign_check_tolerance)) { uwsgi_log("[uwsgi-subscription for pid %d] invalid (sniffed ?) packet sent for slot: %.*s node: %.*s unix_check: %lu\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address, (unsigned long) usr->unix_check); return NULL; } // check here as we are sure the node will be added uwsgi_subscription_sni_check(current_slot, usr); #endif node = uwsgi_malloc(sizeof(struct uwsgi_subscribe_node)); node->len = usr->address_len; node->modifier1 = usr->modifier1; node->modifier2 = usr->modifier2; node->requests = 0; node->last_requests = 0; node->tx = 0; node->rx = 0; node->reference = 0; node->death_mark = 0; node->failcnt = 0; node->cores = usr->cores; node->load = usr->load; node->weight = usr->weight; node->unix_check = usr->unix_check; if (!node->weight) node->weight = 1; node->wrr = 0; node->pid = usr->pid; node->uid = usr->uid; node->gid = usr->gid; node->notify[0] = 0; if (usr->notify_len > 0 && usr->notify_len < 102) { memcpy(node->notify, usr->notify, usr->notify_len); node->notify[usr->notify_len] = 0; } node->last_check = uwsgi_now(); node->slot = current_slot; memcpy(node->name, usr->address, usr->address_len); if (old_node) { old_node->next = node; } node->next = NULL; uwsgi_log("[uwsgi-subscription for pid %d] %.*s => new node: %.*s\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address); if (node->notify[0]) { char buf[1024]; int ret = snprintf(buf, 1024, "[subscription ack] %.*s => new node: %.*s", usr->keylen, usr->key, usr->address_len, usr->address); if (ret > 0 && ret < 1024) uwsgi_notify_msg(node->notify, buf, ret); } return node; } else { current_slot = uwsgi_malloc(sizeof(struct uwsgi_subscribe_slot)); #ifdef UWSGI_SSL current_slot->sign_ctx = NULL; if (uwsgi.subscriptions_sign_check_dir && !subscription_new_sign_ctx(current_slot, usr)) { free(current_slot); return NULL; } #endif uint32_t hash = djb33x_hash(usr->key, usr->keylen); int hash_key = hash % 0xffff; current_slot->hash = hash_key; current_slot->keylen = usr->keylen; memcpy(current_slot->key, usr->key, usr->keylen); if (uwsgi.subscriptions_credentials_check_dir) { if (!uwsgi_subscription_credentials_check(current_slot, usr)) { free(current_slot); return NULL; } } current_slot->key[usr->keylen] = 0; current_slot->hits = 0; #ifdef UWSGI_SSL current_slot->sni_enabled = 0; uwsgi_subscription_sni_check(current_slot, usr); #endif current_slot->nodes = uwsgi_malloc(sizeof(struct uwsgi_subscribe_node)); current_slot->nodes->slot = current_slot; current_slot->nodes->len = usr->address_len; current_slot->nodes->reference = 0; current_slot->nodes->requests = 0; current_slot->nodes->last_requests = 0; current_slot->nodes->tx = 0; current_slot->nodes->rx = 0; current_slot->nodes->death_mark = 0; current_slot->nodes->failcnt = 0; current_slot->nodes->modifier1 = usr->modifier1; current_slot->nodes->modifier2 = usr->modifier2; current_slot->nodes->cores = usr->cores; current_slot->nodes->load = usr->load; current_slot->nodes->weight = usr->weight; current_slot->nodes->unix_check = usr->unix_check; if (!current_slot->nodes->weight) current_slot->nodes->weight = 1; current_slot->nodes->wrr = 0; current_slot->nodes->pid = usr->pid; current_slot->nodes->uid = usr->uid; current_slot->nodes->gid = usr->gid; current_slot->nodes->notify[0] = 0; if (usr->notify_len > 0 && usr->notify_len < 102) { memcpy(current_slot->nodes->notify, usr->notify, usr->notify_len); current_slot->nodes->notify[usr->notify_len] = 0; } memcpy(current_slot->nodes->name, usr->address, usr->address_len); current_slot->nodes->last_check = uwsgi_now(); current_slot->nodes->next = NULL; a_slot = slot[hash_key]; while (a_slot) { old_slot = a_slot; a_slot = a_slot->next; } if (old_slot) { old_slot->next = current_slot; } current_slot->prev = old_slot; current_slot->next = NULL; if (!slot[hash_key] || current_slot->prev == NULL) { slot[hash_key] = current_slot; } uwsgi_log("[uwsgi-subscription for pid %d] new pool: %.*s (hash key: %d)\n", (int) uwsgi.mypid, usr->keylen, usr->key, current_slot->hash); uwsgi_log("[uwsgi-subscription for pid %d] %.*s => new node: %.*s\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address); if (current_slot->nodes->notify[0]) { char buf[1024]; int ret = snprintf(buf, 1024, "[subscription ack] %.*s => new node: %.*s", usr->keylen, usr->key, usr->address_len, usr->address); if (ret > 0 && ret < 1024) uwsgi_notify_msg(current_slot->nodes->notify, buf, ret); } return current_slot->nodes; } } static void send_subscription(int sfd, char *host, char *message, uint16_t message_size) { int fd = sfd; struct sockaddr_in udp_addr; struct sockaddr_un un_addr; ssize_t ret; char *udp_port = strchr(host, ':'); if (fd == -1) { if (udp_port) { fd = socket(AF_INET, SOCK_DGRAM, 0); } else { fd = socket(AF_UNIX, SOCK_DGRAM, 0); } if (fd < 0) { uwsgi_error("send_subscription()/socket()"); return; } uwsgi_socket_nb(fd); } else if (fd == -2) { static int unix_fd = -1; static int inet_fd = -1; if (udp_port) { if (inet_fd == -1) { inet_fd = socket(AF_INET, SOCK_DGRAM, 0); if (inet_fd < 0) { uwsgi_error("send_subscription()/socket()"); return; } uwsgi_socket_nb(inet_fd); } fd = inet_fd; } else { if (unix_fd == -1) { unix_fd = socket(AF_UNIX, SOCK_DGRAM, 0); if (unix_fd < 0) { uwsgi_error("send_subscription()/socket()"); return; } uwsgi_socket_nb(unix_fd); } fd = unix_fd; } } if (udp_port) { udp_port[0] = 0; memset(&udp_addr, 0, sizeof(struct sockaddr_in)); udp_addr.sin_family = AF_INET; udp_addr.sin_port = htons(atoi(udp_port + 1)); udp_addr.sin_addr.s_addr = inet_addr(host); ret = sendto(fd, message, message_size, 0, (struct sockaddr *) &udp_addr, sizeof(udp_addr)); udp_port[0] = ':'; } else { memset(&un_addr, 0, sizeof(struct sockaddr_un)); un_addr.sun_family = AF_UNIX; // use 102 as the magic number strncat(un_addr.sun_path, host, 102); if (uwsgi.subscriptions_use_credentials) { // could be useless as internally the socket could add them automagically ret = uwsgi_pass_cred2(fd, message, message_size, (struct sockaddr *) &un_addr, sizeof(un_addr)); } else { ret = sendto(fd, message, message_size, 0, (struct sockaddr *) &un_addr, sizeof(un_addr)); } } if (ret < 0) { uwsgi_error("send_subscription()/sendto()"); } if (sfd == -1) close(fd); } static struct uwsgi_buffer *uwsgi_subscription_ub(char *key, size_t keysize, uint8_t modifier1, uint8_t modifier2, uint8_t cmd, char *socket_name, char *sign, char *sni_key, char *sni_crt, char *sni_ca) { struct uwsgi_buffer *ub = uwsgi_buffer_new(4096); // make space for uwsgi header ub->pos = 4; if (uwsgi_buffer_append_keyval(ub, "key", 3, key, keysize)) goto end; if (uwsgi_buffer_append_keyval(ub, "address", 7, socket_name, strlen(socket_name))) goto end; if (uwsgi.subscribe_with_modifier1) { modifier1 = atoi(uwsgi.subscribe_with_modifier1); } if (uwsgi_buffer_append_keynum(ub, "modifier1", 9, modifier1)) goto end; if (uwsgi_buffer_append_keynum(ub, "modifier2", 9, modifier2)) goto end; if (uwsgi_buffer_append_keynum(ub, "cores", 5, uwsgi.numproc * uwsgi.cores)) goto end; if (uwsgi_buffer_append_keynum(ub, "load", 4, uwsgi.shared->load)) goto end; if (uwsgi.auto_weight) { if (uwsgi_buffer_append_keynum(ub, "weight", 6, uwsgi.numproc * uwsgi.cores)) goto end; } else { if (uwsgi_buffer_append_keynum(ub, "weight", 6, uwsgi.weight)) goto end; } if (sni_key) { if (uwsgi_buffer_append_keyval(ub, "sni_key", 7, sni_key, strlen(sni_key))) goto end; } if (sni_crt) { if (uwsgi_buffer_append_keyval(ub, "sni_crt", 7, sni_crt, strlen(sni_crt))) goto end; } if (sni_ca) { if (uwsgi_buffer_append_keyval(ub, "sni_ca", 6, sni_ca, strlen(sni_ca))) goto end; } if (uwsgi.subscription_notify_socket) { if (uwsgi_buffer_append_keyval(ub, "notify", 6, uwsgi.subscription_notify_socket, strlen(uwsgi.subscription_notify_socket))) goto end; } else if (uwsgi.notify_socket_fd > -1 && uwsgi.notify_socket) { if (uwsgi_buffer_append_keyval(ub, "notify", 6, uwsgi.notify_socket, strlen(uwsgi.notify_socket))) goto end; } #ifdef UWSGI_SSL if (sign) { if (uwsgi_buffer_append_keynum(ub, "unix", 4, (uwsgi_now() + (time_t) cmd))) goto end; unsigned int signature_len = 0; char *signature = uwsgi_rsa_sign(sign, ub->buf + 4, ub->pos - 4, &signature_len); if (signature && signature_len > 0) { if (uwsgi_buffer_append_keyval(ub, "sign", 4, signature, signature_len)) { free(signature); goto end; } free(signature); } } #endif // add uwsgi header if (uwsgi_buffer_set_uh(ub, 224, cmd)) goto end; return ub; end: uwsgi_buffer_destroy(ub); return NULL; } void uwsgi_send_subscription_from_fd(int fd, char *udp_address, char *key, size_t keysize, uint8_t modifier1, uint8_t modifier2, uint8_t cmd, char *socket_name, char *sign, char *sni_key, char *sni_crt, char *sni_ca) { if (socket_name == NULL && !uwsgi.sockets) return; if (!socket_name) { socket_name = uwsgi.sockets->name; } struct uwsgi_buffer *ub = uwsgi_subscription_ub(key, keysize, modifier1, modifier2, cmd, socket_name, sign, sni_key, sni_crt, sni_ca); if (!ub) return; send_subscription(fd, udp_address, ub->buf, ub->pos); uwsgi_buffer_destroy(ub); } void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8_t modifier1, uint8_t modifier2, uint8_t cmd, char *socket_name, char *sign, char *sni_key, char *sni_crt, char *sni_ca) { uwsgi_send_subscription_from_fd(-1, udp_address, key, keysize, modifier1, modifier2, cmd, socket_name, sign, sni_key, sni_crt, sni_ca); } #ifdef UWSGI_SSL static int subscription_is_safe(struct uwsgi_subscribe_req *usr) { struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, uwsgi.subscriptions_sign_skip_uid) { if (usl->custom == 0) { usl->custom = atoi(usl->value); } if (usr->uid > 0 && usr->uid == (uid_t) usl->custom) { return 1; } } return 0; } static int subscription_new_sign_ctx(struct uwsgi_subscribe_slot *slot, struct uwsgi_subscribe_req *usr) { if (subscription_is_safe(usr)) return 1; if (usr->sign_len == 0 || usr->base_len == 0) return 0; if (usr->unix_check < (uwsgi_now() - (time_t) uwsgi.subscriptions_sign_check_tolerance)) { uwsgi_log("[uwsgi-subscription for pid %d] invalid (sniffed ?) packet sent for slot: %.*s node: %.*s unix_check: %lu\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address, (unsigned long) usr->unix_check); return 0; } char *keyfile = uwsgi_sanitize_cert_filename(uwsgi.subscriptions_sign_check_dir, usr->key, usr->keylen); FILE *kf = fopen(keyfile, "r"); free(keyfile); if (!kf) return 0; slot->sign_public_key = PEM_read_PUBKEY(kf, NULL, NULL, NULL); fclose(kf); if (!slot->sign_public_key) { uwsgi_log("unable to load public key for %.*s\n", usr->keylen, usr->key); return 0; } slot->sign_ctx = EVP_MD_CTX_create(); if (!slot->sign_ctx) { uwsgi_log("unable to initialize EVP context for %.*s\n", usr->keylen, usr->key); EVP_PKEY_free(slot->sign_public_key); return 0; } if (!uwsgi_subscription_sign_check(slot, usr)) { EVP_PKEY_free(slot->sign_public_key); EVP_MD_CTX_destroy(slot->sign_ctx); return 0; } return 1; } int uwsgi_subscription_sign_check(struct uwsgi_subscribe_slot *slot, struct uwsgi_subscribe_req *usr) { if (subscription_is_safe(usr)) return 1; if (usr->sign_len == 0 || usr->base_len == 0) return 0; if (!slot->sign_ctx) { if (!subscription_new_sign_ctx(slot, usr)) return 0; } if (EVP_VerifyInit_ex(slot->sign_ctx, uwsgi.subscriptions_sign_check_md, NULL) == 0) { ERR_print_errors_fp(stderr); return 0; } if (EVP_VerifyUpdate(slot->sign_ctx, usr->base, usr->base_len) == 0) { ERR_print_errors_fp(stderr); return 0; } if (EVP_VerifyFinal(slot->sign_ctx, (unsigned char *) usr->sign, usr->sign_len, slot->sign_public_key) != 1) { #ifdef UWSGI_DEBUG ERR_print_errors_fp(stderr); #endif return 0; } return 1; } #endif int uwsgi_no_subscriptions(struct uwsgi_subscribe_slot **slot) { int i; for (i = 0; i < UMAX16; i++) { if (slot[i]) return 0; } return 1; } struct uwsgi_subscribe_slot **uwsgi_subscription_init_ht() { if (!uwsgi.subscription_algo) { uwsgi_subscription_set_algo(NULL); } return uwsgi_calloc(sizeof(struct uwsgi_subscription_slot *) * UMAX16); } void uwsgi_subscribe(char *subscription, uint8_t cmd) { size_t subfile_size; size_t i; char *key = NULL; int keysize = 0; char *modifier1 = NULL; int modifier1_len = 0; char *socket_name = NULL; char *udp_address = subscription; char *udp_port = NULL; char *subscription_key = NULL; char *sign = NULL; // check for explicit socket_name char *equal = strchr(subscription, '='); if (equal) { socket_name = subscription; if (socket_name[0] == '=') { equal = strchr(socket_name + 1, '='); if (!equal) return; *equal = '\0'; struct uwsgi_socket *us = uwsgi_get_shared_socket_by_num(atoi(socket_name + 1)); if (!us) return; socket_name = us->name; } *equal = '\0'; udp_address = equal + 1; } // check for unix socket if (udp_address[0] != '/') { udp_port = strchr(udp_address, ':'); if (!udp_port) { if (equal) *equal = '='; return; } subscription_key = strchr(udp_port + 1, ':'); } else { subscription_key = strchr(udp_address + 1, ':'); } if (!subscription_key) { if (equal) *equal = '='; return; } udp_address = uwsgi_concat2n(udp_address, subscription_key - udp_address, "", 0); if (subscription_key[1] == '@') { if (!uwsgi_file_exists(subscription_key + 2)) goto clear; char *lines = uwsgi_open_and_read(subscription_key + 2, &subfile_size, 1, NULL); if (subfile_size > 0) { key = lines; for (i = 0; i < subfile_size; i++) { if (lines[i] == 0) { if (keysize > 0) { if (key[0] != '#' && key[0] != '\n') { modifier1 = strchr(key, ','); if (modifier1) { modifier1[0] = 0; modifier1++; modifier1_len = strlen(modifier1); keysize = strlen(key); } uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign, NULL, NULL, NULL); modifier1 = NULL; modifier1_len = 0; } } break; } else if (lines[i] == '\n') { if (keysize > 0) { if (key[0] != '#' && key[0] != '\n') { lines[i] = 0; modifier1 = strchr(key, ','); if (modifier1) { modifier1[0] = 0; modifier1++; modifier1_len = strlen(modifier1); keysize = strlen(key); } uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign, NULL, NULL, NULL); modifier1 = NULL; modifier1_len = 0; lines[i] = '\n'; } } key = lines + i + 1; keysize = 0; continue; } keysize++; } } free(lines); } else { modifier1 = strchr(subscription_key + 1, ','); if (modifier1) { modifier1[0] = 0; modifier1++; sign = strchr(modifier1 + 1, ','); if (sign) { *sign = 0; sign++; } modifier1_len = strlen(modifier1); } uwsgi_send_subscription(udp_address, subscription_key + 1, strlen(subscription_key + 1), uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign, NULL, NULL, NULL); if (modifier1) modifier1[-1] = ','; if (sign) sign[-1] = ','; } clear: if (equal) *equal = '='; free(udp_address); } void uwsgi_subscribe2(char *arg, uint8_t cmd) { char *s2_server = NULL; char *s2_key = NULL; char *s2_socket = NULL; char *s2_addr = NULL; char *s2_weight = NULL; char *s2_sign = NULL; char *s2_modifier1 = NULL; char *s2_modifier2 = NULL; char *s2_check = NULL; char *s2_sni_key = NULL; char *s2_sni_crt = NULL; char *s2_sni_ca = NULL; if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=', "server", &s2_server, "key", &s2_key, "socket", &s2_socket, "addr", &s2_addr, "weight", &s2_weight, "modifier1", &s2_modifier1, "modifier2", &s2_modifier2, "sign", &s2_sign, "check", &s2_check, "sni_key", &s2_sni_key, "sni_crt", &s2_sni_crt, "sni_ca", &s2_sni_ca, NULL)) { return; } if (!s2_server || !s2_key) goto end; if (s2_check) { if (uwsgi_file_exists(s2_check)) goto end; } if (s2_weight) { uwsgi.weight = atoi(s2_weight); } if (s2_socket) { struct uwsgi_socket *us = uwsgi_get_socket_by_num(atoi(s2_socket)); if (us) { if (s2_addr) { free(s2_addr); } s2_addr = uwsgi_str(us->name); } } uint8_t modifier1 = 0; uint8_t modifier2 = 0; if (s2_modifier1) { modifier1 = atoi(s2_modifier1); } if (s2_modifier2) { modifier2 = atoi(s2_modifier2); } uwsgi_send_subscription(s2_server, s2_key, strlen(s2_key), modifier1, modifier2, cmd, s2_addr, s2_sign, s2_sni_key, s2_sni_crt, s2_sni_ca); end: if (s2_server) free(s2_server); if (s2_key) free(s2_key); if (s2_socket) free(s2_socket); if (s2_addr) free(s2_addr); if (s2_weight) free(s2_weight); if (s2_modifier1) free(s2_modifier1); if (s2_modifier2) free(s2_modifier2); if (s2_sign) free(s2_sign); if (s2_check) free(s2_check); if (s2_sni_crt) free(s2_sni_crt); if (s2_sni_key) free(s2_sni_key); if (s2_sni_ca) free(s2_sni_ca); } void uwsgi_subscribe_all(uint8_t cmd, int verbose) { if (uwsgi.subscriptions_blocked) return; // -- subscribe struct uwsgi_string_list *subscriptions = uwsgi.subscriptions; while (subscriptions) { if (verbose) { uwsgi_log("%s %s\n", cmd ? "unsubscribing from" : "subscribing to", subscriptions->value); } uwsgi_subscribe(subscriptions->value, cmd); subscriptions = subscriptions->next; } // --subscribe2 subscriptions = uwsgi.subscriptions2; while (subscriptions) { if (verbose) { uwsgi_log("%s %s\n", cmd ? "unsubscribing from" : "subscribing to", subscriptions->value); } uwsgi_subscribe2(subscriptions->value, cmd); subscriptions = subscriptions->next; } } uwsgi-2.0.29/core/timebomb.c000066400000000000000000000022431477626554400156610ustar00rootroot00000000000000#include "uwsgi.h" /* uWSGI timebomb this is a simple thread waiting for a timeout and calling exit with the specified value. You can use it as a last resort in async apps that could block normal uWSGI behaviours */ struct time_bomb { int timeout; int exit_code; }; static void *time_bomb(void *arg) { // block all signals sigset_t smask; sigfillset(&smask); pthread_sigmask(SIG_BLOCK, &smask, NULL); struct time_bomb *tb = (struct time_bomb *) arg; struct timeval tv; tv.tv_sec = tb->timeout; tv.tv_usec = 0; select(0, NULL, NULL, NULL, &tv); uwsgi_log_verbose("*** BOOOOOOM ***\n"); exit(tb->exit_code); } void uwsgi_time_bomb(int timeout, int exit_code) { pthread_t time_bomb_thread; struct time_bomb *tb = uwsgi_malloc(sizeof(struct time_bomb)); tb->timeout = timeout; tb->exit_code = exit_code; if (pthread_create(&time_bomb_thread, NULL, time_bomb, (void *) tb)) { uwsgi_error("pthread_create()"); uwsgi_log("unable to setup the time bomb, goodbye\n"); exit(exit_code); } else { uwsgi_log_verbose("Fire in the hole !!! (%d seconds to detonation)\n", timeout); } } uwsgi-2.0.29/core/transformations.c000066400000000000000000000073771477626554400173310ustar00rootroot00000000000000#include "uwsgi.h" /* uWSGI transformations each body chunk is passed (in chain) to every transformation some of them supports streaming, other requires buffering at the end of the request the "final chain" is called (and the whole chain freed) Transformations (if required) could completely swallow already set headers */ extern struct uwsgi_server uwsgi; // -1 error, 0 = no buffer, send the body, 1 = buffer int uwsgi_apply_transformations(struct wsgi_request *wsgi_req, char *buf, size_t len) { wsgi_req->transformed_chunk = NULL; wsgi_req->transformed_chunk_len = 0; struct uwsgi_transformation *ut = wsgi_req->transformations; char *t_buf = buf; size_t t_len = len; uint8_t flushed = 0; while(ut) { // allocate the buffer (if needed) if (!ut->chunk) { ut->chunk = uwsgi_buffer_new(t_len); } // skip final transformations before appending data if (ut->is_final) goto next; if (uwsgi_buffer_append(ut->chunk, t_buf, t_len)) { return -1; } // if the transformation cannot stream, continue buffering (the func will be called at the end) if (!ut->can_stream) return 1; ut->round++; if (ut->func(wsgi_req, ut)) { return -1; } if (ut->flushed) flushed = 1; t_buf = ut->chunk->buf; t_len = ut->chunk->pos; // we reset the buffer, so we do not waste memory ut->chunk->pos = 0; next: ut = ut->next; } // if we are here we can tell the writer to send the body to the client // no buffering please if (!flushed) { wsgi_req->transformed_chunk = t_buf; wsgi_req->transformed_chunk_len = t_len; } return 0; } /* run all the remaining (or buffered) transformations */ int uwsgi_apply_final_transformations(struct wsgi_request *wsgi_req) { struct uwsgi_transformation *ut = wsgi_req->transformations; wsgi_req->transformed_chunk = NULL; wsgi_req->transformed_chunk_len = 0; char *t_buf = NULL; size_t t_len = 0; uint8_t flushed = 0; int found_nostream = 0; while(ut) { if (!found_nostream) { if (!ut->can_stream) { found_nostream = 1; } else { // stop the chain if no chunk is available if (!ut->chunk) return 0; t_buf = ut->chunk->buf; t_len = ut->chunk->pos; goto next; } } if (!ut->chunk) { if (t_len > 0) { ut->chunk = uwsgi_buffer_new(t_len); } else { ut->chunk = uwsgi_buffer_new(uwsgi.page_size); } } if (t_len > 0) { if (uwsgi_buffer_append(ut->chunk, t_buf, t_len)) { return -1; } } // run the transformation ut->round++; if (ut->func(wsgi_req, ut)) { return -1; } if (ut->flushed) flushed = 1; t_buf = ut->chunk->buf; t_len = ut->chunk->pos; next: ut = ut->next; } // if we are here, all of the transformations are applied if (!flushed) { wsgi_req->transformed_chunk = t_buf; wsgi_req->transformed_chunk_len = t_len; } return 0; } void uwsgi_free_transformations(struct wsgi_request *wsgi_req) { struct uwsgi_transformation *ut = wsgi_req->transformations; while(ut) { struct uwsgi_transformation *current_ut = ut; if (current_ut->chunk) { uwsgi_buffer_destroy(current_ut->chunk); } if (current_ut->ub) { uwsgi_buffer_destroy(current_ut->ub); } if (current_ut->fd > -1) { close(current_ut->fd); } ut = ut->next; free(current_ut); } } struct uwsgi_transformation *uwsgi_add_transformation(struct wsgi_request *wsgi_req, int (*func)(struct wsgi_request *, struct uwsgi_transformation *), void *data) { struct uwsgi_transformation *old_ut = NULL, *ut = wsgi_req->transformations; while(ut) { old_ut = ut; ut = ut->next; } ut = uwsgi_calloc(sizeof(struct uwsgi_transformation)); ut->func = func; ut->fd = -1; ut->data = data; if (old_ut) { old_ut->next = ut; } else { wsgi_req->transformations = ut; } return ut; } uwsgi-2.0.29/core/utils.c000066400000000000000000003116541477626554400152340ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; #ifdef __BIG_ENDIAN__ uint16_t uwsgi_swap16(uint16_t x) { return (uint16_t) ((x & 0xff) << 8 | (x & 0xff00) >> 8); } uint32_t uwsgi_swap32(uint32_t x) { x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0x00FF00FF); return (x >> 16) | (x << 16); } // thanks to ffmpeg project for this idea :P uint64_t uwsgi_swap64(uint64_t x) { union { uint64_t ll; uint32_t l[2]; } w, r; w.ll = x; r.l[0] = uwsgi_swap32(w.l[1]); r.l[1] = uwsgi_swap32(w.l[0]); return r.ll; } #endif // check if a string is a valid hex number int check_hex(char *str, int len) { int i; for (i = 0; i < len; i++) { if ((str[i] < '0' && str[i] > '9') && (str[i] < 'a' && str[i] > 'f') && (str[i] < 'A' && str[i] > 'F') ) { return 0; } } return 1; } // increase worker harakiri void inc_harakiri(int sec) { if (uwsgi.master_process) { uwsgi.workers[uwsgi.mywid].harakiri += sec; } else { alarm(uwsgi.harakiri_options.workers + sec); } } // set worker harakiri void set_harakiri(int sec) { if (sec == 0) { uwsgi.workers[uwsgi.mywid].harakiri = 0; } else { uwsgi.workers[uwsgi.mywid].harakiri = uwsgi_now() + sec; } if (!uwsgi.master_process) { alarm(sec); } } // set user harakiri void set_user_harakiri(int sec) { if (!uwsgi.master_process) { uwsgi_log("!!! unable to set user harakiri without the master process !!!\n"); return; } // a 0 seconds value, reset the timer if (sec == 0) { if (uwsgi.muleid > 0) { uwsgi.mules[uwsgi.muleid - 1].user_harakiri = 0; } else if (uwsgi.i_am_a_spooler) { struct uwsgi_spooler *uspool = uwsgi.i_am_a_spooler; uspool->user_harakiri = 0; } else { uwsgi.workers[uwsgi.mywid].user_harakiri = 0; } } else { if (uwsgi.muleid > 0) { uwsgi.mules[uwsgi.muleid - 1].user_harakiri = uwsgi_now() + sec; } else if (uwsgi.i_am_a_spooler) { struct uwsgi_spooler *uspool = uwsgi.i_am_a_spooler; uspool->user_harakiri = uwsgi_now() + sec; } else { uwsgi.workers[uwsgi.mywid].user_harakiri = uwsgi_now() + sec; } } } // set mule harakiri void set_mule_harakiri(int sec) { if (sec == 0) { uwsgi.mules[uwsgi.muleid - 1].harakiri = 0; } else { uwsgi.mules[uwsgi.muleid - 1].harakiri = uwsgi_now() + sec; } if (!uwsgi.master_process) { alarm(sec); } } // set spooler harakiri void set_spooler_harakiri(int sec) { if (sec == 0) { uwsgi.i_am_a_spooler->harakiri = 0; } else { uwsgi.i_am_a_spooler->harakiri = uwsgi_now() + sec; } if (!uwsgi.master_process) { alarm(sec); } } // daemonize to the specified logfile void daemonize(char *logfile) { pid_t pid; // do not daemonize under emperor if (uwsgi.has_emperor) { logto(logfile); return; } pid = fork(); if (pid < 0) { uwsgi_error("fork()"); exit(1); } if (pid != 0) { _exit(0); } if (setsid() < 0) { uwsgi_error("setsid()"); exit(1); } /* refork... */ pid = fork(); if (pid < 0) { uwsgi_error("fork()"); exit(1); } if (pid != 0) { _exit(0); } if (!uwsgi.do_not_change_umask) { umask(0); } /*if (chdir("/") != 0) { uwsgi_error("chdir()"); exit(1); } */ uwsgi_remap_fd(0, "/dev/null"); logto(logfile); } // get current working directory char *uwsgi_get_cwd() { // set this to static to avoid useless reallocations in stats mode static size_t newsize = 256; char *cwd = uwsgi_malloc(newsize); if (getcwd(cwd, newsize) == NULL && errno == ERANGE) { newsize += 256; uwsgi_log("need a bigger buffer (%lu bytes) for getcwd(). doing reallocation.\n", (unsigned long) newsize); free(cwd); cwd = uwsgi_malloc(newsize); if (getcwd(cwd, newsize) == NULL) { uwsgi_error("getcwd()"); exit(1); } } return cwd; } #ifdef __linux__ void uwsgi_set_cgroup() { char *cgroup_taskfile; FILE *cgroup; char *cgroup_opt; struct uwsgi_string_list *usl, *uslo; if (!uwsgi.cgroup) return; if (getuid()) return; usl = uwsgi.cgroup; while (usl) { int mode = strtol(uwsgi.cgroup_dir_mode, 0, 8); if (mkdir(usl->value, mode)) { if (errno != EEXIST) { uwsgi_error("uwsgi_set_cgroup()/mkdir()"); exit(1); } if (chmod(usl->value, mode)) { uwsgi_error("uwsgi_set_cgroup()/chmod()"); exit(1); } uwsgi_log("using Linux cgroup %s with mode %o\n", usl->value, mode); } else { uwsgi_log("created Linux cgroup %s with mode %o\n", usl->value, mode); } cgroup_taskfile = uwsgi_concat2(usl->value, "/tasks"); cgroup = fopen(cgroup_taskfile, "w"); if (!cgroup) { uwsgi_error_open(cgroup_taskfile); exit(1); } if (fprintf(cgroup, "%d\n", (int) getpid()) <= 0 || ferror(cgroup) || fclose(cgroup)) { uwsgi_error("could not set cgroup"); exit(1); } uwsgi_log("assigned process %d to cgroup %s\n", (int) getpid(), cgroup_taskfile); free(cgroup_taskfile); uslo = uwsgi.cgroup_opt; while (uslo) { cgroup_opt = strchr(uslo->value, '='); if (!cgroup_opt) { cgroup_opt = strchr(uslo->value, ':'); if (!cgroup_opt) { uwsgi_log("invalid cgroup-opt syntax\n"); exit(1); } } cgroup_opt[0] = 0; cgroup_opt++; cgroup_taskfile = uwsgi_concat3(usl->value, "/", uslo->value); cgroup = fopen(cgroup_taskfile, "w"); if (cgroup) { if (fprintf(cgroup, "%s\n", cgroup_opt) <= 0 || ferror(cgroup) || fclose(cgroup)) { uwsgi_log("could not set cgroup option %s to %s\n", uslo->value, cgroup_opt); exit(1); } uwsgi_log("set %s to %s\n", cgroup_opt, cgroup_taskfile); } free(cgroup_taskfile); cgroup_opt[-1] = '='; uslo = uslo->next; } usl = usl->next; } } #endif #ifdef UWSGI_CAP void uwsgi_apply_cap(cap_value_t * cap, int caps_count) { cap_value_t minimal_cap_values[] = { CAP_SYS_CHROOT, CAP_SETUID, CAP_SETGID, CAP_SETPCAP }; cap_t caps = cap_init(); if (!caps) { uwsgi_error("cap_init()"); exit(1); } cap_clear(caps); cap_set_flag(caps, CAP_EFFECTIVE, 4, minimal_cap_values, CAP_SET); cap_set_flag(caps, CAP_PERMITTED, 4, minimal_cap_values, CAP_SET); cap_set_flag(caps, CAP_PERMITTED, caps_count, cap, CAP_SET); cap_set_flag(caps, CAP_INHERITABLE, caps_count, cap, CAP_SET); if (cap_set_proc(caps) < 0) { uwsgi_error("cap_set_proc()"); exit(1); } cap_free(caps); #ifdef __linux__ #ifdef SECBIT_KEEP_CAPS if (prctl(SECBIT_KEEP_CAPS, 1, 0, 0, 0) < 0) { uwsgi_error("prctl()"); exit(1); } #else if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) { uwsgi_error("prctl()"); exit(1); } #endif #endif } #endif // drop privileges (as root) /* here we manage jails/namespaces too it is a pretty huge function... refactory is needed */ void uwsgi_as_root() { if (getuid() > 0) goto nonroot; if (!uwsgi.master_as_root && !uwsgi.uidname) { uwsgi_log_initial("uWSGI running as root, you can use --uid/--gid/--chroot options\n"); } int in_jail = 0; #if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL) if (uwsgi.unshare && !uwsgi.reloads) { if (unshare(uwsgi.unshare)) { uwsgi_error("unshare()"); exit(1); } else { uwsgi_log("[linux-namespace] applied unshare() mask: %d\n", uwsgi.unshare); } #ifdef CLONE_NEWUSER if (uwsgi.unshare & CLONE_NEWUSER) { if (setuid(0)) { uwsgi_error("uwsgi_as_root()/setuid(0)"); exit(1); } } #endif in_jail = 1; } #endif #ifdef UWSGI_CAP if (uwsgi.cap && uwsgi.cap_count > 0 && !uwsgi.reloads) { uwsgi_apply_cap(uwsgi.cap, uwsgi.cap_count); } #endif #if defined(__FreeBSD__) || defined(__GNU_kFreeBSD__) if (uwsgi.jail && !uwsgi.reloads) { struct jail ujail; char *jarg = uwsgi_str(uwsgi.jail); char *j_hostname = NULL; char *j_name = NULL; char *space = strchr(jarg, ' '); if (space) { *space = 0; j_hostname = space + 1; space = strchr(j_hostname, ' '); if (space) { *space = 0; j_name = space + 1; } } ujail.version = JAIL_API_VERSION; ujail.path = jarg; ujail.hostname = j_hostname ? j_hostname : ""; ujail.jailname = j_name; ujail.ip4s = 0; ujail.ip6s = 0; struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, uwsgi.jail_ip4) { ujail.ip4s++; } struct in_addr *saddr = uwsgi_calloc(sizeof(struct in_addr) * ujail.ip4s); int i = 0; uwsgi_foreach(usl, uwsgi.jail_ip4) { if (!inet_pton(AF_INET, usl->value, &saddr[i].s_addr)) { uwsgi_error("jail()/inet_pton()"); exit(1); } i++; } ujail.ip4 = saddr; #ifdef AF_INET6 uwsgi_foreach(usl, uwsgi.jail_ip6) { ujail.ip6s++; } struct in6_addr *saddr6 = uwsgi_calloc(sizeof(struct in6_addr) * ujail.ip6s); i = 0; uwsgi_foreach(usl, uwsgi.jail_ip6) { if (!inet_pton(AF_INET6, usl->value, &saddr6[i].s6_addr)) { uwsgi_error("jail()/inet_pton()"); exit(1); } i++; } ujail.ip6 = saddr6; #endif int jail_id = jail(&ujail); if (jail_id < 0) { uwsgi_error("jail()"); exit(1); } if (uwsgi.jidfile) { if (uwsgi_write_intfile(uwsgi.jidfile, jail_id)) { uwsgi_log("unable to write jidfile\n"); exit(1); } } uwsgi_log("--- running in FreeBSD jail %d ---\n", jail_id); in_jail = 1; } #ifdef UWSGI_HAS_FREEBSD_LIBJAIL if (uwsgi.jail_attach && !uwsgi.reloads) { struct jailparam jparam; uwsgi_log("attaching to FreeBSD jail %s ...\n", uwsgi.jail_attach); if (!is_a_number(uwsgi.jail_attach)) { if (jailparam_init(&jparam, "name")) { uwsgi_error("jailparam_init()"); exit(1); } } else { if (jailparam_init(&jparam, "jid")) { uwsgi_error("jailparam_init()"); exit(1); } } jailparam_import(&jparam, uwsgi.jail_attach); int jail_id = jailparam_set(&jparam, 1, JAIL_UPDATE | JAIL_ATTACH); if (jail_id < 0) { uwsgi_error("jailparam_set()"); exit(1); } jailparam_free(&jparam, 1); uwsgi_log("--- running in FreeBSD jail %d ---\n", jail_id); in_jail = 1; } if (uwsgi.jail2 && !uwsgi.reloads) { struct uwsgi_string_list *usl = NULL; unsigned nparams = 0; uwsgi_foreach(usl, uwsgi.jail2) { nparams++; } struct jailparam *params = uwsgi_malloc(sizeof(struct jailparam) * nparams); int i = 0; uwsgi_foreach(usl, uwsgi.jail2) { uwsgi_log("FreeBSD libjail applying %s\n", usl->value); char *equal = strchr(usl->value, '='); if (equal) { *equal = 0; } if (jailparam_init(¶ms[i], usl->value)) { uwsgi_error("jailparam_init()"); exit(1); } if (equal) { jailparam_import(¶ms[i], equal + 1); *equal = '='; } else { jailparam_import(¶ms[i], "1"); } i++; } int jail_id = jailparam_set(params, nparams, JAIL_CREATE | JAIL_ATTACH); if (jail_id < 0) { uwsgi_error("jailparam_set()"); exit(1); } jailparam_free(params, nparams); if (uwsgi.jidfile) { if (uwsgi_write_intfile(uwsgi.jidfile, jail_id)) { uwsgi_log("unable to write jidfile\n"); exit(1); } } uwsgi_log("--- running in FreeBSD jail %d ---\n", jail_id); in_jail = 1; } #endif #endif if (in_jail || uwsgi.jailed) { int i; for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->early_post_jail) { uwsgi.gp[i]->early_post_jail(); } } uwsgi_hooks_run(uwsgi.hook_post_jail, "post-jail", 1); struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, uwsgi.mount_post_jail) { uwsgi_log("mounting \"%s\" (post-jail)...\n", usl->value); if (uwsgi_mount_hook(usl->value)) { exit(1); } } uwsgi_foreach(usl, uwsgi.umount_post_jail) { uwsgi_log("un-mounting \"%s\" (post-jail)...\n", usl->value); if (uwsgi_umount_hook(usl->value)) { exit(1); } } uwsgi_foreach(usl, uwsgi.exec_post_jail) { uwsgi_log("running \"%s\" (post-jail)...\n", usl->value); int ret = uwsgi_run_command_and_wait(NULL, usl->value); if (ret != 0) { uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret); exit(1); } } uwsgi_foreach(usl, uwsgi.call_post_jail) { if (uwsgi_call_symbol(usl->value)) { uwsgi_log("unable to call function \"%s\"\n", usl->value); exit(1); } } if (uwsgi.refork_post_jail) { uwsgi_log("re-fork()ing...\n"); pid_t pid = fork(); if (pid < 0) { uwsgi_error("fork()"); exit(1); } if (pid > 0) { // block all signals sigset_t smask; sigfillset(&smask); sigprocmask(SIG_BLOCK, &smask, NULL); int status; if (waitpid(pid, &status, 0) < 0) { uwsgi_error("waitpid()"); } _exit(0); } } for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->post_jail) { uwsgi.gp[i]->post_jail(); } } } if (uwsgi.chroot && !uwsgi.is_chrooted && !uwsgi.reloads) { if (!uwsgi.master_as_root) uwsgi_log("chroot() to %s\n", uwsgi.chroot); if (chroot(uwsgi.chroot)) { uwsgi_error("chroot()"); exit(1); } uwsgi.is_chrooted = 1; #ifdef __linux__ if (uwsgi.logging_options.memory_report) { uwsgi_log("*** Warning, on linux system you have to bind-mount the /proc fs in your chroot to get memory debug/report.\n"); } #endif } #ifdef __linux__ if (uwsgi.pivot_root && !uwsgi.reloads) { char *arg = uwsgi_str(uwsgi.pivot_root); char *space = strchr(arg, ' '); if (!space) { uwsgi_log("invalid pivot_root syntax, new_root and put_old must be separated by a space\n"); exit(1); } *space = 0; #if defined(MS_REC) && defined(MS_PRIVATE) if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL)) { uwsgi_error("mount()"); exit(1); } #endif if (chdir(arg)) { uwsgi_error("pivot_root()/chdir()"); exit(1); } space += 1 + strlen(arg); if (space[0] == '/') space++; if (pivot_root(".", space)) { uwsgi_error("pivot_root()"); exit(1); } if (uwsgi.logging_options.memory_report) { uwsgi_log("*** Warning, on linux system you have to bind-mount the /proc fs in your chroot to get memory debug/report.\n"); } free(arg); if (chdir("/")) { uwsgi_error("chdir()"); exit(1); } } #endif #if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL) if (uwsgi.unshare2 && !uwsgi.reloads) { if (unshare(uwsgi.unshare2)) { uwsgi_error("unshare()"); exit(1); } else { uwsgi_log("[linux-namespace] applied unshare() mask: %d\n", uwsgi.unshare2); } #ifdef CLONE_NEWUSER if (uwsgi.unshare2 & CLONE_NEWUSER) { if (setuid(0)) { uwsgi_error("uwsgi_as_root()/setuid(0)"); exit(1); } } #endif in_jail = 1; } #endif if (uwsgi.refork_as_root) { uwsgi_log("re-fork()ing...\n"); pid_t pid = fork(); if (pid < 0) { uwsgi_error("fork()"); exit(1); } if (pid > 0) { // block all signals sigset_t smask; sigfillset(&smask); sigprocmask(SIG_BLOCK, &smask, NULL); int status; if (waitpid(pid, &status, 0) < 0) { uwsgi_error("waitpid()"); } _exit(0); } } struct uwsgi_string_list *usl; uwsgi_foreach(usl, uwsgi.wait_for_interface) { if (!uwsgi.wait_for_interface_timeout) { uwsgi.wait_for_interface_timeout = 60; } uwsgi_log("waiting for interface %s (max %d seconds) ...\n", usl->value, uwsgi.wait_for_interface_timeout); int counter = 0; for (;;) { if (counter > uwsgi.wait_for_interface_timeout) { uwsgi_log("interface %s unavailable after %d seconds\n", usl->value, counter); exit(1); } unsigned int index = if_nametoindex(usl->value); if (index > 0) { uwsgi_log("interface %s found with index %u\n", usl->value, index); break; } else { sleep(1); counter++; } } } uwsgi_foreach(usl, uwsgi.wait_for_fs) { if (uwsgi_wait_for_fs(usl->value, 0)) exit(1); } uwsgi_foreach(usl, uwsgi.wait_for_file) { if (uwsgi_wait_for_fs(usl->value, 1)) exit(1); } uwsgi_foreach(usl, uwsgi.wait_for_dir) { if (uwsgi_wait_for_fs(usl->value, 2)) exit(1); } uwsgi_foreach(usl, uwsgi.wait_for_mountpoint) { if (uwsgi_wait_for_mountpoint(usl->value)) exit(1); } uwsgi_hooks_run(uwsgi.hook_as_root, "as root", 1); uwsgi_foreach(usl, uwsgi.mount_as_root) { uwsgi_log("mounting \"%s\" (as root)...\n", usl->value); if (uwsgi_mount_hook(usl->value)) { exit(1); } } uwsgi_foreach(usl, uwsgi.umount_as_root) { uwsgi_log("un-mounting \"%s\" (as root)...\n", usl->value); if (uwsgi_umount_hook(usl->value)) { exit(1); } } // now run the scripts needed by root uwsgi_foreach(usl, uwsgi.exec_as_root) { uwsgi_log("running \"%s\" (as root)...\n", usl->value); int ret = uwsgi_run_command_and_wait(NULL, usl->value); if (ret != 0) { uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret); exit(1); } } uwsgi_foreach(usl, uwsgi.call_as_root) { if (uwsgi_call_symbol(usl->value)) { uwsgi_log("unable to call function \"%s\"\n", usl->value); } } if (uwsgi.gidname) { struct group *ugroup = getgrnam(uwsgi.gidname); if (ugroup) { uwsgi.gid = ugroup->gr_gid; } else { uwsgi_log("group %s not found.\n", uwsgi.gidname); exit(1); } } if (uwsgi.uidname) { struct passwd *upasswd = getpwnam(uwsgi.uidname); if (upasswd) { uwsgi.uid = upasswd->pw_uid; } else { uwsgi_log("user %s not found.\n", uwsgi.uidname); exit(1); } } if (uwsgi.logfile_chown) { int log_fd = 2; if (uwsgi.log_master && uwsgi.original_log_fd > -1) { log_fd = uwsgi.original_log_fd; } if (fchown(log_fd, uwsgi.uid, uwsgi.gid)) { uwsgi_error("fchown()"); exit(1); } } // fix ipcsem owner if (uwsgi.lock_ops.lock_init == uwsgi_lock_ipcsem_init) { struct uwsgi_lock_item *uli = uwsgi.registered_locks; while (uli) { union semun { int val; struct semid_ds *buf; ushort *array; } semu; struct semid_ds sds; memset(&sds, 0, sizeof(sds)); semu.buf = &sds; int semid = 0; memcpy(&semid, uli->lock_ptr, sizeof(int)); if (semctl(semid, 0, IPC_STAT, semu)) { uwsgi_error("semctl()"); exit(1); } semu.buf->sem_perm.uid = uwsgi.uid; semu.buf->sem_perm.gid = uwsgi.gid; if (semctl(semid, 0, IPC_SET, semu)) { uwsgi_error("semctl()"); exit(1); } uli = uli->next; } } // ok try to call some special hook before finally dropping privileges int i; for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->before_privileges_drop) { uwsgi.gp[i]->before_privileges_drop(); } } if (uwsgi.gid) { if (!uwsgi.master_as_root) uwsgi_log("setgid() to %d\n", uwsgi.gid); if (setgid(uwsgi.gid)) { uwsgi_error("setgid()"); exit(1); } if (uwsgi.no_initgroups || !uwsgi.uid) { if (setgroups(0, NULL)) { uwsgi_error("setgroups()"); exit(1); } } else { char *uidname = uwsgi.uidname; if (!uidname) { struct passwd *pw = getpwuid(uwsgi.uid); if (pw) uidname = pw->pw_name; } if (!uidname) uidname = uwsgi_num2str(uwsgi.uid); if (initgroups(uidname, uwsgi.gid)) { uwsgi_error("setgroups()"); exit(1); } } struct uwsgi_string_list *usl; size_t ags = 0; uwsgi_foreach(usl, uwsgi.additional_gids) ags++; if (ags > 0) { gid_t *ags_list = uwsgi_calloc(sizeof(gid_t) * ags); size_t g_pos = 0; uwsgi_foreach(usl, uwsgi.additional_gids) { ags_list[g_pos] = atoi(usl->value); if (!ags_list[g_pos]) { struct group *g = getgrnam(usl->value); if (g) { ags_list[g_pos] = g->gr_gid; } else { uwsgi_log("unable to find group %s\n", usl->value); exit(1); } } g_pos++; } if (setgroups(ags, ags_list)) { uwsgi_error("setgroups()"); exit(1); } } int additional_groups = getgroups(0, NULL); if (additional_groups > 0) { gid_t *gids = uwsgi_calloc(sizeof(gid_t) * additional_groups); if (getgroups(additional_groups, gids) > 0) { int i; for (i = 0; i < additional_groups; i++) { if (gids[i] == uwsgi.gid) continue; struct group *gr = getgrgid(gids[i]); if (gr) { uwsgi_log("set additional group %d (%s)\n", gids[i], gr->gr_name); } else { uwsgi_log("set additional group %d\n", gids[i]); } } } } } if (uwsgi.uid) { if (!uwsgi.master_as_root) uwsgi_log("setuid() to %d\n", uwsgi.uid); if (setuid(uwsgi.uid)) { uwsgi_error("setuid()"); exit(1); } } if (!getuid()) { uwsgi_log_initial("*** WARNING: you are running uWSGI as root !!! (use the --uid flag) *** \n"); } #ifdef UWSGI_CAP if (uwsgi.cap && uwsgi.cap_count > 0 && !uwsgi.reloads) { cap_t caps = cap_init(); if (!caps) { uwsgi_error("cap_init()"); exit(1); } cap_clear(caps); cap_set_flag(caps, CAP_EFFECTIVE, uwsgi.cap_count, uwsgi.cap, CAP_SET); cap_set_flag(caps, CAP_PERMITTED, uwsgi.cap_count, uwsgi.cap, CAP_SET); cap_set_flag(caps, CAP_INHERITABLE, uwsgi.cap_count, uwsgi.cap, CAP_SET); if (cap_set_proc(caps) < 0) { uwsgi_error("cap_set_proc()"); exit(1); } cap_free(caps); } #endif if (uwsgi.refork) { uwsgi_log("re-fork()ing...\n"); pid_t pid = fork(); if (pid < 0) { uwsgi_error("fork()"); exit(1); } if (pid > 0) { // block all signals sigset_t smask; sigfillset(&smask); sigprocmask(SIG_BLOCK, &smask, NULL); int status; if (waitpid(pid, &status, 0) < 0) { uwsgi_error("waitpid()"); } _exit(0); } } uwsgi_hooks_run(uwsgi.hook_as_user, "as user", 1); // now run the scripts needed by the user uwsgi_foreach(usl, uwsgi.exec_as_user) { uwsgi_log("running \"%s\" (as uid: %d gid: %d) ...\n", usl->value, (int) getuid(), (int) getgid()); int ret = uwsgi_run_command_and_wait(NULL, usl->value); if (ret != 0) { uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret); exit(1); } } uwsgi_foreach(usl, uwsgi.call_as_user) { if (uwsgi_call_symbol(usl->value)) { uwsgi_log("unable to call function \"%s\"\n", usl->value); exit(1); } } // we could now patch the binary if (uwsgi.unprivileged_binary_patch) { uwsgi.argv[0] = uwsgi.unprivileged_binary_patch; execvp(uwsgi.unprivileged_binary_patch, uwsgi.argv); uwsgi_error("execvp()"); exit(1); } if (uwsgi.unprivileged_binary_patch_arg) { uwsgi_exec_command_with_args(uwsgi.unprivileged_binary_patch_arg); } return; nonroot: if (uwsgi.chroot && !uwsgi.is_chrooted && !uwsgi.is_a_reload) { uwsgi_log("cannot chroot() as non-root user\n"); exit(1); } if (uwsgi.gid && getgid() != uwsgi.gid) { uwsgi_log("cannot setgid() as non-root user\n"); exit(1); } if (uwsgi.uid && getuid() != uwsgi.uid) { uwsgi_log("cannot setuid() as non-root user\n"); exit(1); } } static void close_and_free_request(struct wsgi_request *wsgi_req) { // close the connection with the client if (!wsgi_req->fd_closed) { // NOTE, if we close the socket before receiving eventually sent data, socket layer will send a RST wsgi_req->socket->proto_close(wsgi_req); } if (wsgi_req->post_file) { fclose(wsgi_req->post_file); } if (wsgi_req->post_read_buf) { free(wsgi_req->post_read_buf); } if (wsgi_req->post_readline_buf) { free(wsgi_req->post_readline_buf); } if (wsgi_req->proto_parser_buf) { free(wsgi_req->proto_parser_buf); } } // destroy a request void uwsgi_destroy_request(struct wsgi_request *wsgi_req) { close_and_free_request(wsgi_req); // reset for avoiding following requests to fail on non-uwsgi protocols // thanks Marko Tiikkaja for catching it wsgi_req->uh->pktsize = 0; // some plugins expected async_id to be defined before setup int tmp_id = wsgi_req->async_id; memset(wsgi_req, 0, sizeof(struct wsgi_request)); wsgi_req->async_id = tmp_id; } // finalize/close/free a request void uwsgi_close_request(struct wsgi_request *wsgi_req) { int waitpid_status; int tmp_id; uint64_t tmp_rt, rss = 0, vsz = 0; // apply transformations if (wsgi_req->transformations) { if (uwsgi_apply_final_transformations(wsgi_req) == 0) { if (wsgi_req->transformed_chunk && wsgi_req->transformed_chunk_len > 0) { uwsgi_response_write_body_do(wsgi_req, wsgi_req->transformed_chunk, wsgi_req->transformed_chunk_len); } } uwsgi_free_transformations(wsgi_req); } // check if headers should be sent if (wsgi_req->headers) { if (!wsgi_req->headers_sent && !wsgi_req->headers_size && !wsgi_req->response_size) { uwsgi_response_write_headers_do(wsgi_req); } uwsgi_buffer_destroy(wsgi_req->headers); } uint64_t end_of_request = uwsgi_micros(); wsgi_req->end_of_request = end_of_request; if (!wsgi_req->do_not_account_avg_rt) { tmp_rt = wsgi_req->end_of_request - wsgi_req->start_of_request; uwsgi.workers[uwsgi.mywid].running_time += tmp_rt; uwsgi.workers[uwsgi.mywid].avg_response_time = (uwsgi.workers[uwsgi.mywid].avg_response_time + tmp_rt) / 2; } // get memory usage if (uwsgi.logging_options.memory_report == 1 || uwsgi.force_get_memusage) { get_memusage(&rss, &vsz); uwsgi.workers[uwsgi.mywid].vsz_size = vsz; uwsgi.workers[uwsgi.mywid].rss_size = rss; } if (!wsgi_req->do_not_account) { uwsgi.workers[0].requests++; uwsgi.workers[uwsgi.mywid].requests++; uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].requests++; uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].write_errors += wsgi_req->write_errors; uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].read_errors += wsgi_req->read_errors; // this is used for MAX_REQUESTS uwsgi.workers[uwsgi.mywid].delta_requests++; } #ifdef UWSGI_ROUTING // apply final routes after accounting uwsgi_apply_final_routes(wsgi_req); #endif // close socket and free parsers-allocated memory close_and_free_request(wsgi_req); // after_request hook if (!wsgi_req->is_raw && uwsgi.p[wsgi_req->uh->modifier1]->after_request) uwsgi.p[wsgi_req->uh->modifier1]->after_request(wsgi_req); // after_request custom hooks struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, uwsgi.after_request_hooks) { void (*func) (struct wsgi_request *) = (void (*)(struct wsgi_request *)) usl->custom_ptr; func(wsgi_req); } // leave harakiri mode if (uwsgi.workers[uwsgi.mywid].harakiri > 0) { set_harakiri(0); } // leave user harakiri mode if (uwsgi.workers[uwsgi.mywid].user_harakiri > 0) { set_user_harakiri(0); } if (!wsgi_req->do_not_account) { // this is racy in multithread mode if (wsgi_req->response_size > 0) { uwsgi.workers[uwsgi.mywid].tx += wsgi_req->response_size; } if (wsgi_req->headers_size > 0) { uwsgi.workers[uwsgi.mywid].tx += wsgi_req->headers_size; } } // defunct process reaper if (uwsgi.reaper == 1) { while (waitpid(WAIT_ANY, &waitpid_status, WNOHANG) > 0); } // free logvars struct uwsgi_logvar *lv = wsgi_req->logvars; while (lv) { struct uwsgi_logvar *ptr = lv; lv = lv->next; free(ptr); } // free additional headers struct uwsgi_string_list *ah = wsgi_req->additional_headers; while (ah) { struct uwsgi_string_list *ptr = ah; ah = ah->next; free(ptr->value); free(ptr); } // free remove headers ah = wsgi_req->remove_headers; while (ah) { struct uwsgi_string_list *ptr = ah; ah = ah->next; free(ptr->value); free(ptr); } // free chunked input if (wsgi_req->chunked_input_buf) { uwsgi_buffer_destroy(wsgi_req->chunked_input_buf); } // free websocket engine if (wsgi_req->websocket_buf) { uwsgi_buffer_destroy(wsgi_req->websocket_buf); } if (wsgi_req->websocket_send_buf) { uwsgi_buffer_destroy(wsgi_req->websocket_send_buf); } // reset request wsgi_req->uh->pktsize = 0; tmp_id = wsgi_req->async_id; memset(wsgi_req, 0, sizeof(struct wsgi_request)); // some plugins expected async_id to be defined before setup wsgi_req->async_id = tmp_id; // yes, this is pretty useless but we cannot ensure all of the plugin have the same behaviour uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 0; if (uwsgi.max_requests > 0 && uwsgi.workers[uwsgi.mywid].delta_requests >= (uwsgi.max_requests + ((uwsgi.mywid-1) * uwsgi.max_requests_delta)) && (end_of_request - (uwsgi.workers[uwsgi.mywid].last_spawn * 1000000) >= uwsgi.min_worker_lifetime * 1000000)) { goodbye_cruel_world(); } if (uwsgi.reload_on_as && (rlim_t) vsz >= uwsgi.reload_on_as && (end_of_request - (uwsgi.workers[uwsgi.mywid].last_spawn * 1000000) >= uwsgi.min_worker_lifetime * 1000000)) { goodbye_cruel_world(); } if (uwsgi.reload_on_rss && (rlim_t) rss >= uwsgi.reload_on_rss && (end_of_request - (uwsgi.workers[uwsgi.mywid].last_spawn * 1000000) >= uwsgi.min_worker_lifetime * 1000000)) { goodbye_cruel_world(); } // after the first request, if i am a vassal, signal Emperor about my loyalty if (uwsgi.has_emperor && !uwsgi.loyal) { uwsgi_log("announcing my loyalty to the Emperor...\n"); char byte = 17; if (write(uwsgi.emperor_fd, &byte, 1) != 1) { uwsgi_error("write()"); } uwsgi.loyal = 1; } #ifdef __linux__ #ifdef MADV_MERGEABLE // run the ksm mapper if (uwsgi.linux_ksm > 0 && (uwsgi.workers[uwsgi.mywid].requests % uwsgi.linux_ksm) == 0) { uwsgi_linux_ksm_map(); } #endif #endif } #ifdef __linux__ #ifdef MADV_MERGEABLE void uwsgi_linux_ksm_map(void) { int dirty = 0; size_t i; unsigned long long start = 0, end = 0; int errors = 0; int lines = 0; int fd = open("/proc/self/maps", O_RDONLY); if (fd < 0) { uwsgi_error_open("[uwsgi-KSM] /proc/self/maps"); return; } // allocate memory if not available; if (uwsgi.ksm_mappings_current == NULL) { if (!uwsgi.ksm_buffer_size) uwsgi.ksm_buffer_size = 32768; uwsgi.ksm_mappings_current = uwsgi_malloc(uwsgi.ksm_buffer_size); uwsgi.ksm_mappings_current_size = 0; } if (uwsgi.ksm_mappings_last == NULL) { if (!uwsgi.ksm_buffer_size) uwsgi.ksm_buffer_size = 32768; uwsgi.ksm_mappings_last = uwsgi_malloc(uwsgi.ksm_buffer_size); uwsgi.ksm_mappings_last_size = 0; } uwsgi.ksm_mappings_current_size = read(fd, uwsgi.ksm_mappings_current, uwsgi.ksm_buffer_size); close(fd); if (uwsgi.ksm_mappings_current_size <= 0) { uwsgi_log("[uwsgi-KSM] unable to read /proc/self/maps data\n"); return; } // we now have areas if (uwsgi.ksm_mappings_last_size == 0 || uwsgi.ksm_mappings_current_size != uwsgi.ksm_mappings_last_size) { dirty = 1; } else { if (memcmp(uwsgi.ksm_mappings_current, uwsgi.ksm_mappings_last, uwsgi.ksm_mappings_current_size) != 0) { dirty = 1; } } // it is dirty, swap addresses and parse it if (dirty) { char *tmp = uwsgi.ksm_mappings_last; uwsgi.ksm_mappings_last = uwsgi.ksm_mappings_current; uwsgi.ksm_mappings_current = tmp; size_t tmp_size = uwsgi.ksm_mappings_last_size; uwsgi.ksm_mappings_last_size = uwsgi.ksm_mappings_current_size; uwsgi.ksm_mappings_current_size = tmp_size; // scan each line and call madvise on it char *ptr = uwsgi.ksm_mappings_last; for (i = 0; i < uwsgi.ksm_mappings_last_size; i++) { if (uwsgi.ksm_mappings_last[i] == '\n') { lines++; uwsgi.ksm_mappings_last[i] = 0; if (sscanf(ptr, "%llx-%llx %*s", &start, &end) == 2) { if (madvise((void *) (long) start, (size_t) (end - start), MADV_MERGEABLE)) { errors++; } } uwsgi.ksm_mappings_last[i] = '\n'; ptr = uwsgi.ksm_mappings_last + i + 1; } } if (errors >= lines) { uwsgi_error("[uwsgi-KSM] unable to share pages"); } } } #endif #endif #ifdef __linux__ long uwsgi_num_from_file(char *filename, int quiet) { char buf[16]; ssize_t len; int fd = open(filename, O_RDONLY); if (fd < 0) { if (!quiet) uwsgi_error_open(filename); return -1L; } len = read(fd, buf, sizeof(buf)); if (len == 0) { if (!quiet) uwsgi_log("read error %s\n", filename); close(fd); return -1L; } close(fd); return strtol(buf, (char **) NULL, 10); } #endif // setup for a new request void wsgi_req_setup(struct wsgi_request *wsgi_req, int async_id, struct uwsgi_socket *uwsgi_sock) { wsgi_req->app_id = -1; wsgi_req->async_id = async_id; wsgi_req->sendfile_fd = -1; wsgi_req->hvec = uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].hvec; // skip the first 4 bytes; wsgi_req->uh = (struct uwsgi_header *) uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].buffer; wsgi_req->buffer = uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].buffer + 4; if (uwsgi.post_buffering > 0) { wsgi_req->post_buffering_buf = uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].post_buf; } if (uwsgi_sock) { wsgi_req->socket = uwsgi_sock; } uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 0; // now check for suspend request if (uwsgi.workers[uwsgi.mywid].suspended == 1) { uwsgi_log_verbose("*** worker %d suspended ***\n", uwsgi.mywid); cycle: // wait for some signal (normally SIGTSTP) or 10 seconds (as fallback) (void) poll(NULL, 0, 10 * 1000); if (uwsgi.workers[uwsgi.mywid].suspended == 1) goto cycle; uwsgi_log_verbose("*** worker %d resumed ***\n", uwsgi.mywid); } } int wsgi_req_async_recv(struct wsgi_request *wsgi_req) { uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 1; wsgi_req->start_of_request = uwsgi_micros(); wsgi_req->start_of_request_in_sec = wsgi_req->start_of_request / 1000000; if (!wsgi_req->do_not_add_to_async_queue) { if (event_queue_add_fd_read(uwsgi.async_queue, wsgi_req->fd) < 0) return -1; async_add_timeout(wsgi_req, uwsgi.socket_timeout); uwsgi.async_proto_fd_table[wsgi_req->fd] = wsgi_req; } // enter harakiri mode if (uwsgi.harakiri_options.workers > 0) { set_harakiri(uwsgi.harakiri_options.workers); } return 0; } // receive a new request int wsgi_req_recv(int queue, struct wsgi_request *wsgi_req) { uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 1; wsgi_req->start_of_request = uwsgi_micros(); wsgi_req->start_of_request_in_sec = wsgi_req->start_of_request / 1000000; // edge triggered sockets get the whole request during accept() phase if (!wsgi_req->socket->edge_trigger) { for (;;) { int ret = wsgi_req->socket->proto(wsgi_req); if (ret == UWSGI_OK) break; if (ret == UWSGI_AGAIN) { ret = uwsgi_wait_read_req(wsgi_req); if (ret <= 0) return -1; continue; } return -1; } } // enter harakiri mode if (uwsgi.harakiri_options.workers > 0) { set_harakiri(uwsgi.harakiri_options.workers); } #ifdef UWSGI_ROUTING if (uwsgi_apply_routes(wsgi_req) == UWSGI_ROUTE_BREAK) return 0; #endif wsgi_req->async_status = uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req); return 0; } void uwsgi_post_accept(struct wsgi_request *wsgi_req) { // set close on exec (if not a new socket) if (!wsgi_req->socket->edge_trigger && uwsgi.close_on_exec) { if (fcntl(wsgi_req->fd, F_SETFD, FD_CLOEXEC) < 0) { uwsgi_error("fcntl()"); } } // enable TCP_NODELAY ? if (uwsgi.tcp_nodelay) { uwsgi_tcp_nodelay(wsgi_req->fd); } } // accept a new request int wsgi_req_simple_accept(struct wsgi_request *wsgi_req, int fd) { wsgi_req->fd = wsgi_req->socket->proto_accept(wsgi_req, fd); if (wsgi_req->fd < 0) { return -1; } uwsgi_post_accept(wsgi_req); return 0; } // send heartbeat to the emperor void uwsgi_heartbeat() { if (!uwsgi.has_emperor) return; time_t now = uwsgi_now(); if (uwsgi.next_heartbeat <= now) { char byte = 26; if (write(uwsgi.emperor_fd, &byte, 1) != 1) { uwsgi_error("write()"); } uwsgi.next_heartbeat = now + uwsgi.heartbeat; } } // accept a request int wsgi_req_accept(int queue, struct wsgi_request *wsgi_req) { int ret; int interesting_fd = -1; struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; int timeout = -1; thunder_lock; // Recheck the manage_next_request before going forward. // This is because the worker might get cheaped while it's // blocking on the thunder_lock, because thunder_lock is // not interruptable, it'll slow down the cheaping process // (the worker will handle the next request before shuts down). if (!uwsgi.workers[uwsgi.mywid].manage_next_request) { thunder_unlock; return -1; } // heartbeat // in multithreaded mode we are now locked if (uwsgi.has_emperor && uwsgi.heartbeat) { time_t now = uwsgi_now(); // overengineering ... (reduce skew problems) timeout = uwsgi.heartbeat; if (!uwsgi.next_heartbeat) { uwsgi.next_heartbeat = now; } if (uwsgi.next_heartbeat >= now) { timeout = uwsgi.next_heartbeat - now; } } // need edge trigger ? if (uwsgi.is_et) { while (uwsgi_sock) { if (uwsgi_sock->retry && uwsgi_sock->retry[wsgi_req->async_id]) { timeout = 0; break; } uwsgi_sock = uwsgi_sock->next; } // reset pointer uwsgi_sock = uwsgi.sockets; } ret = event_queue_wait(queue, timeout, &interesting_fd); if (ret < 0) { thunder_unlock; return -1; } // check for heartbeat if (uwsgi.has_emperor && uwsgi.heartbeat) { uwsgi_heartbeat(); // no need to continue if timed-out if (ret == 0) { thunder_unlock; return -1; } } if (uwsgi.signal_socket > -1 && (interesting_fd == uwsgi.signal_socket || interesting_fd == uwsgi.my_signal_socket)) { thunder_unlock; uwsgi_receive_signal(interesting_fd, "worker", uwsgi.mywid); return -1; } while (uwsgi_sock) { if (interesting_fd == uwsgi_sock->fd || (uwsgi_sock->retry && uwsgi_sock->retry[wsgi_req->async_id]) || (uwsgi_sock->fd_threads && interesting_fd == uwsgi_sock->fd_threads[wsgi_req->async_id])) { wsgi_req->socket = uwsgi_sock; wsgi_req->fd = wsgi_req->socket->proto_accept(wsgi_req, interesting_fd); thunder_unlock; if (wsgi_req->fd < 0) { return -1; } if (!uwsgi_sock->edge_trigger) { uwsgi_post_accept(wsgi_req); } return 0; } uwsgi_sock = uwsgi_sock->next; } thunder_unlock; return -1; } // translate a OS env to a uWSGI option void env_to_arg(char *src, char *dst) { int i; int val = 0; for (i = 0; i < (int) strlen(src); i++) { if (src[i] == '=') { val = 1; } if (val) { dst[i] = src[i]; } else { dst[i] = tolower((int) src[i]); if (dst[i] == '_') { dst[i] = '-'; } } } dst[strlen(src)] = 0; } // parse OS envs void parse_sys_envs(char **envs) { char **uenvs = envs; char *earg, *eq_pos; while (*uenvs) { if (!strncmp(*uenvs, "UWSGI_", 6) && strncmp(*uenvs, "UWSGI_RELOADS=", 14) && strncmp(*uenvs, "UWSGI_VASSALS_DIR=", 18) && strncmp(*uenvs, "UWSGI_EMPEROR_FD=", 17) && strncmp(*uenvs, "UWSGI_BROODLORD_NUM=", 20) && strncmp(*uenvs, "UWSGI_EMPEROR_FD_CONFIG=", 24) && strncmp(*uenvs, "UWSGI_EMPEROR_PROXY=", 20) && strncmp(*uenvs, "UWSGI_JAIL_PID=", 15) && strncmp(*uenvs, "UWSGI_ORIGINAL_PROC_NAME=", 25)) { earg = uwsgi_malloc(strlen(*uenvs + 6) + 1); env_to_arg(*uenvs + 6, earg); eq_pos = strchr(earg, '='); if (!eq_pos) { break; } eq_pos[0] = 0; add_exported_option(earg, eq_pos + 1, 0); } uenvs++; } } // get the application id int uwsgi_get_app_id(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, int modifier1) { int i; struct stat st; int found; char *app_name = key; uint16_t app_name_len = key_len; if (app_name_len == 0 && wsgi_req) { app_name = wsgi_req->appid; app_name_len = wsgi_req->appid_len; if (app_name_len == 0) { if (!uwsgi.ignore_script_name) { app_name = wsgi_req->script_name; app_name_len = wsgi_req->script_name_len; } if (uwsgi.vhost) { char *vhost_name = uwsgi_concat3n(wsgi_req->host, wsgi_req->host_len, "|", 1, wsgi_req->script_name, wsgi_req->script_name_len); app_name_len = wsgi_req->host_len + 1 + wsgi_req->script_name_len; app_name = uwsgi_req_append(wsgi_req, "UWSGI_APPID", 11, vhost_name, app_name_len); free(vhost_name); if (!app_name) { uwsgi_log("unable to add UWSGI_APPID to the uwsgi buffer, consider increasing it\n"); return -1; } #ifdef UWSGI_DEBUG uwsgi_debug("VirtualHost KEY=%.*s\n", app_name_len, app_name); #endif } wsgi_req->appid = app_name; wsgi_req->appid_len = app_name_len; } } for (i = 0; i < uwsgi_apps_cnt; i++) { // reset check found = 0; #ifdef UWSGI_DEBUG uwsgi_log("searching for %.*s in %.*s %p\n", app_name_len, app_name, uwsgi_apps[i].mountpoint_len, uwsgi_apps[i].mountpoint, uwsgi_apps[i].callable); #endif if (!uwsgi_apps[i].callable) { continue; } if (!uwsgi_strncmp(uwsgi_apps[i].mountpoint, uwsgi_apps[i].mountpoint_len, app_name, app_name_len)) { found = 1; } if (found) { if (uwsgi_apps[i].touch_reload[0]) { if (!stat(uwsgi_apps[i].touch_reload, &st)) { if (st.st_mtime != uwsgi_apps[i].touch_reload_mtime) { // serve the new request and reload uwsgi.workers[uwsgi.mywid].manage_next_request = 0; if (uwsgi.threads > 1) { uwsgi.workers[uwsgi.mywid].destroy = 1; } #ifdef UWSGI_DEBUG uwsgi_log("mtime %d %d\n", st.st_mtime, uwsgi_apps[i].touch_reload_mtime); #endif } } } if (modifier1 == -1) return i; if (modifier1 == uwsgi_apps[i].modifier1) return i; } } return -1; } char *uwsgi_substitute(char *src, char *what, char *with) { int count = 0; if (!with) return src; size_t len = strlen(src); size_t wlen = strlen(what); size_t with_len = strlen(with); char *p = strstr(src, what); if (!p) { return src; } while (p) { count++; p = strstr(p + wlen, what); } len += (count * with_len) + 1; char *dst = uwsgi_calloc(len); char *ptr = src; char *dst_ptr = dst; p = strstr(ptr, what); while (p) { memcpy(dst_ptr, ptr, p - ptr); dst_ptr += p - ptr; memcpy(dst_ptr, with, with_len); dst_ptr += with_len; ptr = p + wlen; p = strstr(ptr, what); } snprintf(dst_ptr, strlen(ptr) + 1, "%s", ptr); return dst; } int uwsgi_is_file(char *filename) { struct stat st; if (stat(filename, &st)) { return 0; } if (S_ISREG(st.st_mode)) return 1; return 0; } int uwsgi_is_file2(char *filename, struct stat *st) { if (stat(filename, st)) { return 0; } if (S_ISREG(st->st_mode)) return 1; return 0; } int uwsgi_is_dir(char *filename) { struct stat st; if (stat(filename, &st)) { return 0; } if (S_ISDIR(st.st_mode)) return 1; return 0; } int uwsgi_is_link(char *filename) { struct stat st; if (lstat(filename, &st)) { return 0; } if (S_ISLNK(st.st_mode)) return 1; return 0; } void *uwsgi_malloc(size_t size) { char *ptr = malloc(size); if (ptr == NULL) { uwsgi_error("malloc()"); uwsgi_log("!!! tried memory allocation of %llu bytes !!!\n", (unsigned long long) size); uwsgi_backtrace(uwsgi.backtrace_depth); exit(1); } return ptr; } void *uwsgi_calloc(size_t size) { char *ptr = uwsgi_malloc(size); memset(ptr, 0, size); return ptr; } char *uwsgi_resolve_ip(char *domain) { struct hostent *he; he = gethostbyname(domain); if (!he || !*he->h_addr_list || (he->h_addrtype != AF_INET #ifdef AF_INET6 && he->h_addrtype != AF_INET6 #endif )) { return NULL; } return inet_ntoa(*(struct in_addr *) he->h_addr_list[0]); } int uwsgi_file_exists(char *filename) { // TODO check for http url or stdin return !access(filename, R_OK); } int uwsgi_file_executable(char *filename) { // TODO check for http url or stdin return !access(filename, R_OK | X_OK); } char *magic_sub(char *buffer, size_t len, size_t * size, char *magic_table[]) { size_t i; size_t magic_len = 0; char *magic_buf = uwsgi_malloc(len); char *magic_ptr = magic_buf; char *old_magic_buf; for (i = 0; i < len; i++) { if (buffer[i] == '%' && (i + 1) < len && magic_table[(unsigned char) buffer[i + 1]]) { old_magic_buf = magic_buf; magic_buf = uwsgi_concat3n(old_magic_buf, magic_len, magic_table[(unsigned char) buffer[i + 1]], strlen(magic_table[(unsigned char) buffer[i + 1]]), buffer + i + 2, len - i); free(old_magic_buf); magic_len += strlen(magic_table[(unsigned char) buffer[i + 1]]); magic_ptr = magic_buf + magic_len; i++; } else { *magic_ptr = buffer[i]; magic_ptr++; magic_len++; } } *size = magic_len; return magic_buf; } void init_magic_table(char *magic_table[]) { int i; for (i = 0; i <= 0xff; i++) { magic_table[i] = ""; } magic_table['%'] = "%"; magic_table['('] = "%("; } char *uwsgi_get_last_char(char *what, char c) { size_t len = strlen(what); while (len--) { if (what[len] == c) return what + len; } return NULL; } char *uwsgi_get_last_charn(char *what, size_t len, char c) { while (len--) { if (what[len] == c) return what + len; } return NULL; } char *uwsgi_num2str(int num) { char *str = uwsgi_malloc(11); snprintf(str, 11, "%d", num); return str; } char *uwsgi_float2str(float num) { char *str = uwsgi_malloc(11); snprintf(str, 11, "%f", num); return str; } char *uwsgi_64bit2str(int64_t num) { char *str = uwsgi_malloc(sizeof(MAX64_STR) + 1); snprintf(str, sizeof(MAX64_STR) + 1, "%lld", (long long) num); return str; } char *uwsgi_size2str(size_t num) { char *str = uwsgi_malloc(sizeof(UMAX64_STR) + 1); snprintf(str, sizeof(UMAX64_STR) + 1, "%llu", (unsigned long long) num); return str; } int uwsgi_num2str2(int num, char *ptr) { return snprintf(ptr, 11, "%d", num); } int uwsgi_num2str2n(int num, char *ptr, int size) { return snprintf(ptr, size, "%d", num); } int uwsgi_long2str2n(unsigned long long num, char *ptr, int size) { int ret = snprintf(ptr, size, "%llu", num); if (ret <= 0 || ret > size) return 0; return ret; } int is_unix(char *socket_name, int len) { int i; for (i = 0; i < len; i++) { if (socket_name[i] == ':') return 0; } return 1; } int is_a_number(char *what) { int i; for (i = 0; i < (int) strlen(what); i++) { if (!isdigit((int) what[i])) return 0; } return 1; } void uwsgi_unix_signal(int signum, void (*func) (int)) { struct sigaction sa; memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = func; sigemptyset(&sa.sa_mask); if (sigaction(signum, &sa, NULL) < 0) { uwsgi_error("sigaction()"); } } int uwsgi_list_has_num(char *list, int num) { char *list2 = uwsgi_concat2(list, ""); char *p, *ctx = NULL; uwsgi_foreach_token(list2, ",", p, ctx) { if (atoi(p) == num) { free(list2); return 1; } } free(list2); return 0; } int uwsgi_list_has_str(char *list, char *str) { char *list2 = uwsgi_str(list); char *p, *ctx = NULL; uwsgi_foreach_token(list2, " ", p, ctx) { if (!strcasecmp(p, str)) { free(list2); return 1; } } free(list2); return 0; } static char hex2num(char *str) { char val = 0; val <<= 4; if (str[0] >= '0' && str[0] <= '9') { val += str[0] & 0x0F; } else if (str[0] >= 'A' && str[0] <= 'F') { val += (str[0] & 0x0F) + 9; } else if (str[0] >= 'a' && str[0] <= 'f') { val += (str[0] & 0x0F) + 9; } else { return 0; } val <<= 4; if (str[1] >= '0' && str[1] <= '9') { val += str[1] & 0x0F; } else if (str[1] >= 'A' && str[1] <= 'F') { val += (str[1] & 0x0F) + 9; } else if (str[1] >= 'a' && str[1] <= 'f') { val += (str[1] & 0x0F) + 9; } else { return 0; } return val; } int uwsgi_str2_num(char *str) { int num = 0; num = 10 * (str[0] - 48); num += str[1] - 48; return num; } int uwsgi_str3_num(char *str) { int num = 0; num = 100 * (str[0] - 48); num += 10 * (str[1] - 48); num += str[2] - 48; return num; } int uwsgi_str4_num(char *str) { int num = 0; num = 1000 * (str[0] - 48); num += 100 * (str[1] - 48); num += 10 * (str[2] - 48); num += str[3] - 48; return num; } uint64_t uwsgi_str_num(char *str, int len) { int i; uint64_t num = 0; uint64_t delta = pow(10, len); for (i = 0; i < len; i++) { delta = delta / 10; num += delta * (str[i] - 48); } return num; } char *uwsgi_split3(char *buf, size_t len, char sep, char **part1, size_t * part1_len, char **part2, size_t * part2_len, char **part3, size_t * part3_len) { size_t i; int status = 0; *part1 = NULL; *part2 = NULL; *part3 = NULL; for (i = 0; i < len; i++) { if (buf[i] == sep) { // get part1 if (status == 0) { *part1 = buf; *part1_len = i; status = 1; } // get part2 else if (status == 1) { *part2 = *part1 + *part1_len + 1; *part2_len = (buf + i) - *part2; break; } } } if (*part1 && *part2) { if (*part2 + *part2_len + 1 > buf + len) { return NULL; } *part3 = *part2 + *part2_len + 1; *part3_len = (buf + len) - *part3; return buf + len; } return NULL; } char *uwsgi_split4(char *buf, size_t len, char sep, char **part1, size_t * part1_len, char **part2, size_t * part2_len, char **part3, size_t * part3_len, char **part4, size_t * part4_len) { size_t i; int status = 0; *part1 = NULL; *part2 = NULL; *part3 = NULL; *part4 = NULL; for (i = 0; i < len; i++) { if (buf[i] == sep) { // get part1 if (status == 0) { *part1 = buf; *part1_len = i; status = 1; } // get part2 else if (status == 1) { *part2 = *part1 + *part1_len + 1; *part2_len = (buf + i) - *part2; status = 2; } // get part3 else if (status == 2) { *part3 = *part2 + *part2_len + 1; *part3_len = (buf + i) - *part3; break; } } } if (*part1 && *part2 && *part3) { if (*part3 + *part3_len + 1 > buf + len) { return NULL; } *part4 = *part3 + *part3_len + 1; *part4_len = (buf + len) - *part4; return buf + len; } return NULL; } char *uwsgi_netstring(char *buf, size_t len, char **netstring, size_t * netstring_len) { char *ptr = buf; char *watermark = buf + len; *netstring_len = 0; while (ptr < watermark) { // end of string size ? if (*ptr == ':') { *netstring_len = uwsgi_str_num(buf, ptr - buf); if (ptr + *netstring_len + 2 > watermark) { return NULL; } *netstring = ptr + 1; return ptr + *netstring_len + 2; } ptr++; } return NULL; } struct uwsgi_dyn_dict *uwsgi_dyn_dict_new(struct uwsgi_dyn_dict **dd, char *key, int keylen, char *val, int vallen) { struct uwsgi_dyn_dict *uwsgi_dd = *dd, *old_dd; if (!uwsgi_dd) { *dd = uwsgi_malloc(sizeof(struct uwsgi_dyn_dict)); uwsgi_dd = *dd; uwsgi_dd->prev = NULL; } else { while (uwsgi_dd) { old_dd = uwsgi_dd; uwsgi_dd = uwsgi_dd->next; } uwsgi_dd = uwsgi_malloc(sizeof(struct uwsgi_dyn_dict)); old_dd->next = uwsgi_dd; uwsgi_dd->prev = old_dd; } uwsgi_dd->key = key; uwsgi_dd->keylen = keylen; uwsgi_dd->value = val; uwsgi_dd->vallen = vallen; uwsgi_dd->hits = 0; uwsgi_dd->status = 0; uwsgi_dd->next = NULL; return uwsgi_dd; } void uwsgi_dyn_dict_del(struct uwsgi_dyn_dict *item) { struct uwsgi_dyn_dict *prev = item->prev; struct uwsgi_dyn_dict *next = item->next; if (prev) { prev->next = next; } if (next) { next->prev = prev; } free(item); } void *uwsgi_malloc_shared(size_t size) { void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); if (addr == MAP_FAILED) { uwsgi_log("unable to allocate %llu bytes (%lluMB)\n", (unsigned long long) size, (unsigned long long) (size / (1024 * 1024))); uwsgi_error("mmap()"); exit(1); } return addr; } void *uwsgi_calloc_shared(size_t size) { void *ptr = uwsgi_malloc_shared(size); memset(ptr, 0, size); return ptr; } struct uwsgi_string_list *uwsgi_string_new_list(struct uwsgi_string_list **list, char *value) { struct uwsgi_string_list *uwsgi_string = *list, *old_uwsgi_string; if (!uwsgi_string) { *list = uwsgi_malloc(sizeof(struct uwsgi_string_list)); uwsgi_string = *list; } else { while (uwsgi_string) { old_uwsgi_string = uwsgi_string; uwsgi_string = uwsgi_string->next; } uwsgi_string = uwsgi_malloc(sizeof(struct uwsgi_string_list)); old_uwsgi_string->next = uwsgi_string; } uwsgi_string->value = value; uwsgi_string->len = 0; if (value) { uwsgi_string->len = strlen(value); } uwsgi_string->next = NULL; uwsgi_string->custom = 0; uwsgi_string->custom2 = 0; uwsgi_string->custom_ptr = NULL; return uwsgi_string; } #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) struct uwsgi_regexp_list *uwsgi_regexp_custom_new_list(struct uwsgi_regexp_list **list, char *value, char *custom) { struct uwsgi_regexp_list *url = *list, *old_url; if (!url) { *list = uwsgi_malloc(sizeof(struct uwsgi_regexp_list)); url = *list; } else { while (url) { old_url = url; url = url->next; } url = uwsgi_malloc(sizeof(struct uwsgi_regexp_list)); old_url->next = url; } if (uwsgi_regexp_build(value, &url->pattern)) { exit(1); } url->next = NULL; url->custom = 0; url->custom_ptr = NULL; url->custom_str = custom; return url; } int uwsgi_regexp_match_pattern(char *pattern, char *str) { uwsgi_pcre *regexp; if (uwsgi_regexp_build(pattern, ®exp)) return 1; return !uwsgi_regexp_match(regexp, str, strlen(str)); } #endif char *uwsgi_string_get_list(struct uwsgi_string_list **list, int pos, size_t * len) { struct uwsgi_string_list *uwsgi_string = *list; int counter = 0; while (uwsgi_string) { if (counter == pos) { *len = uwsgi_string->len; return uwsgi_string->value; } uwsgi_string = uwsgi_string->next; counter++; } *len = 0; return NULL; } void uwsgi_string_del_list(struct uwsgi_string_list **list, struct uwsgi_string_list *item) { struct uwsgi_string_list *uwsgi_string = *list, *old_uwsgi_string = NULL; while (uwsgi_string) { if (uwsgi_string == item) { // parent instance ? if (old_uwsgi_string == NULL) { *list = uwsgi_string->next; } else { old_uwsgi_string->next = uwsgi_string->next; } free(uwsgi_string); return; } old_uwsgi_string = uwsgi_string; uwsgi_string = uwsgi_string->next; } } void uwsgi_sig_pause() { sigset_t mask; sigemptyset(&mask); sigsuspend(&mask); } char *uwsgi_binsh() { struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, uwsgi.binsh) { if (uwsgi_file_executable(usl->value)) { return usl->value; } } return "/bin/sh"; } void uwsgi_exec_command_with_args(char *cmdline) { char *argv[4]; argv[0] = uwsgi_binsh(); argv[1] = "-c"; argv[2] = cmdline; argv[3] = NULL; execvp(argv[0], argv); uwsgi_error("execvp()"); exit(1); } static int uwsgi_run_command_do(char *command, char *arg) { char *argv[4]; #ifdef __linux__ if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) { uwsgi_error("prctl()"); } #endif if (command == NULL) { argv[0] = uwsgi_binsh(); argv[1] = "-c"; argv[2] = arg; argv[3] = NULL; execvp(argv[0], argv); } else { argv[0] = command; argv[1] = arg; argv[2] = NULL; execvp(command, argv); } uwsgi_error("execvp()"); //never here exit(1); } int uwsgi_run_command_and_wait(char *command, char *arg) { int waitpid_status = 0; pid_t pid = fork(); if (pid < 0) { return -1; } if (pid > 0) { if (waitpid(pid, &waitpid_status, 0) < 0) { uwsgi_error("uwsgi_run_command_and_wait()/waitpid()"); return -1; } return WEXITSTATUS(waitpid_status); } return uwsgi_run_command_do(command, arg); } int uwsgi_run_command_putenv_and_wait(char *command, char *arg, char **envs, unsigned int nenvs) { int waitpid_status = 0; pid_t pid = fork(); if (pid < 0) { return -1; } if (pid > 0) { if (waitpid(pid, &waitpid_status, 0) < 0) { uwsgi_error("uwsgi_run_command_and_wait()/waitpid()"); return -1; } return WEXITSTATUS(waitpid_status); } unsigned int i; for (i = 0; i < nenvs; i++) { if (putenv(envs[i])) { uwsgi_error("uwsgi_run_command_putenv_and_wait()/putenv()"); exit(1); } } return uwsgi_run_command_do(command, arg); } pid_t uwsgi_run_command(char *command, int *stdin_fd, int stdout_fd) { char *argv[4]; int waitpid_status = 0; pid_t pid = fork(); if (pid < 0) { return -1; } if (pid > 0) { if (stdin_fd && stdin_fd[0] > -1) { close(stdin_fd[0]); } if (stdout_fd > -1) { close(stdout_fd); } if (waitpid(pid, &waitpid_status, WNOHANG) < 0) { uwsgi_error("waitpid()"); return -1; } return pid; } uwsgi_close_all_sockets(); //uwsgi_close_all_fds(); int i; for (i = 3; i < (int) uwsgi.max_fd; i++) { if (stdin_fd) { if (i == stdin_fd[0] || i == stdin_fd[1]) { continue; } } if (stdout_fd > -1) { if (i == stdout_fd) { continue; } } #ifdef __APPLE__ fcntl(i, F_SETFD, FD_CLOEXEC); #else close(i); #endif } if (stdin_fd) { close(stdin_fd[1]); } else { if (!uwsgi_valid_fd(0)) { int in_fd = open("/dev/null", O_RDONLY); if (in_fd < 0) { uwsgi_error_open("/dev/null"); } else { if (in_fd != 0) { if (dup2(in_fd, 0) < 0) { uwsgi_error("dup2()"); } } } } } if (stdout_fd > -1 && stdout_fd != 1) { if (dup2(stdout_fd, 1) < 0) { uwsgi_error("dup2()"); exit(1); } } if (stdin_fd && stdin_fd[0] > -1 && stdin_fd[0] != 0) { if (dup2(stdin_fd[0], 0) < 0) { uwsgi_error("dup2()"); exit(1); } } if (setsid() < 0) { uwsgi_error("setsid()"); exit(1); } argv[0] = uwsgi_binsh(); argv[1] = "-c"; argv[2] = command; argv[3] = NULL; execvp(uwsgi_binsh(), argv); uwsgi_error("execvp()"); //never here exit(1); } int uwsgi_endswith(char *str1, char *str2) { size_t i; size_t str1len = strlen(str1); size_t str2len = strlen(str2); char *ptr; if (str2len > str1len) return 0; ptr = (str1 + str1len) - str2len; for (i = 0; i < str2len; i++) { if (*ptr != str2[i]) return 0; ptr++; } return 1; } void uwsgi_chown(char *filename, char *owner) { uid_t new_uid = -1; uid_t new_gid = -1; struct group *new_group = NULL; struct passwd *new_user = NULL; char *colon = strchr(owner, ':'); if (colon) { colon[0] = 0; } if (is_a_number(owner)) { new_uid = atoi(owner); } else { new_user = getpwnam(owner); if (!new_user) { uwsgi_log("unable to find user %s\n", owner); exit(1); } new_uid = new_user->pw_uid; } if (colon) { colon[0] = ':'; if (is_a_number(colon + 1)) { new_gid = atoi(colon + 1); } else { new_group = getgrnam(colon + 1); if (!new_group) { uwsgi_log("unable to find group %s\n", colon + 1); exit(1); } new_gid = new_group->gr_gid; } } if (chown(filename, new_uid, new_gid)) { uwsgi_error("chown()"); exit(1); } } char *uwsgi_get_binary_path(char *argvzero) { #if defined(__linux__) || defined(__CYGWIN__) char *buf = uwsgi_calloc(PATH_MAX + 1); ssize_t len = readlink("/proc/self/exe", buf, PATH_MAX); if (len > 0) { return buf; } free(buf); #elif defined(_WIN32) char *buf = uwsgi_calloc(PATH_MAX + 1); if (GetModuleFileName(NULL, buf, PATH_MAX) > 0) { return buf; } free(buf); #elif defined(__NetBSD__) char *buf = uwsgi_calloc(PATH_MAX + 1); ssize_t len = readlink("/proc/curproc/exe", buf, PATH_MAX); if (len > 0) { return buf; } if (realpath(argvzero, buf)) { return buf; } free(buf); #elif defined(__APPLE__) char *buf = uwsgi_malloc(uwsgi.page_size); uint32_t len = uwsgi.page_size; if (_NSGetExecutablePath(buf, &len) == 0) { // return only absolute path #ifndef OLD_REALPATH char *newbuf = realpath(buf, NULL); if (newbuf) { free(buf); return newbuf; } #endif } free(buf); #elif defined(__sun__) // do not free this value !!! char *buf = (char *) getexecname(); if (buf) { // return only absolute path if (buf[0] == '/') { return buf; } char *newbuf = uwsgi_malloc(PATH_MAX + 1); if (realpath(buf, newbuf)) { return newbuf; } } #elif defined(__FreeBSD__) || defined(__GNU_kFreeBSD__) char *buf = uwsgi_malloc(uwsgi.page_size); size_t len = uwsgi.page_size; int mib[4]; mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PATHNAME; mib[3] = -1; if (sysctl(mib, 4, buf, &len, NULL, 0) == 0) { return buf; } free(buf); #endif return argvzero; } char *uwsgi_get_line(char *ptr, char *watermark, int *size) { char *p = ptr; int count = 0; while (p < watermark) { if (*p == '\n') { *size = count; return ptr + count; } count++; p++; } return NULL; } void uwsgi_build_mime_dict(char *filename) { size_t size = 0; char *buf = uwsgi_open_and_read(filename, &size, 1, NULL); char *watermark = buf + size; int linesize = 0; char *line = buf; int i; int type_size = 0; int ext_start = 0; int found; int entries = 0; uwsgi_log("building mime-types dictionary from file %s...", filename); while (uwsgi_get_line(line, watermark, &linesize) != NULL) { found = 0; if (isalnum((int) line[0])) { // get the type size for (i = 0; i < linesize; i++) { if (isblank((int) line[i])) { type_size = i; found = 1; break; } } if (!found) { line += linesize + 1; continue; } found = 0; for (i = type_size; i < linesize; i++) { if (!isblank((int) line[i])) { ext_start = i; found = 1; break; } } if (!found) { line += linesize + 1; continue; } char *current = line + ext_start; int ext_size = 0; for (i = ext_start; i < linesize; i++) { if (isblank((int) line[i])) { #ifdef UWSGI_DEBUG uwsgi_log("%.*s %.*s\n", ext_size, current, type_size, line); #endif uwsgi_dyn_dict_new(&uwsgi.mimetypes, current, ext_size, line, type_size); entries++; ext_size = 0; current = NULL; continue; } else if (current == NULL) { current = line + i; } ext_size++; } if (current && ext_size > 1) { #ifdef UWSGI_DEBUG uwsgi_log("%.*s %.*s\n", ext_size, current, type_size, line); #endif uwsgi_dyn_dict_new(&uwsgi.mimetypes, current, ext_size, line, type_size); entries++; } } line += linesize + 1; } uwsgi_log("%d entry found\n", entries); } #ifdef __linux__ struct uwsgi_unshare_id { char *name; int value; }; static struct uwsgi_unshare_id uwsgi_unshare_list[] = { #ifdef CLONE_FILES {"files", CLONE_FILES}, #endif #ifdef CLONE_NEWIPC {"ipc", CLONE_NEWIPC}, #endif #ifdef CLONE_NEWNET {"net", CLONE_NEWNET}, #endif #ifdef CLONE_IO {"io", CLONE_IO}, #endif #ifdef CLONE_PARENT {"parent", CLONE_PARENT}, #endif #ifdef CLONE_NEWPID {"pid", CLONE_NEWPID}, #endif #ifdef CLONE_NEWNS {"ns", CLONE_NEWNS}, {"fs", CLONE_NEWNS}, {"mount", CLONE_NEWNS}, {"mnt", CLONE_NEWNS}, #endif #ifdef CLONE_SYSVSEM {"sysvsem", CLONE_SYSVSEM}, #endif #ifdef CLONE_NEWUTS {"uts", CLONE_NEWUTS}, #endif #ifdef CLONE_NEWUSER {"user", CLONE_NEWUSER}, #endif {NULL, -1} }; static int uwsgi_get_unshare_id(char *name) { struct uwsgi_unshare_id *uui = uwsgi_unshare_list; while (uui->name) { if (!strcmp(uui->name, name)) return uui->value; uui++; } return -1; } void uwsgi_build_unshare(char *what, int *mask) { char *list = uwsgi_str(what); char *p, *ctx = NULL; uwsgi_foreach_token(list, ",", p, ctx) { int u_id = uwsgi_get_unshare_id(p); if (u_id != -1) { *mask |= u_id; } else { uwsgi_log("unknown namespace subsystem: %s\n", p); exit(1); } } free(list); } #endif #ifdef UWSGI_CAP struct uwsgi_cap { char *name; cap_value_t value; }; static struct uwsgi_cap uwsgi_cap_list[] = { {"chown", CAP_CHOWN}, {"dac_override", CAP_DAC_OVERRIDE}, {"dac_read_search", CAP_DAC_READ_SEARCH}, {"fowner", CAP_FOWNER}, {"fsetid", CAP_FSETID}, {"kill", CAP_KILL}, {"setgid", CAP_SETGID}, {"setuid", CAP_SETUID}, {"setpcap", CAP_SETPCAP}, {"linux_immutable", CAP_LINUX_IMMUTABLE}, {"net_bind_service", CAP_NET_BIND_SERVICE}, {"net_broadcast", CAP_NET_BROADCAST}, {"net_admin", CAP_NET_ADMIN}, {"net_raw", CAP_NET_RAW}, {"ipc_lock", CAP_IPC_LOCK}, {"ipc_owner", CAP_IPC_OWNER}, {"sys_module", CAP_SYS_MODULE}, {"sys_rawio", CAP_SYS_RAWIO}, {"sys_chroot", CAP_SYS_CHROOT}, {"sys_ptrace", CAP_SYS_PTRACE}, {"sys_pacct", CAP_SYS_PACCT}, {"sys_admin", CAP_SYS_ADMIN}, {"sys_boot", CAP_SYS_BOOT}, {"sys_nice", CAP_SYS_NICE}, {"sys_resource", CAP_SYS_RESOURCE}, {"sys_time", CAP_SYS_TIME}, {"sys_tty_config", CAP_SYS_TTY_CONFIG}, {"mknod", CAP_MKNOD}, #ifdef CAP_LEASE {"lease", CAP_LEASE}, #endif #ifdef CAP_AUDIT_WRITE {"audit_write", CAP_AUDIT_WRITE}, #endif #ifdef CAP_AUDIT_CONTROL {"audit_control", CAP_AUDIT_CONTROL}, #endif #ifdef CAP_SETFCAP {"setfcap", CAP_SETFCAP}, #endif #ifdef CAP_MAC_OVERRIDE {"mac_override", CAP_MAC_OVERRIDE}, #endif #ifdef CAP_MAC_ADMIN {"mac_admin", CAP_MAC_ADMIN}, #endif #ifdef CAP_SYSLOG {"syslog", CAP_SYSLOG}, #endif #ifdef CAP_WAKE_ALARM {"wake_alarm", CAP_WAKE_ALARM}, #endif {NULL, -1} }; static int uwsgi_get_cap_id(char *name) { struct uwsgi_cap *ucl = uwsgi_cap_list; while (ucl->name) { if (!strcmp(ucl->name, name)) return ucl->value; ucl++; } return -1; } int uwsgi_build_cap(char *what, cap_value_t ** cap) { int cap_id; char *caps = uwsgi_str(what); int pos = 0; int count = 0; char *p, *ctx = NULL; uwsgi_foreach_token(caps, ",", p, ctx) { if (is_a_number(p)) { count++; } else { cap_id = uwsgi_get_cap_id(p); if (cap_id != -1) { count++; } else { uwsgi_log("[security] unknown capability: %s\n", p); } } } free(caps); *cap = uwsgi_malloc(sizeof(cap_value_t) * count); caps = uwsgi_str(what); ctx = NULL; uwsgi_foreach_token(caps, ",", p, ctx) { if (is_a_number(p)) { cap_id = atoi(p); } else { cap_id = uwsgi_get_cap_id(p); } if (cap_id != -1) { (*cap)[pos] = cap_id; uwsgi_log("setting capability %s [%d]\n", p, cap_id); pos++; } else { uwsgi_log("[security] unknown capability: %s\n", p); } } free(caps); return count; } #endif void uwsgi_apply_config_pass(char symbol, char *(*hook) (char *)) { int i, j; for (i = 0; i < uwsgi.exported_opts_cnt; i++) { int has_symbol = 0; int depth = 0; char *magic_key = NULL; char *magic_val = NULL; if (uwsgi.exported_opts[i]->value && !uwsgi.exported_opts[i]->configured) { for (j = 0; j < (int) strlen(uwsgi.exported_opts[i]->value); j++) { if (uwsgi.exported_opts[i]->value[j] == symbol) { has_symbol = 1; } else if (uwsgi.exported_opts[i]->value[j] == '(' && has_symbol == 1) { has_symbol = 2; depth = 0; magic_key = uwsgi.exported_opts[i]->value + j + 1; } else if (has_symbol > 1) { if (uwsgi.exported_opts[i]->value[j] == '(') { has_symbol++; depth++; } else if (uwsgi.exported_opts[i]->value[j] == ')') { if (depth > 0) { has_symbol++; depth--; continue; } if (has_symbol <= 2) { magic_key = NULL; has_symbol = 0; continue; } #ifdef UWSGI_DEBUG uwsgi_log("need to interpret the %.*s tag\n", has_symbol - 2, magic_key); #endif char *tmp_magic_key = uwsgi_concat2n(magic_key, has_symbol - 2, "", 0); magic_val = hook(tmp_magic_key); free(tmp_magic_key); if (!magic_val) { magic_key = NULL; has_symbol = 0; continue; } uwsgi.exported_opts[i]->value = uwsgi_concat4n(uwsgi.exported_opts[i]->value, (magic_key - 2) - uwsgi.exported_opts[i]->value, magic_val, strlen(magic_val), magic_key + (has_symbol - 1), strlen(magic_key + (has_symbol - 1)), "", 0); #ifdef UWSGI_DEBUG uwsgi_log("computed new value = %s\n", uwsgi.exported_opts[i]->value); #endif magic_key = NULL; has_symbol = 0; j = 0; } else { has_symbol++; } } else { has_symbol = 0; } } } } } void uwsgi_set_processname(char *name) { #if defined(__linux__) || defined(__sun__) size_t amount = 0; // prepare for strncat *uwsgi.orig_argv[0] = 0; if (uwsgi.procname_prefix) { amount += strlen(uwsgi.procname_prefix); if ((int) amount > uwsgi.max_procname - 1) return; strncat(uwsgi.orig_argv[0], uwsgi.procname_prefix, uwsgi.max_procname - (amount + 1)); } amount += strlen(name); if ((int) amount > uwsgi.max_procname - 1) return; strncat(uwsgi.orig_argv[0], name, (uwsgi.max_procname - amount + 1)); if (uwsgi.procname_append) { amount += strlen(uwsgi.procname_append); if ((int) amount > uwsgi.max_procname - 1) return; strncat(uwsgi.orig_argv[0], uwsgi.procname_append, uwsgi.max_procname - (amount + 1)); } // fill with spaces... memset(uwsgi.orig_argv[0] + amount + 1, ' ', uwsgi.max_procname - (amount)); // end with \0 memset(uwsgi.orig_argv[0] + amount + 1 + (uwsgi.max_procname - (amount)), '\0', 1); #elif defined(__FreeBSD__) || defined(__GNU_kFreeBSD__) || defined(__NetBSD__) if (uwsgi.procname_prefix) { if (!uwsgi.procname_append) { setproctitle("-%s%s", uwsgi.procname_prefix, name); } else { setproctitle("-%s%s%s", uwsgi.procname_prefix, name, uwsgi.procname_append); } } else if (uwsgi.procname_append) { if (!uwsgi.procname_prefix) { setproctitle("-%s%s", name, uwsgi.procname_append); } else { setproctitle("-%s%s%s", uwsgi.procname_prefix, name, uwsgi.procname_append); } } else { setproctitle("-%s", name); } #endif } // this is a wrapper for fork restoring original argv pid_t uwsgi_fork(char *name) { pid_t pid = fork(); if (pid == 0) { #ifndef __CYGWIN__ if (uwsgi.never_swap) { if (mlockall(MCL_CURRENT | MCL_FUTURE)) { uwsgi_error("mlockall()"); } } #endif #if defined(__linux__) || defined(__sun__) int i; for (i = 0; i < uwsgi.argc; i++) { // stop fixing original argv if the new one is bigger if (!uwsgi.orig_argv[i]) break; strcpy(uwsgi.orig_argv[i], uwsgi.argv[i]); } #endif if (uwsgi.auto_procname && name) { if (uwsgi.procname) { uwsgi_set_processname(uwsgi.procname); } else { uwsgi_set_processname(name); } } } return pid; } void escape_shell_arg(char *src, size_t len, char *dst) { size_t i; char *ptr = dst; for (i = 0; i < len; i++) { if (strchr("&;`'\"|*?~<>^()[]{}$\\\n", src[i])) { *ptr++ = '\\'; } *ptr++ = src[i]; } *ptr++ = 0; } void escape_json(char *src, size_t len, char *dst) { size_t i; char *ptr = dst; for (i = 0; i < len; i++) { if (src[i] == '\t') { *ptr++ = '\\'; *ptr++ = 't'; } else if (src[i] == '\n') { *ptr++ = '\\'; *ptr++ = 'n'; } else if (src[i] == '\r') { *ptr++ = '\\'; *ptr++ = 'r'; } else if (src[i] == '"') { *ptr++ = '\\'; *ptr++ = '"'; } else if (src[i] == '\\') { *ptr++ = '\\'; *ptr++ = '\\'; } else { *ptr++ = src[i]; } } *ptr++ = 0; } /* build PATH_INFO from raw_uri it manages: percent encoding dot_segments removal stop at the first # */ void http_url_decode(char *buf, uint16_t * len, char *dst) { enum { zero = 0, percent1, percent2, slash, dot, dotdot } status; uint16_t i, current_new_len, new_len = 0; char value[2]; char *ptr = dst; value[0] = '0'; value[1] = '0'; status = zero; int no_slash = 0; if (*len > 0 && buf[0] != '/') { status = slash; no_slash = 1; } for (i = 0; i < *len; i++) { char c = buf[i]; if (c == '#') break; switch (status) { case zero: if (c == '%') { status = percent1; break; } if (c == '/') { status = slash; break; } *ptr++ = c; new_len++; break; case percent1: if (c == '%') { *ptr++ = '%'; new_len++; status = zero; break; } value[0] = c; status = percent2; break; case percent2: value[1] = c; *ptr++ = hex2num(value); new_len++; status = zero; break; case slash: if (c == '.') { status = dot; break; } // we could be at the first round (in non slash) if (i > 0 || !no_slash) { *ptr++ = '/'; new_len++; } if (c == '%') { status = percent1; break; } if (c == '/') { status = slash; break; } *ptr++ = c; new_len++; status = zero; break; case dot: if (c == '.') { status = dotdot; break; } if (c == '/') { status = slash; break; } if (i > 1) { *ptr++ = '/'; new_len++; } *ptr++ = '.'; new_len++; if (c == '%') { status = percent1; break; } *ptr++ = c; new_len++; status = zero; break; case dotdot: // here we need to remove a segment if (c == '/') { current_new_len = new_len; while (current_new_len) { current_new_len--; ptr--; if (dst[current_new_len] == '/') { break; } } new_len = current_new_len; status = slash; break; } if (i > 2) { *ptr++ = '/'; new_len++; } *ptr++ = '.'; new_len++; *ptr++ = '.'; new_len++; if (c == '%') { status = percent1; break; } *ptr++ = c; new_len++; status = zero; break; // over engineering default: *ptr++ = c; new_len++; break; } } switch (status) { case slash: case dot: *ptr++ = '/'; new_len++; break; case dotdot: current_new_len = new_len; while (current_new_len) { if (dst[current_new_len - 1] == '/') { break; } current_new_len--; } new_len = current_new_len; break; default: break; } *len = new_len; } /* we scan the table in reverse, as updated values are at the end */ char *uwsgi_get_var(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t * len) { int i; for (i = wsgi_req->var_cnt - 1; i > 0; i -= 2) { if (!uwsgi_strncmp(key, keylen, wsgi_req->hvec[i - 1].iov_base, wsgi_req->hvec[i - 1].iov_len)) { *len = wsgi_req->hvec[i].iov_len; return wsgi_req->hvec[i].iov_base; } } return NULL; } struct uwsgi_app *uwsgi_add_app(int id, uint8_t modifier1, char *mountpoint, int mountpoint_len, void *interpreter, void *callable) { if (id > uwsgi.max_apps) { uwsgi_log("FATAL ERROR: you cannot load more than %d apps in a worker\n", uwsgi.max_apps); exit(1); } struct uwsgi_app *wi = &uwsgi_apps[id]; memset(wi, 0, sizeof(struct uwsgi_app)); wi->modifier1 = modifier1; wi->mountpoint_len = mountpoint_len < 0xff ? mountpoint_len : (0xff - 1); strncpy(wi->mountpoint, mountpoint, wi->mountpoint_len); wi->interpreter = interpreter; wi->callable = callable; uwsgi_apps_cnt++; // check if we need to emulate fork() COW int i; if (uwsgi.mywid == 0) { for (i = 1; i <= uwsgi.numproc; i++) { memcpy(&uwsgi.workers[i].apps[id], &uwsgi.workers[0].apps[id], sizeof(struct uwsgi_app)); uwsgi.workers[i].apps_cnt = uwsgi_apps_cnt; } } if (!uwsgi.no_default_app) { if ((mountpoint_len == 0 || (mountpoint_len == 1 && mountpoint[0] == '/')) && uwsgi.default_app == -1) { uwsgi.default_app = id; } } return wi; } char *uwsgi_check_touches(struct uwsgi_string_list *touch_list) { // touch->value - file path // touch->custom - file timestamp // touch->custom2 - 0 if file exists, 1 if it does not exists struct uwsgi_string_list *touch = touch_list; while (touch) { struct stat tr_st; if (stat(touch->value, &tr_st)) { if (touch->custom && !touch->custom2) { #ifdef UWSGI_DEBUG uwsgi_log("[uwsgi-check-touches] File %s was removed\n", touch->value); #endif touch->custom2 = 1; return touch->custom_ptr ? touch->custom_ptr : touch->value; } else if (!touch->custom && !touch->custom2) { uwsgi_log("unable to stat() %s, events will be triggered as soon as the file is created\n", touch->value); touch->custom2 = 1; } touch->custom = 0; } else { if (!touch->custom && touch->custom2) { #ifdef UWSGI_DEBUG uwsgi_log("[uwsgi-check-touches] File was created: %s\n", touch->value); #endif touch->custom = (uint64_t) tr_st.st_mtime; touch->custom2 = 0; return touch->custom_ptr ? touch->custom_ptr : touch->value; } else if (touch->custom && (uint64_t) tr_st.st_mtime > touch->custom) { #ifdef UWSGI_DEBUG uwsgi_log("[uwsgi-check-touches] modification detected on %s: %llu -> %llu\n", touch->value, (unsigned long long) touch->custom, (unsigned long long) tr_st.st_mtime); #endif touch->custom = (uint64_t) tr_st.st_mtime; return touch->custom_ptr ? touch->custom_ptr : touch->value; } touch->custom = (uint64_t) tr_st.st_mtime; } touch = touch->next; } return NULL; } char *uwsgi_chomp(char *str) { ssize_t slen = (ssize_t) strlen(str), i; if (!slen) return str; slen--; for (i = slen; i >= 0; i--) { if (str[i] == '\r' || str[i] == '\n') { str[i] = 0; } else { return str; } } return str; } char *uwsgi_chomp2(char *str) { ssize_t slen = (ssize_t) strlen(str), i; if (!slen) return str; slen--; for (i = slen; i >= 0; i--) { if (str[i] == '\r' || str[i] == '\n' || str[i] == '\t' || str[i] == ' ') { str[i] = 0; } else { return str; } } return str; } int uwsgi_tmpfd() { int fd = -1; char *tmpdir = getenv("TMPDIR"); if (!tmpdir) { tmpdir = "/tmp"; } #ifdef O_TMPFILE fd = open(tmpdir, O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR); if (fd >= 0) { return fd; } // fallback to old style #endif char *template = uwsgi_concat2(tmpdir, "/uwsgiXXXXXX"); fd = mkstemp(template); unlink(template); free(template); return fd; } FILE *uwsgi_tmpfile() { int fd = uwsgi_tmpfd(); if (fd < 0) return NULL; return fdopen(fd, "w+"); } int uwsgi_file_to_string_list(char *filename, struct uwsgi_string_list **list) { char line[1024]; FILE *fh = fopen(filename, "r"); if (fh) { while (fgets(line, 1024, fh)) { uwsgi_string_new_list(list, uwsgi_chomp(uwsgi_str(line))); } fclose(fh); return 1; } uwsgi_error_open(filename); return 0; } void uwsgi_setup_post_buffering() { if (!uwsgi.post_buffering_bufsize) uwsgi.post_buffering_bufsize = 8192; if (uwsgi.post_buffering_bufsize < uwsgi.post_buffering) { uwsgi.post_buffering_bufsize = uwsgi.post_buffering; uwsgi_log("setting request body buffering size to %lu bytes\n", (unsigned long) uwsgi.post_buffering_bufsize); } } void uwsgi_emulate_cow_for_apps(int id) { int i; // check if we need to emulate fork() COW if (uwsgi.mywid == 0) { for (i = 1; i <= uwsgi.numproc; i++) { memcpy(&uwsgi.workers[i].apps[id], &uwsgi.workers[0].apps[id], sizeof(struct uwsgi_app)); uwsgi.workers[i].apps_cnt = uwsgi_apps_cnt; } } } int uwsgi_write_intfile(char *filename, int n) { FILE *pidfile = fopen(filename, "w"); if (!pidfile) { uwsgi_error_open(filename); exit(1); } if (fprintf(pidfile, "%d\n", n) <= 0 || ferror(pidfile)) { fclose(pidfile); return -1; } if (fclose(pidfile)) { return -1; } return 0; } void uwsgi_write_pidfile(char *pidfile_name) { uwsgi_log("writing pidfile to %s\n", pidfile_name); if (uwsgi_write_intfile(pidfile_name, (int) getpid())) { uwsgi_log("could not write pidfile.\n"); } } void uwsgi_write_pidfile_explicit(char *pidfile_name, pid_t pid) { uwsgi_log("writing pidfile to %s\n", pidfile_name); if (uwsgi_write_intfile(pidfile_name, (int) pid)) { uwsgi_log("could not write pidfile.\n"); } } char *uwsgi_expand_path(char *dir, int dir_len, char *ptr) { if (dir_len > PATH_MAX) { uwsgi_log("invalid path size: %d (max %d)\n", dir_len, PATH_MAX); return NULL; } char *src = uwsgi_concat2n(dir, dir_len, "", 0); char *dst = ptr; if (!dst) dst = uwsgi_malloc(PATH_MAX + 1); if (!realpath(src, dst)) { uwsgi_error_realpath(src); if (!ptr) free(dst); free(src); return NULL; } free(src); return dst; } void uwsgi_set_cpu_affinity() { #if defined(__linux__) || defined(__FreeBSD__) || defined(__GNU_kFreeBSD__) char buf[4096]; int ret; int pos = 0; if (uwsgi.cpu_affinity) { int base_cpu = (uwsgi.mywid - 1) * uwsgi.cpu_affinity; if (base_cpu >= uwsgi.cpus) { base_cpu = base_cpu % uwsgi.cpus; } ret = snprintf(buf, 4096, "mapping worker %d to CPUs:", uwsgi.mywid); if (ret < 25 || ret >= 4096) { uwsgi_log("unable to initialize cpu affinity !!!\n"); exit(1); } pos += ret; #if defined(__linux__) || defined(__GNU_kFreeBSD__) cpu_set_t cpuset; #elif defined(__FreeBSD__) cpuset_t cpuset; #endif CPU_ZERO(&cpuset); int i; for (i = 0; i < uwsgi.cpu_affinity; i++) { if (base_cpu >= uwsgi.cpus) base_cpu = 0; CPU_SET(base_cpu, &cpuset); ret = snprintf(buf + pos, 4096 - pos, " %d", base_cpu); if (ret < 2 || ret >= 4096) { uwsgi_log("unable to initialize cpu affinity !!!\n"); exit(1); } pos += ret; base_cpu++; } #if defined(__linux__) || defined(__GNU_kFreeBSD__) if (sched_setaffinity(0, sizeof(cpu_set_t), &cpuset)) { uwsgi_error("sched_setaffinity()"); } #elif defined(__FreeBSD__) if (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(cpuset), &cpuset)) { uwsgi_error("cpuset_setaffinity"); } #endif uwsgi_log("%s\n", buf); } #endif } #ifdef UWSGI_ELF #if defined(__linux__) #include #endif char *uwsgi_elf_section(char *filename, char *s, size_t * len) { struct stat st; char *output = NULL; int fd = open(filename, O_RDONLY); if (fd < 0) { uwsgi_error_open(filename); return NULL; } if (fstat(fd, &st)) { uwsgi_error("stat()"); close(fd); return NULL; } if (st.st_size < EI_NIDENT) { uwsgi_log("invalid elf file: %s\n", filename); close(fd); return NULL; } char *addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (addr == MAP_FAILED) { uwsgi_error("mmap()"); close(fd); return NULL; } if (addr[0] != ELFMAG0) goto clear; if (addr[1] != ELFMAG1) goto clear; if (addr[2] != ELFMAG2) goto clear; if (addr[3] != ELFMAG3) goto clear; if (addr[4] == ELFCLASS32) { // elf header Elf32_Ehdr *elfh = (Elf32_Ehdr *) addr; // first section Elf32_Shdr *sections = ((Elf32_Shdr *) (addr + elfh->e_shoff)); // number of sections int ns = elfh->e_shnum; // the names table Elf32_Shdr *table = §ions[elfh->e_shstrndx]; // string table session pointer char *names = addr + table->sh_offset; Elf32_Shdr *ss = NULL; int i; for (i = 0; i < ns; i++) { char *name = names + sections[i].sh_name; if (!strcmp(name, s)) { ss = §ions[i]; break; } } if (ss) { *len = ss->sh_size; output = uwsgi_concat2n(addr + ss->sh_offset, ss->sh_size, "", 0); } } else if (addr[4] == ELFCLASS64) { // elf header Elf64_Ehdr *elfh = (Elf64_Ehdr *) addr; // first section Elf64_Shdr *sections = ((Elf64_Shdr *) (addr + elfh->e_shoff)); // number of sections int ns = elfh->e_shnum; // the names table Elf64_Shdr *table = §ions[elfh->e_shstrndx]; // string table session pointer char *names = addr + table->sh_offset; Elf64_Shdr *ss = NULL; int i; for (i = 0; i < ns; i++) { char *name = names + sections[i].sh_name; if (!strcmp(name, s)) { ss = §ions[i]; break; } } if (ss) { *len = ss->sh_size; output = uwsgi_concat2n(addr + ss->sh_offset, ss->sh_size, "", 0); } } clear: close(fd); munmap(addr, st.st_size); return output; } #endif static void *uwsgi_thread_run(void *arg) { struct uwsgi_thread *ut = (struct uwsgi_thread *) arg; // block all signals sigset_t smask; sigfillset(&smask); pthread_sigmask(SIG_BLOCK, &smask, NULL); ut->queue = event_queue_init(); event_queue_add_fd_read(ut->queue, ut->pipe[1]); ut->func(ut); return NULL; } struct uwsgi_thread *uwsgi_thread_new_with_data(void (*func) (struct uwsgi_thread *), void *data) { struct uwsgi_thread *ut = uwsgi_calloc(sizeof(struct uwsgi_thread)); #if defined(SOCK_SEQPACKET) && defined(__linux__) if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, ut->pipe)) { #else if (socketpair(AF_UNIX, SOCK_DGRAM, 0, ut->pipe)) { #endif free(ut); return NULL; } uwsgi_socket_nb(ut->pipe[0]); uwsgi_socket_nb(ut->pipe[1]); ut->func = func; ut->data = data; pthread_attr_init(&ut->tattr); pthread_attr_setdetachstate(&ut->tattr, PTHREAD_CREATE_DETACHED); // 512K should be enough... pthread_attr_setstacksize(&ut->tattr, 512 * 1024); if (pthread_create(&ut->tid, &ut->tattr, uwsgi_thread_run, ut)) { uwsgi_error("pthread_create()"); goto error; } return ut; error: close(ut->pipe[0]); close(ut->pipe[1]); free(ut); return NULL; } struct uwsgi_thread *uwsgi_thread_new(void (*func) (struct uwsgi_thread *)) { return uwsgi_thread_new_with_data(func, NULL); } int uwsgi_kvlist_parse(char *src, size_t len, char list_separator, int kv_separator, ...) { size_t i; va_list ap; struct uwsgi_string_list *itemlist = NULL; char *buf = uwsgi_calloc(len + 1); // ok let's start splitting the string int escaped = 0; char *base = buf; char *ptr = buf; for (i = 0; i < len; i++) { if (src[i] == list_separator && !escaped) { *ptr++ = 0; uwsgi_string_new_list(&itemlist, base); base = ptr; } else if (src[i] == '\\' && !escaped) { escaped = 1; } else if (escaped) { *ptr++ = src[i]; escaped = 0; } else { *ptr++ = src[i]; } } if (ptr > base) { uwsgi_string_new_list(&itemlist, base); } struct uwsgi_string_list *usl = itemlist; while (usl) { len = strlen(usl->value); char *item_buf = uwsgi_calloc(len + 1); base = item_buf; ptr = item_buf; escaped = 0; for (i = 0; i < len; i++) { if (usl->value[i] == kv_separator && !escaped) { *ptr++ = 0; va_start(ap, kv_separator); for (;;) { char *p = va_arg(ap, char *); if (!p) break; char **pp = va_arg(ap, char **); if (!pp) break; if (!strcmp(p, base)) { *pp = uwsgi_str(usl->value + i + 1); } } va_end(ap); base = ptr; break; } else if (usl->value[i] == '\\' && !escaped) { escaped = 1; } else if (escaped) { escaped = 0; } else { *ptr++ = usl->value[i]; } } free(item_buf); usl = usl->next; } // destroy the list (no need to destroy the value as it is a pointer to buf) usl = itemlist; while (usl) { struct uwsgi_string_list *tmp_usl = usl; usl = usl->next; free(tmp_usl); } free(buf); return 0; } int uwsgi_send_http_stats(int fd) { char buf[4096]; int ret = uwsgi_waitfd(fd, uwsgi.socket_timeout); if (ret <= 0) return -1; if (read(fd, buf, 4096) <= 0) return -1; struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); if (!ub) return -1; if (uwsgi_buffer_append(ub, "HTTP/1.0 200 OK\r\n", 17)) goto error; if (uwsgi_buffer_append(ub, "Connection: close\r\n", 19)) goto error; if (uwsgi_buffer_append(ub, "Access-Control-Allow-Origin: *\r\n", 32)) goto error; if (uwsgi_buffer_append(ub, "Content-Type: application/json\r\n", 32)) goto error; if (uwsgi_buffer_append(ub, "\r\n", 2)) goto error; if (uwsgi_buffer_send(ub, fd)) goto error; uwsgi_buffer_destroy(ub); return 0; error: uwsgi_buffer_destroy(ub); return -1; } int uwsgi_call_symbol(char *symbol) { void (*func) (void) = dlsym(RTLD_DEFAULT, symbol); if (!func) return -1; func(); return 0; } int uwsgi_plugin_modifier1(char *plugin) { int ret = -1; char *symbol_name = uwsgi_concat2(plugin, "_plugin"); struct uwsgi_plugin *up = dlsym(RTLD_DEFAULT, symbol_name); if (!up) goto end; ret = up->modifier1; end: free(symbol_name); return ret; } char *uwsgi_strip(char *src) { char *dst = src; size_t len = strlen(src); int i; for (i = 0; i < (ssize_t) len; i++) { if (src[i] == ' ' || src[i] == '\t') { dst++; } } len -= (dst - src); for (i = len; i >= 0; i--) { if (dst[i] == ' ' || dst[i] == '\t') { dst[i] = 0; } else { break; } } return dst; } void uwsgi_uuid(char *buf) { #ifdef UWSGI_UUID uuid_t uuid_value; uuid_generate(uuid_value); uuid_unparse(uuid_value, buf); #else unsigned int i, r[11]; if (!uwsgi_file_exists("/dev/urandom")) goto fallback; int fd = open("/dev/urandom", O_RDONLY); if (fd < 0) goto fallback; for (i = 0; i < 11; i++) { if (read(fd, &r[i], 4) != 4) { close(fd); goto fallback; } } close(fd); goto done; fallback: for (i = 0; i < 11; i++) { r[i] = (unsigned int) rand(); } done: snprintf(buf, 37, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10]); #endif } int uwsgi_uuid_cmp(char *x, char *y) { int i; for (i = 0; i < 36; i++) { if (x[i] != y[i]) { if (x[i] > y[i]) { return 1; } return 0; } } return 0; } void uwsgi_additional_header_add(struct wsgi_request *wsgi_req, char *hh, uint16_t hh_len) { // will be freed on request's end char *header = uwsgi_concat2n(hh, hh_len, "", 0); uwsgi_string_new_list(&wsgi_req->additional_headers, header); } void uwsgi_remove_header(struct wsgi_request *wsgi_req, char *hh, uint16_t hh_len) { char *header = uwsgi_concat2n(hh, hh_len, "", 0); uwsgi_string_new_list(&wsgi_req->remove_headers, header); } // based on nginx implementation static uint8_t b64_table64[] = { 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 77, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77, 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 77, 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77 }; static char b64_table64_2[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; char *uwsgi_base64_decode(char *buf, size_t len, size_t * d_len) { // find the real size and check for invalid values size_t i; for (i = 0; i < len; i++) { if (buf[i] == '=') break; // check for invalid content if (b64_table64[(uint8_t) buf[i]] == 77) { return NULL; } } // check for invalid size if (i % 4 == 1) return NULL; // compute the new size *d_len = (((len + 3) / 4) * 3); char *dst = uwsgi_malloc(*d_len + 1); char *ptr = dst; uint8_t *src = (uint8_t *) buf; while (i > 3) { *ptr++ = (char) (b64_table64[src[0]] << 2 | b64_table64[src[1]] >> 4); *ptr++ = (char) (b64_table64[src[1]] << 4 | b64_table64[src[2]] >> 2); *ptr++ = (char) (b64_table64[src[2]] << 6 | b64_table64[src[3]]); src += 4; i -= 4; } if (i > 1) { *ptr++ = (char) (b64_table64[src[0]] << 2 | b64_table64[src[1]] >> 4); } if (i > 2) { *ptr++ = (char) (b64_table64[src[1]] << 4 | b64_table64[src[2]] >> 2); } *d_len = (ptr - dst); *ptr++ = 0; return dst; } char *uwsgi_base64_encode(char *buf, size_t len, size_t * d_len) { *d_len = ((len * 4) / 3) + 5; uint8_t *src = (uint8_t *) buf; char *dst = uwsgi_malloc(*d_len); char *ptr = dst; while (len >= 3) { *ptr++ = b64_table64_2[src[0] >> 2]; *ptr++ = b64_table64_2[((src[0] << 4) & 0x30) | (src[1] >> 4)]; *ptr++ = b64_table64_2[((src[1] << 2) & 0x3C) | (src[2] >> 6)]; *ptr++ = b64_table64_2[src[2] & 0x3F]; src += 3; len -= 3; } if (len > 0) { *ptr++ = b64_table64_2[src[0] >> 2]; uint8_t tmp = (src[0] << 4) & 0x30; if (len > 1) tmp |= src[1] >> 4; *ptr++ = b64_table64_2[tmp]; if (len < 2) { *ptr++ = '='; } else { *ptr++ = b64_table64_2[(src[1] << 2) & 0x3C]; } *ptr++ = '='; } *ptr = 0; *d_len = ((char *) ptr - dst); return dst; } uint16_t uwsgi_be16(char *buf) { uint16_t *src = (uint16_t *) buf; uint16_t ret = 0; uint8_t *ptr = (uint8_t *) & ret; ptr[0] = (uint8_t) ((*src >> 8) & 0xff); ptr[1] = (uint8_t) (*src & 0xff); return ret; } uint32_t uwsgi_be32(char *buf) { uint32_t *src = (uint32_t *) buf; uint32_t ret = 0; uint8_t *ptr = (uint8_t *) & ret; ptr[0] = (uint8_t) ((*src >> 24) & 0xff); ptr[1] = (uint8_t) ((*src >> 16) & 0xff); ptr[2] = (uint8_t) ((*src >> 8) & 0xff); ptr[3] = (uint8_t) (*src & 0xff); return ret; } uint64_t uwsgi_be64(char *buf) { uint64_t *src = (uint64_t *) buf; uint64_t ret = 0; uint8_t *ptr = (uint8_t *) & ret; ptr[0] = (uint8_t) ((*src >> 56) & 0xff); ptr[1] = (uint8_t) ((*src >> 48) & 0xff); ptr[2] = (uint8_t) ((*src >> 40) & 0xff); ptr[3] = (uint8_t) ((*src >> 32) & 0xff); ptr[4] = (uint8_t) ((*src >> 24) & 0xff); ptr[5] = (uint8_t) ((*src >> 16) & 0xff); ptr[6] = (uint8_t) ((*src >> 8) & 0xff); ptr[7] = (uint8_t) (*src & 0xff); return ret; } char *uwsgi_get_header(struct wsgi_request *wsgi_req, char *hh, uint16_t len, uint16_t * rlen) { char *key = uwsgi_malloc(len + 6); uint16_t key_len = len; char *ptr = key; *rlen = 0; if (uwsgi_strncmp(hh, len, "Content-Length", 14) && uwsgi_strncmp(hh, len, "Content-Type", 12)) { memcpy(ptr, "HTTP_", 5); ptr += 5; key_len += 5; } uint16_t i; for (i = 0; i < len; i++) { if (hh[i] == '-') { *ptr++ = '_'; } else { *ptr++ = toupper((int) hh[i]); } } char *value = uwsgi_get_var(wsgi_req, key, key_len, rlen); free(key); return value; } static char *uwsgi_hex_table[] = { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF", "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF", }; char *uwsgi_str_to_hex(char *src, size_t slen) { char *dst = uwsgi_malloc(slen * 2); char *ptr = dst; size_t i; for (i = 0; i < slen; i++) { uint8_t pos = (uint8_t) src[i]; memcpy(ptr, uwsgi_hex_table[pos], 2); ptr += 2; } return dst; } // dst has to be 3 times buf size (USE IT ONLY FOR PATH_INFO !!!) void http_url_encode(char *buf, uint16_t * len, char *dst) { uint16_t i; char *ptr = dst; for (i = 0; i < *len; i++) { if ((buf[i] >= 'A' && buf[i] <= 'Z') || (buf[i] >= 'a' && buf[i] <= 'z') || (buf[i] >= '0' && buf[i] <= '9') || buf[i] == '-' || buf[i] == '_' || buf[i] == '.' || buf[i] == '~' || buf[i] == '/') { *ptr++ = buf[i]; } else { char *h = uwsgi_hex_table[(int) buf[i]]; *ptr++ = '%'; *ptr++ = h[0]; *ptr++ = h[1]; } } *len = ptr - dst; } void uwsgi_takeover() { if (uwsgi.i_am_a_spooler) { uwsgi_spooler_run(); } else if (uwsgi.muleid) { uwsgi_mule_run(); } else { uwsgi_worker_run(); } } // create a message pipe void create_msg_pipe(int *fd, int bufsize) { #if defined(SOCK_SEQPACKET) && defined(__linux__) if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fd)) { #else if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fd)) { #endif uwsgi_error("create_msg_pipe()/socketpair()"); exit(1); } uwsgi_socket_nb(fd[0]); uwsgi_socket_nb(fd[1]); if (bufsize) { if (setsockopt(fd[0], SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(int))) { uwsgi_error("create_msg_pipe()/setsockopt()"); } if (setsockopt(fd[0], SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(int))) { uwsgi_error("create_msg_pipe()/setsockopt()"); } if (setsockopt(fd[1], SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(int))) { uwsgi_error("create_msg_pipe()/setsockopt()"); } if (setsockopt(fd[1], SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(int))) { uwsgi_error("create_msg_pipe()/setsockopt()"); } } } char *uwsgi_binary_path() { return uwsgi.binary_path ? uwsgi.binary_path : "uwsgi"; } void uwsgi_envdir(char *edir) { DIR *d = opendir(edir); if (!d) { uwsgi_error("[uwsgi-envdir] opendir()"); exit(1); } struct dirent *de; while ((de = readdir(d)) != NULL) { // skip hidden files if (de->d_name[0] == '.') continue; struct stat st; char *filename = uwsgi_concat3(edir, "/", de->d_name); if (stat(filename, &st)) { uwsgi_log("[uwsgi-envdir] error stating %s\n", filename); uwsgi_error("[uwsgi-envdir] stat()"); exit(1); } if (!S_ISREG(st.st_mode)) { free(filename); continue; } // unsetenv if (st.st_size == 0) { #ifdef UNSETENV_VOID unsetenv(de->d_name); #else if (unsetenv(de->d_name)) { uwsgi_log("[uwsgi-envdir] unable to unset %s\n", de->d_name); uwsgi_error("[uwsgi-envdir] unsetenv"); exit(1); } #endif free(filename); continue; } // read the content of the file size_t size = 0; char *content = uwsgi_open_and_read(filename, &size, 1, NULL); if (!content) { uwsgi_log("[uwsgi-envdir] unable to open %s\n", filename); uwsgi_error_open(filename); exit(1); } free(filename); // HACK, envdir states we only need to strip the end of the string .... uwsgi_chomp2(content); // ... and substitute 0 with \n size_t slen = strlen(content); size_t i; for (i = 0; i < slen; i++) { if (content[i] == 0) { content[i] = '\n'; } } if (setenv(de->d_name, content, 1)) { uwsgi_log("[uwsgi-envdir] unable to set %s\n", de->d_name); uwsgi_error("[uwsgi-envdir] setenv"); exit(1); } free(content); } closedir(d); } void uwsgi_envdirs(struct uwsgi_string_list *envdirs) { struct uwsgi_string_list *usl = envdirs; while (usl) { uwsgi_envdir(usl->value); usl = usl->next; } } void uwsgi_opt_envdir(char *opt, char *value, void *foobar) { uwsgi_envdir(value); } void uwsgi_exit(int status) { uwsgi.last_exit_code = status; // disable macro expansion (exit) (status); } int uwsgi_base128(struct uwsgi_buffer *ub, uint64_t l, int first) { if (l > 127) { if (uwsgi_base128(ub, l / 128, 0)) return -1; } l %= 128; if (first) { if (uwsgi_buffer_u8(ub, (uint8_t) l)) return -1; } else { if (uwsgi_buffer_u8(ub, 0x80 | (uint8_t) l)) return -1; } return 0; } #ifdef __linux__ void uwsgi_setns(char *path) { int (*u_setns) (int, int) = (int (*)(int, int)) dlsym(RTLD_DEFAULT, "setns"); if (!u_setns) { uwsgi_log("your system misses setns() syscall !!!\n"); exit(1); } // cound be overwritten int count = 64; uwsgi_log("joining namespaces from %s ...\n", path); for (;;) { int ns_fd = uwsgi_connect(path, 30, 0); if (ns_fd < 0) { uwsgi_error("uwsgi_setns()/uwsgi_connect()"); sleep(1); continue; } int *fds = uwsgi_attach_fd(ns_fd, &count, "uwsgi-setns", 11); if (fds && count > 0) { int i; for (i = 0; i < count; i++) { if (fds[i] > -1) { if (u_setns(fds[i], 0) < 0) { uwsgi_error("uwsgi_setns()/setns()"); exit(1); } close(fds[i]); } } free(fds); close(ns_fd); break; } if (fds) free(fds); close(ns_fd); sleep(1); } } #endif mode_t uwsgi_mode_t(char *value, int *error) { mode_t mode = 0; *error = 0; if (strlen(value) < 3) { *error = 1; return mode; } if (strlen(value) == 3) { mode = (mode << 3) + (value[0] - '0'); mode = (mode << 3) + (value[1] - '0'); mode = (mode << 3) + (value[2] - '0'); } else { mode = (mode << 3) + (value[1] - '0'); mode = (mode << 3) + (value[2] - '0'); mode = (mode << 3) + (value[3] - '0'); } return mode; } int uwsgi_wait_for_mountpoint(char *mountpoint) { if (!uwsgi.wait_for_fs_timeout) { uwsgi.wait_for_fs_timeout = 60; } uwsgi_log("waiting for %s (max %d seconds) ...\n", mountpoint, uwsgi.wait_for_fs_timeout); int counter = 0; for (;;) { if (counter > uwsgi.wait_for_fs_timeout) { uwsgi_log("%s unavailable after %d seconds\n", mountpoint, counter); return -1; } struct stat st0; struct stat st1; if (stat(mountpoint, &st0)) goto retry; if (!S_ISDIR(st0.st_mode)) goto retry; char *relative = uwsgi_concat2(mountpoint, "/../"); if (stat(relative, &st1)) { free(relative); goto retry; } free(relative); // useless :P if (!S_ISDIR(st1.st_mode)) goto retry; if (st0.st_dev == st1.st_dev) goto retry; uwsgi_log_verbose("%s mounted\n", mountpoint); return 0; retry: sleep(1); counter++; } return -1; } // type -> 1 file, 2 dir, 0 both int uwsgi_wait_for_fs(char *filename, int type) { if (!uwsgi.wait_for_fs_timeout) { uwsgi.wait_for_fs_timeout = 60; } uwsgi_log("waiting for %s (max %d seconds) ...\n", filename, uwsgi.wait_for_fs_timeout); int counter = 0; for (;;) { if (counter > uwsgi.wait_for_fs_timeout) { uwsgi_log("%s unavailable after %d seconds\n", filename, counter); return -1; } struct stat st; if (stat(filename, &st)) goto retry; if (type == 1 && !S_ISREG(st.st_mode)) goto retry; if (type == 2 && !S_ISDIR(st.st_mode)) goto retry; uwsgi_log_verbose("%s found\n", filename); return 0; retry: sleep(1); counter++; } return -1; } int uwsgi_wait_for_socket(char *socket_name) { if (!uwsgi.wait_for_socket_timeout) { uwsgi.wait_for_socket_timeout = 60; } uwsgi_log("waiting for %s (max %d seconds) ...\n", socket_name, uwsgi.wait_for_socket_timeout); int counter = 0; for (;;) { if (counter > uwsgi.wait_for_socket_timeout) { uwsgi_log("%s unavailable after %d seconds\n", socket_name, counter); return -1; } // wait for 1 second to respect uwsgi.wait_for_fs_timeout int fd = uwsgi_connect(socket_name, 1, 0); if (fd < 0) goto retry; close(fd); uwsgi_log_verbose("%s ready\n", socket_name); return 0; retry: sleep(1); counter++; } return -1; } void uwsgi_fix_range_for_size(enum uwsgi_range* parsed, int64_t* from, int64_t* to, int64_t size) { if (*parsed != UWSGI_RANGE_PARSED) { return; } if (*from < 0) { *from = size + *from; } if (*to > size-1) { *to = size-1; } if (*from == 0 && *to == size-1) { /* we have a right to reset to 200 OK answer */ *parsed = UWSGI_RANGE_NOT_PARSED; } else if (*to >= *from) { *parsed = UWSGI_RANGE_VALID; } else { /* case *from > size-1 is also handled here */ *parsed = UWSGI_RANGE_INVALID; *from = 0; *to = 0; } } uwsgi-2.0.29/core/uwsgi.c000066400000000000000000006525321477626554400152350ustar00rootroot00000000000000/* *** uWSGI *** Copyright (C) 2009-2017 Unbit S.a.s. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "uwsgi.h" struct uwsgi_server uwsgi; pid_t masterpid; #if defined(__APPLE__) && defined(UWSGI_AS_SHARED_LIBRARY) #include #define UWSGI_ENVIRON (*_NSGetEnviron()) #else extern char **environ; #define UWSGI_ENVIRON environ #endif UWSGI_DECLARE_EMBEDDED_PLUGINS; static struct uwsgi_option uwsgi_base_options[] = { {"socket", required_argument, 's', "bind to the specified UNIX/TCP socket using default protocol", uwsgi_opt_add_socket, NULL, 0}, {"uwsgi-socket", required_argument, 's', "bind to the specified UNIX/TCP socket using uwsgi protocol", uwsgi_opt_add_socket, "uwsgi", 0}, #ifdef UWSGI_SSL {"suwsgi-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using uwsgi protocol over SSL", uwsgi_opt_add_ssl_socket, "suwsgi", 0}, {"ssl-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using uwsgi protocol over SSL", uwsgi_opt_add_ssl_socket, "suwsgi", 0}, #endif {"http-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using HTTP protocol", uwsgi_opt_add_socket, "http", 0}, {"http-socket-modifier1", required_argument, 0, "force the specified modifier1 when using HTTP protocol", uwsgi_opt_set_64bit, &uwsgi.http_modifier1, 0}, {"http-socket-modifier2", required_argument, 0, "force the specified modifier2 when using HTTP protocol", uwsgi_opt_set_64bit, &uwsgi.http_modifier2, 0}, {"http11-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using HTTP 1.1 (Keep-Alive) protocol", uwsgi_opt_add_socket, "http11", 0}, #ifdef UWSGI_SSL {"https-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using HTTPS protocol", uwsgi_opt_add_ssl_socket, "https", 0}, {"https-socket-modifier1", required_argument, 0, "force the specified modifier1 when using HTTPS protocol", uwsgi_opt_set_64bit, &uwsgi.https_modifier1, 0}, {"https-socket-modifier2", required_argument, 0, "force the specified modifier2 when using HTTPS protocol", uwsgi_opt_set_64bit, &uwsgi.https_modifier2, 0}, #endif {"fastcgi-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using FastCGI protocol", uwsgi_opt_add_socket, "fastcgi", 0}, {"fastcgi-nph-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using FastCGI protocol (nph mode)", uwsgi_opt_add_socket, "fastcgi-nph", 0}, {"fastcgi-modifier1", required_argument, 0, "force the specified modifier1 when using FastCGI protocol", uwsgi_opt_set_64bit, &uwsgi.fastcgi_modifier1, 0}, {"fastcgi-modifier2", required_argument, 0, "force the specified modifier2 when using FastCGI protocol", uwsgi_opt_set_64bit, &uwsgi.fastcgi_modifier2, 0}, {"scgi-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using SCGI protocol", uwsgi_opt_add_socket, "scgi", 0}, {"scgi-nph-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using SCGI protocol (nph mode)", uwsgi_opt_add_socket, "scgi-nph", 0}, {"scgi-modifier1", required_argument, 0, "force the specified modifier1 when using SCGI protocol", uwsgi_opt_set_64bit, &uwsgi.scgi_modifier1, 0}, {"scgi-modifier2", required_argument, 0, "force the specified modifier2 when using SCGI protocol", uwsgi_opt_set_64bit, &uwsgi.scgi_modifier2, 0}, {"raw-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using RAW protocol", uwsgi_opt_add_socket_no_defer, "raw", 0}, {"raw-modifier1", required_argument, 0, "force the specified modifier1 when using RAW protocol", uwsgi_opt_set_64bit, &uwsgi.raw_modifier1, 0}, {"raw-modifier2", required_argument, 0, "force the specified modifier2 when using RAW protocol", uwsgi_opt_set_64bit, &uwsgi.raw_modifier2, 0}, {"puwsgi-socket", required_argument, 0, "bind to the specified UNIX/TCP socket using persistent uwsgi protocol (puwsgi)", uwsgi_opt_add_socket, "puwsgi", 0}, {"protocol", required_argument, 0, "force the specified protocol for default sockets", uwsgi_opt_set_str, &uwsgi.protocol, 0}, {"socket-protocol", required_argument, 0, "force the specified protocol for default sockets", uwsgi_opt_set_str, &uwsgi.protocol, 0}, {"shared-socket", required_argument, 0, "create a shared socket for advanced jailing or ipc", uwsgi_opt_add_shared_socket, NULL, 0}, {"undeferred-shared-socket", required_argument, 0, "create a shared socket for advanced jailing or ipc (undeferred mode)", uwsgi_opt_add_shared_socket, NULL, 0}, {"processes", required_argument, 'p', "spawn the specified number of workers/processes", uwsgi_opt_set_int, &uwsgi.numproc, 0}, {"workers", required_argument, 'p', "spawn the specified number of workers/processes", uwsgi_opt_set_int, &uwsgi.numproc, 0}, {"thunder-lock", no_argument, 0, "serialize accept() usage (if possible)", uwsgi_opt_true, &uwsgi.use_thunder_lock, 0}, {"harakiri", required_argument, 't', "set harakiri timeout", uwsgi_opt_set_int, &uwsgi.harakiri_options.workers, 0}, {"harakiri-verbose", no_argument, 0, "enable verbose mode for harakiri", uwsgi_opt_true, &uwsgi.harakiri_verbose, 0}, {"harakiri-graceful-timeout", required_argument, 0, "interval between graceful harakiri attempt and a sigkill", uwsgi_opt_set_int, &uwsgi.harakiri_graceful_timeout, 0}, {"harakiri-graceful-signal", required_argument, 0, "use this signal instead of sigterm for graceful harakiri attempts", uwsgi_opt_set_int, &uwsgi.harakiri_graceful_signal, 0}, {"harakiri-queue-threshold", required_argument, 0, "only trigger harakiri if queue is greater than this threshold", uwsgi_opt_set_int, &uwsgi.harakiri_queue_threshold, 0}, {"harakiri-no-arh", no_argument, 0, "do not enable harakiri during after-request-hook", uwsgi_opt_true, &uwsgi.harakiri_no_arh, 0}, {"no-harakiri-arh", no_argument, 0, "do not enable harakiri during after-request-hook", uwsgi_opt_true, &uwsgi.harakiri_no_arh, 0}, {"no-harakiri-after-req-hook", no_argument, 0, "do not enable harakiri during after-request-hook", uwsgi_opt_true, &uwsgi.harakiri_no_arh, 0}, {"backtrace-depth", required_argument, 0, "set backtrace depth", uwsgi_opt_set_int, &uwsgi.backtrace_depth, 0}, {"mule-harakiri", required_argument, 0, "set harakiri timeout for mule tasks", uwsgi_opt_set_int, &uwsgi.harakiri_options.mules, 0}, #ifdef UWSGI_XML {"xmlconfig", required_argument, 'x', "load config from xml file", uwsgi_opt_load_xml, NULL, UWSGI_OPT_IMMEDIATE}, {"xml", required_argument, 'x', "load config from xml file", uwsgi_opt_load_xml, NULL, UWSGI_OPT_IMMEDIATE}, #endif {"config", required_argument, 0, "load configuration using the pluggable system", uwsgi_opt_load_config, NULL, UWSGI_OPT_IMMEDIATE}, {"fallback-config", required_argument, 0, "re-exec uwsgi with the specified config when exit code is 1", uwsgi_opt_set_str, &uwsgi.fallback_config, UWSGI_OPT_IMMEDIATE}, {"strict", no_argument, 0, "enable strict mode (placeholder cannot be used)", uwsgi_opt_true, &uwsgi.strict, UWSGI_OPT_IMMEDIATE}, {"skip-zero", no_argument, 0, "skip check of file descriptor 0", uwsgi_opt_true, &uwsgi.skip_zero, 0}, {"skip-atexit", no_argument, 0, "skip atexit hooks (ignored by the master)", uwsgi_opt_true, &uwsgi.skip_atexit, 0}, {"skip-atexit-teardown", no_argument, 0, "skip atexit teardown (ignored by the master)", uwsgi_opt_true, &uwsgi.skip_atexit_teardown, 0}, {"set", required_argument, 'S', "set a placeholder or an option", uwsgi_opt_set_placeholder, NULL, UWSGI_OPT_IMMEDIATE}, {"set-placeholder", required_argument, 0, "set a placeholder", uwsgi_opt_set_placeholder, (void *) 1, UWSGI_OPT_IMMEDIATE}, {"set-ph", required_argument, 0, "set a placeholder", uwsgi_opt_set_placeholder, (void *) 1, UWSGI_OPT_IMMEDIATE}, {"get", required_argument, 0, "print the specified option value and exit", uwsgi_opt_add_string_list, &uwsgi.get_list, UWSGI_OPT_NO_INITIAL}, {"declare-option", required_argument, 0, "declare a new uWSGI custom option", uwsgi_opt_add_custom_option, NULL, UWSGI_OPT_IMMEDIATE}, {"declare-option2", required_argument, 0, "declare a new uWSGI custom option (non-immediate)", uwsgi_opt_add_custom_option, NULL, 0}, {"resolve", required_argument, 0, "place the result of a dns query in the specified placeholder, sytax: placeholder=name (immediate option)", uwsgi_opt_resolve, NULL, UWSGI_OPT_IMMEDIATE}, {"for", required_argument, 0, "(opt logic) for cycle", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for, UWSGI_OPT_IMMEDIATE}, {"for-glob", required_argument, 0, "(opt logic) for cycle (expand glob)", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for_glob, UWSGI_OPT_IMMEDIATE}, {"for-times", required_argument, 0, "(opt logic) for cycle (expand the specified num to a list starting from 1)", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for_times, UWSGI_OPT_IMMEDIATE}, {"for-readline", required_argument, 0, "(opt logic) for cycle (expand the specified file to a list of lines)", uwsgi_opt_logic, (void *) uwsgi_logic_opt_for_readline, UWSGI_OPT_IMMEDIATE}, {"endfor", optional_argument, 0, "(opt logic) end for cycle", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE}, {"end-for", optional_argument, 0, "(opt logic) end for cycle", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE}, {"if-opt", required_argument, 0, "(opt logic) check for option", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_opt, UWSGI_OPT_IMMEDIATE}, {"if-not-opt", required_argument, 0, "(opt logic) check for option", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_opt, UWSGI_OPT_IMMEDIATE}, {"if-env", required_argument, 0, "(opt logic) check for environment variable", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_env, UWSGI_OPT_IMMEDIATE}, {"if-not-env", required_argument, 0, "(opt logic) check for environment variable", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_env, UWSGI_OPT_IMMEDIATE}, {"ifenv", required_argument, 0, "(opt logic) check for environment variable", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_env, UWSGI_OPT_IMMEDIATE}, {"if-reload", no_argument, 0, "(opt logic) check for reload", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_reload, UWSGI_OPT_IMMEDIATE}, {"if-not-reload", no_argument, 0, "(opt logic) check for reload", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_reload, UWSGI_OPT_IMMEDIATE}, {"if-hostname", required_argument, 0, "(opt logic) check for hostname", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_hostname, UWSGI_OPT_IMMEDIATE}, {"if-not-hostname", required_argument, 0, "(opt logic) check for hostname", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_hostname, UWSGI_OPT_IMMEDIATE}, #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) {"if-hostname-match", required_argument, 0, "(opt logic) try to match hostname against a regular expression", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_hostname_match, UWSGI_OPT_IMMEDIATE}, {"if-not-hostname-match", required_argument, 0, "(opt logic) try to match hostname against a regular expression", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_hostname_match, UWSGI_OPT_IMMEDIATE}, #endif {"if-exists", required_argument, 0, "(opt logic) check for file/directory existence", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_exists, UWSGI_OPT_IMMEDIATE}, {"if-not-exists", required_argument, 0, "(opt logic) check for file/directory existence", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_exists, UWSGI_OPT_IMMEDIATE}, {"ifexists", required_argument, 0, "(opt logic) check for file/directory existence", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_exists, UWSGI_OPT_IMMEDIATE}, {"if-plugin", required_argument, 0, "(opt logic) check for plugin", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_plugin, UWSGI_OPT_IMMEDIATE}, {"if-not-plugin", required_argument, 0, "(opt logic) check for plugin", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_plugin, UWSGI_OPT_IMMEDIATE}, {"ifplugin", required_argument, 0, "(opt logic) check for plugin", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_plugin, UWSGI_OPT_IMMEDIATE}, {"if-file", required_argument, 0, "(opt logic) check for file existance", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_file, UWSGI_OPT_IMMEDIATE}, {"if-not-file", required_argument, 0, "(opt logic) check for file existance", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_file, UWSGI_OPT_IMMEDIATE}, {"if-dir", required_argument, 0, "(opt logic) check for directory existance", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_dir, UWSGI_OPT_IMMEDIATE}, {"if-not-dir", required_argument, 0, "(opt logic) check for directory existance", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_not_dir, UWSGI_OPT_IMMEDIATE}, {"ifdir", required_argument, 0, "(opt logic) check for directory existance", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_dir, UWSGI_OPT_IMMEDIATE}, {"if-directory", required_argument, 0, "(opt logic) check for directory existance", uwsgi_opt_logic, (void *) uwsgi_logic_opt_if_dir, UWSGI_OPT_IMMEDIATE}, {"endif", optional_argument, 0, "(opt logic) end if", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE}, {"end-if", optional_argument, 0, "(opt logic) end if", uwsgi_opt_noop, NULL, UWSGI_OPT_IMMEDIATE}, {"blacklist", required_argument, 0, "set options blacklist context", uwsgi_opt_set_str, &uwsgi.blacklist_context, UWSGI_OPT_IMMEDIATE}, {"end-blacklist", no_argument, 0, "clear options blacklist context", uwsgi_opt_set_null, &uwsgi.blacklist_context, UWSGI_OPT_IMMEDIATE}, {"whitelist", required_argument, 0, "set options whitelist context", uwsgi_opt_set_str, &uwsgi.whitelist_context, UWSGI_OPT_IMMEDIATE}, {"end-whitelist", no_argument, 0, "clear options whitelist context", uwsgi_opt_set_null, &uwsgi.whitelist_context, UWSGI_OPT_IMMEDIATE}, {"ignore-sigpipe", no_argument, 0, "do not report (annoying) SIGPIPE", uwsgi_opt_true, &uwsgi.ignore_sigpipe, 0}, {"ignore-write-errors", no_argument, 0, "do not report (annoying) write()/writev() errors", uwsgi_opt_true, &uwsgi.ignore_write_errors, 0}, {"write-errors-tolerance", required_argument, 0, "set the maximum number of allowed write errors (default: no tolerance)", uwsgi_opt_set_64bit, &uwsgi.write_errors_tolerance, 0}, {"write-errors-exception-only", no_argument, 0, "only raise an exception on write errors giving control to the app itself", uwsgi_opt_true, &uwsgi.write_errors_exception_only, 0}, {"disable-write-exception", no_argument, 0, "disable exception generation on write()/writev()", uwsgi_opt_true, &uwsgi.disable_write_exception, 0}, {"inherit", required_argument, 0, "use the specified file as config template", uwsgi_opt_load, NULL, 0}, {"include", required_argument, 0, "include the specified file as immediate configuration", uwsgi_opt_load, NULL, UWSGI_OPT_IMMEDIATE}, {"inject-before", required_argument, 0, "inject a text file before the config file (advanced templating)", uwsgi_opt_add_string_list, &uwsgi.inject_before, UWSGI_OPT_IMMEDIATE}, {"inject-after", required_argument, 0, "inject a text file after the config file (advanced templating)", uwsgi_opt_add_string_list, &uwsgi.inject_after, UWSGI_OPT_IMMEDIATE}, {"daemonize", required_argument, 'd', "daemonize uWSGI", uwsgi_opt_set_str, &uwsgi.daemonize, 0}, {"daemonize2", required_argument, 0, "daemonize uWSGI after app loading", uwsgi_opt_set_str, &uwsgi.daemonize2, 0}, {"stop", required_argument, 0, "stop an instance", uwsgi_opt_pidfile_signal, (void *) SIGINT, UWSGI_OPT_IMMEDIATE}, {"reload", required_argument, 0, "reload an instance", uwsgi_opt_pidfile_signal, (void *) SIGHUP, UWSGI_OPT_IMMEDIATE}, {"pause", required_argument, 0, "pause an instance", uwsgi_opt_pidfile_signal, (void *) SIGTSTP, UWSGI_OPT_IMMEDIATE}, {"suspend", required_argument, 0, "suspend an instance", uwsgi_opt_pidfile_signal, (void *) SIGTSTP, UWSGI_OPT_IMMEDIATE}, {"resume", required_argument, 0, "resume an instance", uwsgi_opt_pidfile_signal, (void *) SIGTSTP, UWSGI_OPT_IMMEDIATE}, {"connect-and-read", required_argument, 0, "connect to a socket and wait for data from it", uwsgi_opt_connect_and_read, NULL, UWSGI_OPT_IMMEDIATE}, {"extract", required_argument, 0, "fetch/dump any supported address to stdout", uwsgi_opt_extract, NULL, UWSGI_OPT_IMMEDIATE}, {"listen", required_argument, 'l', "set the socket listen queue size", uwsgi_opt_set_int, &uwsgi.listen_queue, UWSGI_OPT_IMMEDIATE}, {"max-vars", required_argument, 'v', "set the amount of internal iovec/vars structures", uwsgi_opt_max_vars, NULL, 0}, {"max-apps", required_argument, 0, "set the maximum number of per-worker applications", uwsgi_opt_set_int, &uwsgi.max_apps, 0}, {"buffer-size", required_argument, 'b', "set internal buffer size", uwsgi_opt_set_16bit, &uwsgi.buffer_size, 0}, {"memory-report", no_argument, 'm', "enable memory report", uwsgi_opt_true, &uwsgi.logging_options.memory_report, 0}, {"profiler", required_argument, 0, "enable the specified profiler", uwsgi_opt_set_str, &uwsgi.profiler, 0}, {"cgi-mode", no_argument, 'c', "force CGI-mode for plugins supporting it", uwsgi_opt_true, &uwsgi.cgi_mode, 0}, {"abstract-socket", no_argument, 'a', "force UNIX socket in abstract mode (Linux only)", uwsgi_opt_true, &uwsgi.abstract_socket, 0}, {"chmod-socket", optional_argument, 'C', "chmod-socket", uwsgi_opt_chmod_socket, NULL, 0}, {"chmod", optional_argument, 'C', "chmod-socket", uwsgi_opt_chmod_socket, NULL, 0}, {"chown-socket", required_argument, 0, "chown unix sockets", uwsgi_opt_set_str, &uwsgi.chown_socket, 0}, {"umask", required_argument, 0, "set umask", uwsgi_opt_set_umask, NULL, UWSGI_OPT_IMMEDIATE}, #ifdef __linux__ {"freebind", no_argument, 0, "put socket in freebind mode", uwsgi_opt_true, &uwsgi.freebind, 0}, #endif {"map-socket", required_argument, 0, "map sockets to specific workers", uwsgi_opt_add_string_list, &uwsgi.map_socket, 0}, {"enable-threads", no_argument, 'T', "enable threads (stub option this is true by default)", uwsgi_opt_true, &uwsgi.has_threads, 0}, {"no-threads-wait", no_argument, 0, "do not wait for threads cancellation on quit/reload", uwsgi_opt_true, &uwsgi.no_threads_wait, 0}, {"auto-procname", no_argument, 0, "automatically set processes name to something meaningful", uwsgi_opt_true, &uwsgi.auto_procname, 0}, {"procname-prefix", required_argument, 0, "add a prefix to the process names", uwsgi_opt_set_str, &uwsgi.procname_prefix, UWSGI_OPT_PROCNAME}, {"procname-prefix-spaced", required_argument, 0, "add a spaced prefix to the process names", uwsgi_opt_set_str_spaced, &uwsgi.procname_prefix, UWSGI_OPT_PROCNAME}, {"procname-append", required_argument, 0, "append a string to process names", uwsgi_opt_set_str, &uwsgi.procname_append, UWSGI_OPT_PROCNAME}, {"procname", required_argument, 0, "set process names", uwsgi_opt_set_str, &uwsgi.procname, UWSGI_OPT_PROCNAME}, {"procname-master", required_argument, 0, "set master process name", uwsgi_opt_set_str, &uwsgi.procname_master, UWSGI_OPT_PROCNAME}, {"single-interpreter", no_argument, 'i', "do not use multiple interpreters (where available)", uwsgi_opt_true, &uwsgi.single_interpreter, 0}, {"need-app", optional_argument, 0, "exit if no app can be loaded", uwsgi_opt_true, &uwsgi.need_app, 0}, {"master", no_argument, 'M', "enable master process", uwsgi_opt_true, &uwsgi.master_process, 0}, {"honour-stdin", no_argument, 0, "do not remap stdin to /dev/null", uwsgi_opt_true, &uwsgi.honour_stdin, 0}, {"emperor", required_argument, 0, "run the Emperor", uwsgi_opt_add_string_list, &uwsgi.emperor, 0}, {"emperor-proxy-socket", required_argument, 0, "force the vassal to became an Emperor proxy", uwsgi_opt_set_str, &uwsgi.emperor_proxy, 0}, {"emperor-wrapper", required_argument, 0, "set a binary wrapper for vassals", uwsgi_opt_set_str, &uwsgi.emperor_wrapper, 0}, {"emperor-wrapper-override", required_argument, 0, "set a binary wrapper for vassals to try before the default one", uwsgi_opt_add_string_list, &uwsgi.emperor_wrapper_override, 0}, {"emperor-wrapper-fallback", required_argument, 0, "set a binary wrapper for vassals to try as a last resort", uwsgi_opt_add_string_list, &uwsgi.emperor_wrapper_fallback, 0}, {"emperor-nofollow", no_argument, 0, "do not follow symlinks when checking for mtime", uwsgi_opt_true, &uwsgi.emperor_nofollow, 0}, {"emperor-procname", required_argument, 0, "set the Emperor process name", uwsgi_opt_set_str, &uwsgi.emperor_procname, 0}, {"emperor-freq", required_argument, 0, "set the Emperor scan frequency (default 3 seconds)", uwsgi_opt_set_int, &uwsgi.emperor_freq, 0}, {"emperor-required-heartbeat", required_argument, 0, "set the Emperor tolerance about heartbeats", uwsgi_opt_set_int, &uwsgi.emperor_heartbeat, 0}, {"emperor-curse-tolerance", required_argument, 0, "set the Emperor tolerance about cursed vassals", uwsgi_opt_set_int, &uwsgi.emperor_curse_tolerance, 0}, {"emperor-pidfile", required_argument, 0, "write the Emperor pid in the specified file", uwsgi_opt_set_str, &uwsgi.emperor_pidfile, 0}, {"emperor-tyrant", no_argument, 0, "put the Emperor in Tyrant mode", uwsgi_opt_true, &uwsgi.emperor_tyrant, 0}, {"emperor-tyrant-nofollow", no_argument, 0, "do not follow symlinks when checking for uid/gid in Tyrant mode", uwsgi_opt_true, &uwsgi.emperor_tyrant_nofollow, 0}, {"emperor-stats", required_argument, 0, "run the Emperor stats server", uwsgi_opt_set_str, &uwsgi.emperor_stats, 0}, {"emperor-stats-server", required_argument, 0, "run the Emperor stats server", uwsgi_opt_set_str, &uwsgi.emperor_stats, 0}, {"early-emperor", no_argument, 0, "spawn the emperor as soon as possibile", uwsgi_opt_true, &uwsgi.early_emperor, 0}, {"emperor-broodlord", required_argument, 0, "run the emperor in BroodLord mode", uwsgi_opt_set_int, &uwsgi.emperor_broodlord, 0}, {"emperor-throttle", required_argument, 0, "set throttling level (in milliseconds) for bad behaving vassals (default 1000)", uwsgi_opt_set_int, &uwsgi.emperor_throttle, 0}, {"emperor-max-throttle", required_argument, 0, "set max throttling level (in milliseconds) for bad behaving vassals (default 3 minutes)", uwsgi_opt_set_int, &uwsgi.emperor_max_throttle, 0}, {"emperor-magic-exec", no_argument, 0, "prefix vassals config files with exec:// if they have the executable bit", uwsgi_opt_true, &uwsgi.emperor_magic_exec, 0}, {"emperor-on-demand-extension", required_argument, 0, "search for text file (vassal name + extension) containing the on demand socket name", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_extension, 0}, {"emperor-on-demand-ext", required_argument, 0, "search for text file (vassal name + extension) containing the on demand socket name", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_extension, 0}, {"emperor-on-demand-directory", required_argument, 0, "enable on demand mode binding to the unix socket in the specified directory named like the vassal + .socket", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_directory, 0}, {"emperor-on-demand-dir", required_argument, 0, "enable on demand mode binding to the unix socket in the specified directory named like the vassal + .socket", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_directory, 0}, {"emperor-on-demand-exec", required_argument, 0, "use the output of the specified command as on demand socket name (the vassal name is passed as the only argument)", uwsgi_opt_set_str, &uwsgi.emperor_on_demand_exec, 0}, {"emperor-extra-extension", required_argument, 0, "allows the specified extension in the Emperor (vassal will be called with --config)", uwsgi_opt_add_string_list, &uwsgi.emperor_extra_extension, 0}, {"emperor-extra-ext", required_argument, 0, "allows the specified extension in the Emperor (vassal will be called with --config)", uwsgi_opt_add_string_list, &uwsgi.emperor_extra_extension, 0}, {"emperor-no-blacklist", no_argument, 0, "disable Emperor blacklisting subsystem", uwsgi_opt_true, &uwsgi.emperor_no_blacklist, 0}, #if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL) {"emperor-use-clone", required_argument, 0, "use clone() instead of fork() passing the specified unshare() flags", uwsgi_opt_set_unshare, &uwsgi.emperor_clone, 0}, #endif {"emperor-graceful-shutdown", no_argument, 0, "use vassals graceful shutdown during ragnarok", uwsgi_opt_true, &uwsgi.emperor_graceful_shutdown, 0}, #ifdef UWSGI_CAP {"emperor-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0}, {"vassals-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0}, {"vassal-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0}, #endif {"imperial-monitor-list", no_argument, 0, "list enabled imperial monitors", uwsgi_opt_true, &uwsgi.imperial_monitor_list, 0}, {"imperial-monitors-list", no_argument, 0, "list enabled imperial monitors", uwsgi_opt_true, &uwsgi.imperial_monitor_list, 0}, {"vassals-inherit", required_argument, 0, "add config templates to vassals config (uses --inherit)", uwsgi_opt_add_string_list, &uwsgi.vassals_templates, 0}, {"vassals-include", required_argument, 0, "include config templates to vassals config (uses --include instead of --inherit)", uwsgi_opt_add_string_list, &uwsgi.vassals_includes, 0}, {"vassals-inherit-before", required_argument, 0, "add config templates to vassals config (uses --inherit, parses before the vassal file)", uwsgi_opt_add_string_list, &uwsgi.vassals_templates_before, 0}, {"vassals-include-before", required_argument, 0, "include config templates to vassals config (uses --include instead of --inherit, parses before the vassal file)", uwsgi_opt_add_string_list, &uwsgi.vassals_includes_before, 0}, {"vassals-start-hook", required_argument, 0, "run the specified command before each vassal starts", uwsgi_opt_set_str, &uwsgi.vassals_start_hook, 0}, {"vassals-stop-hook", required_argument, 0, "run the specified command after vassal's death", uwsgi_opt_set_str, &uwsgi.vassals_stop_hook, 0}, {"vassal-sos", required_argument, 0, "ask emperor for reinforcement when overloaded", uwsgi_opt_set_int, &uwsgi.vassal_sos, 0}, {"vassal-sos-backlog", required_argument, 0, "ask emperor for sos if backlog queue has more items than the value specified", uwsgi_opt_set_int, &uwsgi.vassal_sos_backlog, 0}, {"vassals-set", required_argument, 0, "automatically set the specified option (via --set) for every vassal", uwsgi_opt_add_string_list, &uwsgi.vassals_set, 0}, {"vassal-set", required_argument, 0, "automatically set the specified option (via --set) for every vassal", uwsgi_opt_add_string_list, &uwsgi.vassals_set, 0}, {"heartbeat", required_argument, 0, "announce healthiness to the emperor", uwsgi_opt_set_int, &uwsgi.heartbeat, 0}, {"reload-mercy", required_argument, 0, "set the maximum time (in seconds) we wait for workers and other processes to die during reload/shutdown", uwsgi_opt_set_int, &uwsgi.reload_mercy, 0}, {"worker-reload-mercy", required_argument, 0, "set the maximum time (in seconds) a worker can take to reload/shutdown (default is 60)", uwsgi_opt_set_int, &uwsgi.worker_reload_mercy, 0}, {"mule-reload-mercy", required_argument, 0, "set the maximum time (in seconds) a mule can take to reload/shutdown (default is 60)", uwsgi_opt_set_int, &uwsgi.mule_reload_mercy, 0}, {"exit-on-reload", no_argument, 0, "force exit even if a reload is requested", uwsgi_opt_true, &uwsgi.exit_on_reload, 0}, {"die-on-term", no_argument, 0, "exit instead of brutal reload on SIGTERM", uwsgi_opt_true, &uwsgi.die_on_term, 0}, {"force-gateway", no_argument, 0, "force the spawn of the first registered gateway without a master", uwsgi_opt_true, &uwsgi.force_gateway, 0}, {"help", no_argument, 'h', "show this help", uwsgi_help, NULL, UWSGI_OPT_IMMEDIATE}, {"usage", no_argument, 'h', "show this help", uwsgi_help, NULL, UWSGI_OPT_IMMEDIATE}, {"print-sym", required_argument, 0, "print content of the specified binary symbol", uwsgi_print_sym, NULL, UWSGI_OPT_IMMEDIATE}, {"print-symbol", required_argument, 0, "print content of the specified binary symbol", uwsgi_print_sym, NULL, UWSGI_OPT_IMMEDIATE}, {"reaper", no_argument, 'r', "call waitpid(-1,...) after each request to get rid of zombies", uwsgi_opt_true, &uwsgi.reaper, 0}, {"max-requests", required_argument, 'R', "reload workers after the specified amount of managed requests", uwsgi_opt_set_64bit, &uwsgi.max_requests, 0}, {"max-requests-delta", required_argument, 0, "add (worker_id * delta) to the max_requests value of each worker", uwsgi_opt_set_64bit, &uwsgi.max_requests_delta, 0}, {"min-worker-lifetime", required_argument, 0, "number of seconds worker must run before being reloaded (default is 10)", uwsgi_opt_set_64bit, &uwsgi.min_worker_lifetime, 0}, {"max-worker-lifetime", required_argument, 0, "reload workers after the specified amount of seconds (default is disabled)", uwsgi_opt_set_64bit, &uwsgi.max_worker_lifetime, 0}, {"max-worker-lifetime-delta", required_argument, 0, "add (worker_id * delta) seconds to the max_worker_lifetime value of each worker", uwsgi_opt_set_int, &uwsgi.max_worker_lifetime_delta, 0}, {"socket-timeout", required_argument, 'z', "set internal sockets timeout", uwsgi_opt_set_int, &uwsgi.socket_timeout, 0}, {"no-fd-passing", no_argument, 0, "disable file descriptor passing", uwsgi_opt_true, &uwsgi.no_fd_passing, 0}, {"locks", required_argument, 0, "create the specified number of shared locks", uwsgi_opt_set_int, &uwsgi.locks, 0}, {"lock-engine", required_argument, 0, "set the lock engine", uwsgi_opt_set_str, &uwsgi.lock_engine, 0}, {"ftok", required_argument, 0, "set the ipcsem key via ftok() for avoiding duplicates", uwsgi_opt_set_str, &uwsgi.ftok, 0}, {"persistent-ipcsem", no_argument, 0, "do not remove ipcsem's on shutdown", uwsgi_opt_true, &uwsgi.persistent_ipcsem, 0}, {"sharedarea", required_argument, 'A', "create a raw shared memory area of specified pages (note: it supports keyval too)", uwsgi_opt_add_string_list, &uwsgi.sharedareas_list, 0}, {"safe-fd", required_argument, 0, "do not close the specified file descriptor", uwsgi_opt_safe_fd, NULL, 0}, {"fd-safe", required_argument, 0, "do not close the specified file descriptor", uwsgi_opt_safe_fd, NULL, 0}, {"cache", required_argument, 0, "create a shared cache containing given elements", uwsgi_opt_set_64bit, &uwsgi.cache_max_items, 0}, {"cache-blocksize", required_argument, 0, "set cache blocksize", uwsgi_opt_set_64bit, &uwsgi.cache_blocksize, 0}, {"cache-store", required_argument, 0, "enable persistent cache to disk", uwsgi_opt_set_str, &uwsgi.cache_store, UWSGI_OPT_MASTER}, {"cache-store-sync", required_argument, 0, "set frequency of sync for persistent cache", uwsgi_opt_set_int, &uwsgi.cache_store_sync, 0}, {"cache-no-expire", no_argument, 0, "disable auto sweep of expired items", uwsgi_opt_true, &uwsgi.cache_no_expire, 0}, {"cache-expire-freq", required_argument, 0, "set the frequency of cache sweeper scans (default 3 seconds)", uwsgi_opt_set_int, &uwsgi.cache_expire_freq, 0}, {"cache-report-freed-items", no_argument, 0, "constantly report the cache item freed by the sweeper (use only for debug)", uwsgi_opt_true, &uwsgi.cache_report_freed_items, 0}, {"cache-udp-server", required_argument, 0, "bind the cache udp server (used only for set/update/delete) to the specified socket", uwsgi_opt_add_string_list, &uwsgi.cache_udp_server, UWSGI_OPT_MASTER}, {"cache-udp-node", required_argument, 0, "send cache update/deletion to the specified cache udp server", uwsgi_opt_add_string_list, &uwsgi.cache_udp_node, UWSGI_OPT_MASTER}, {"cache-sync", required_argument, 0, "copy the whole content of another uWSGI cache server on server startup", uwsgi_opt_set_str, &uwsgi.cache_sync, 0}, {"cache-use-last-modified", no_argument, 0, "update last_modified_at timestamp on every cache item modification (default is disabled)", uwsgi_opt_true, &uwsgi.cache_use_last_modified, 0}, {"add-cache-item", required_argument, 0, "add an item in the cache", uwsgi_opt_add_string_list, &uwsgi.add_cache_item, 0}, {"load-file-in-cache", required_argument, 0, "load a static file in the cache", uwsgi_opt_add_string_list, &uwsgi.load_file_in_cache, 0}, #ifdef UWSGI_ZLIB {"load-file-in-cache-gzip", required_argument, 0, "load a static file in the cache with gzip compression", uwsgi_opt_add_string_list, &uwsgi.load_file_in_cache_gzip, 0}, #endif {"cache2", required_argument, 0, "create a new generation shared cache (keyval syntax)", uwsgi_opt_add_string_list, &uwsgi.cache2, 0}, {"queue", required_argument, 0, "enable shared queue", uwsgi_opt_set_int, &uwsgi.queue_size, 0}, {"queue-blocksize", required_argument, 0, "set queue blocksize", uwsgi_opt_set_int, &uwsgi.queue_blocksize, 0}, {"queue-store", required_argument, 0, "enable persistent queue to disk", uwsgi_opt_set_str, &uwsgi.queue_store, UWSGI_OPT_MASTER}, {"queue-store-sync", required_argument, 0, "set frequency of sync for persistent queue", uwsgi_opt_set_int, &uwsgi.queue_store_sync, 0}, {"spooler", required_argument, 'Q', "run a spooler on the specified directory", uwsgi_opt_add_spooler, NULL, UWSGI_OPT_MASTER}, {"spooler-external", required_argument, 0, "map spoolers requests to a spooler directory managed by an external instance", uwsgi_opt_add_spooler, (void *) UWSGI_SPOOLER_EXTERNAL, UWSGI_OPT_MASTER}, {"spooler-ordered", no_argument, 0, "try to order the execution of spooler tasks", uwsgi_opt_true, &uwsgi.spooler_ordered, 0}, {"spooler-chdir", required_argument, 0, "chdir() to specified directory before each spooler task", uwsgi_opt_set_str, &uwsgi.spooler_chdir, 0}, {"spooler-processes", required_argument, 0, "set the number of processes for spoolers", uwsgi_opt_set_int, &uwsgi.spooler_numproc, UWSGI_OPT_IMMEDIATE}, {"spooler-quiet", no_argument, 0, "do not be verbose with spooler tasks", uwsgi_opt_true, &uwsgi.spooler_quiet, 0}, {"spooler-max-tasks", required_argument, 0, "set the maximum number of tasks to run before recycling a spooler", uwsgi_opt_set_int, &uwsgi.spooler_max_tasks, 0}, {"spooler-harakiri", required_argument, 0, "set harakiri timeout for spooler tasks", uwsgi_opt_set_int, &uwsgi.harakiri_options.spoolers, 0}, {"spooler-frequency", required_argument, 0, "set spooler frequency", uwsgi_opt_set_int, &uwsgi.spooler_frequency, 0}, {"spooler-freq", required_argument, 0, "set spooler frequency", uwsgi_opt_set_int, &uwsgi.spooler_frequency, 0}, {"mule", optional_argument, 0, "add a mule", uwsgi_opt_add_mule, NULL, UWSGI_OPT_MASTER}, {"mules", required_argument, 0, "add the specified number of mules", uwsgi_opt_add_mules, NULL, UWSGI_OPT_MASTER}, {"farm", required_argument, 0, "add a mule farm", uwsgi_opt_add_farm, NULL, UWSGI_OPT_MASTER}, {"mule-msg-size", optional_argument, 0, "set mule message buffer size", uwsgi_opt_set_int, &uwsgi.mule_msg_size, UWSGI_OPT_MASTER}, {"signal", required_argument, 0, "send a uwsgi signal to a server", uwsgi_opt_signal, NULL, UWSGI_OPT_IMMEDIATE}, {"signal-bufsize", required_argument, 0, "set buffer size for signal queue", uwsgi_opt_set_int, &uwsgi.signal_bufsize, 0}, {"signals-bufsize", required_argument, 0, "set buffer size for signal queue", uwsgi_opt_set_int, &uwsgi.signal_bufsize, 0}, {"signal-timer", required_argument, 0, "add a timer (syntax: )", uwsgi_opt_add_string_list, &uwsgi.signal_timers, UWSGI_OPT_MASTER}, {"timer", required_argument, 0, "add a timer (syntax: )", uwsgi_opt_add_string_list, &uwsgi.signal_timers, UWSGI_OPT_MASTER}, {"signal-rbtimer", required_argument, 0, "add a redblack timer (syntax: )", uwsgi_opt_add_string_list, &uwsgi.rb_signal_timers, UWSGI_OPT_MASTER}, {"rbtimer", required_argument, 0, "add a redblack timer (syntax: )", uwsgi_opt_add_string_list, &uwsgi.rb_signal_timers, UWSGI_OPT_MASTER}, {"rpc-max", required_argument, 0, "maximum number of rpc slots (default: 64)", uwsgi_opt_set_64bit, &uwsgi.rpc_max, 0}, {"disable-logging", no_argument, 'L', "disable request logging", uwsgi_opt_false, &uwsgi.logging_options.enabled, 0}, {"flock", required_argument, 0, "lock the specified file before starting, exit if locked", uwsgi_opt_flock, NULL, UWSGI_OPT_IMMEDIATE}, {"flock-wait", required_argument, 0, "lock the specified file before starting, wait if locked", uwsgi_opt_flock_wait, NULL, UWSGI_OPT_IMMEDIATE}, {"flock2", required_argument, 0, "lock the specified file after logging/daemon setup, exit if locked", uwsgi_opt_set_str, &uwsgi.flock2, UWSGI_OPT_IMMEDIATE}, {"flock-wait2", required_argument, 0, "lock the specified file after logging/daemon setup, wait if locked", uwsgi_opt_set_str, &uwsgi.flock_wait2, UWSGI_OPT_IMMEDIATE}, {"pidfile", required_argument, 0, "create pidfile (before privileges drop)", uwsgi_opt_set_str, &uwsgi.pidfile, 0}, {"pidfile2", required_argument, 0, "create pidfile (after privileges drop)", uwsgi_opt_set_str, &uwsgi.pidfile2, 0}, {"safe-pidfile", required_argument, 0, "create safe pidfile (before privileges drop)", uwsgi_opt_set_str, &uwsgi.safe_pidfile, 0}, {"safe-pidfile2", required_argument, 0, "create safe pidfile (after privileges drop)", uwsgi_opt_set_str, &uwsgi.safe_pidfile2, 0}, {"chroot", required_argument, 0, "chroot() to the specified directory", uwsgi_opt_set_str, &uwsgi.chroot, 0}, #ifdef __linux__ {"pivot-root", required_argument, 0, "pivot_root() to the specified directories (new_root and put_old must be separated with a space)", uwsgi_opt_set_str, &uwsgi.pivot_root, 0}, {"pivot_root", required_argument, 0, "pivot_root() to the specified directories (new_root and put_old must be separated with a space)", uwsgi_opt_set_str, &uwsgi.pivot_root, 0}, #endif {"uid", required_argument, 0, "setuid to the specified user/uid", uwsgi_opt_set_uid, NULL, 0}, {"gid", required_argument, 0, "setgid to the specified group/gid", uwsgi_opt_set_gid, NULL, 0}, {"add-gid", required_argument, 0, "add the specified group id to the process credentials", uwsgi_opt_add_string_list, &uwsgi.additional_gids, 0}, {"immediate-uid", required_argument, 0, "setuid to the specified user/uid IMMEDIATELY", uwsgi_opt_set_immediate_uid, NULL, UWSGI_OPT_IMMEDIATE}, {"immediate-gid", required_argument, 0, "setgid to the specified group/gid IMMEDIATELY", uwsgi_opt_set_immediate_gid, NULL, UWSGI_OPT_IMMEDIATE}, {"no-initgroups", no_argument, 0, "disable additional groups set via initgroups()", uwsgi_opt_true, &uwsgi.no_initgroups, 0}, #ifdef UWSGI_CAP {"cap", required_argument, 0, "set process capability", uwsgi_opt_set_cap, NULL, 0}, #endif #ifdef __linux__ {"unshare", required_argument, 0, "unshare() part of the processes and put it in a new namespace", uwsgi_opt_set_unshare, &uwsgi.unshare, 0}, {"unshare2", required_argument, 0, "unshare() part of the processes and put it in a new namespace after rootfs change", uwsgi_opt_set_unshare, &uwsgi.unshare2, 0}, {"setns-socket", required_argument, 0, "expose a unix socket returning namespace fds from /proc/self/ns", uwsgi_opt_set_str, &uwsgi.setns_socket, UWSGI_OPT_MASTER}, {"setns-socket-skip", required_argument, 0, "skip the specified entry when sending setns file descriptors", uwsgi_opt_add_string_list, &uwsgi.setns_socket_skip, 0}, {"setns-skip", required_argument, 0, "skip the specified entry when sending setns file descriptors", uwsgi_opt_add_string_list, &uwsgi.setns_socket_skip, 0}, {"setns", required_argument, 0, "join a namespace created by an external uWSGI instance", uwsgi_opt_set_str, &uwsgi.setns, 0}, {"setns-preopen", no_argument, 0, "open /proc/self/ns as soon as possible and cache fds", uwsgi_opt_true, &uwsgi.setns_preopen, 0}, #endif {"jailed", no_argument, 0, "mark the instance as jailed (force the execution of post_jail hooks)", uwsgi_opt_true, &uwsgi.jailed, 0}, #if defined(__FreeBSD__) || defined(__GNU_kFreeBSD__) {"jail", required_argument, 0, "put the instance in a FreeBSD jail", uwsgi_opt_set_str, &uwsgi.jail, 0}, {"jail-ip4", required_argument, 0, "add an ipv4 address to the FreeBSD jail", uwsgi_opt_add_string_list, &uwsgi.jail_ip4, 0}, {"jail-ip6", required_argument, 0, "add an ipv6 address to the FreeBSD jail", uwsgi_opt_add_string_list, &uwsgi.jail_ip6, 0}, {"jidfile", required_argument, 0, "save the jid of a FreeBSD jail in the specified file", uwsgi_opt_set_str, &uwsgi.jidfile, 0}, {"jid-file", required_argument, 0, "save the jid of a FreeBSD jail in the specified file", uwsgi_opt_set_str, &uwsgi.jidfile, 0}, #ifdef UWSGI_HAS_FREEBSD_LIBJAIL {"jail2", required_argument, 0, "add an option to the FreeBSD jail", uwsgi_opt_add_string_list, &uwsgi.jail2, 0}, {"libjail", required_argument, 0, "add an option to the FreeBSD jail", uwsgi_opt_add_string_list, &uwsgi.jail2, 0}, {"jail-attach", required_argument, 0, "attach to the FreeBSD jail", uwsgi_opt_set_str, &uwsgi.jail_attach, 0}, #endif #endif {"refork", no_argument, 0, "fork() again after privileges drop. Useful for jailing systems", uwsgi_opt_true, &uwsgi.refork, 0}, {"re-fork", no_argument, 0, "fork() again after privileges drop. Useful for jailing systems", uwsgi_opt_true, &uwsgi.refork, 0}, {"refork-as-root", no_argument, 0, "fork() again before privileges drop. Useful for jailing systems", uwsgi_opt_true, &uwsgi.refork_as_root, 0}, {"re-fork-as-root", no_argument, 0, "fork() again before privileges drop. Useful for jailing systems", uwsgi_opt_true, &uwsgi.refork_as_root, 0}, {"refork-post-jail", no_argument, 0, "fork() again after jailing. Useful for jailing systems", uwsgi_opt_true, &uwsgi.refork_post_jail, 0}, {"re-fork-post-jail", no_argument, 0, "fork() again after jailing. Useful for jailing systems", uwsgi_opt_true, &uwsgi.refork_post_jail, 0}, {"hook-asap", required_argument, 0, "run the specified hook as soon as possible", uwsgi_opt_add_string_list, &uwsgi.hook_asap, 0}, {"hook-pre-jail", required_argument, 0, "run the specified hook before jailing", uwsgi_opt_add_string_list, &uwsgi.hook_pre_jail, 0}, {"hook-post-jail", required_argument, 0, "run the specified hook after jailing", uwsgi_opt_add_string_list, &uwsgi.hook_post_jail, 0}, {"hook-in-jail", required_argument, 0, "run the specified hook in jail after initialization", uwsgi_opt_add_string_list, &uwsgi.hook_in_jail, 0}, {"hook-as-root", required_argument, 0, "run the specified hook before privileges drop", uwsgi_opt_add_string_list, &uwsgi.hook_as_root, 0}, {"hook-as-user", required_argument, 0, "run the specified hook after privileges drop", uwsgi_opt_add_string_list, &uwsgi.hook_as_user, 0}, {"hook-as-user-atexit", required_argument, 0, "run the specified hook before app exit and reload", uwsgi_opt_add_string_list, &uwsgi.hook_as_user_atexit, 0}, {"hook-pre-app", required_argument, 0, "run the specified hook before app loading", uwsgi_opt_add_string_list, &uwsgi.hook_pre_app, 0}, {"hook-post-app", required_argument, 0, "run the specified hook after app loading", uwsgi_opt_add_string_list, &uwsgi.hook_post_app, 0}, {"hook-post-fork", required_argument, 0, "run the specified hook after each fork", uwsgi_opt_add_string_list, &uwsgi.hook_post_fork, 0}, {"hook-accepting", required_argument, 0, "run the specified hook after each worker enter the accepting phase", uwsgi_opt_add_string_list, &uwsgi.hook_accepting, 0}, {"hook-accepting1", required_argument, 0, "run the specified hook after the first worker enters the accepting phase", uwsgi_opt_add_string_list, &uwsgi.hook_accepting1, 0}, {"hook-accepting-once", required_argument, 0, "run the specified hook after each worker enter the accepting phase (once per-instance)", uwsgi_opt_add_string_list, &uwsgi.hook_accepting_once, 0}, {"hook-accepting1-once", required_argument, 0, "run the specified hook after the first worker enters the accepting phase (once per instance)", uwsgi_opt_add_string_list, &uwsgi.hook_accepting1_once, 0}, {"hook-master-start", required_argument, 0, "run the specified hook when the Master starts", uwsgi_opt_add_string_list, &uwsgi.hook_master_start, 0}, {"hook-touch", required_argument, 0, "run the specified hook when the specified file is touched (syntax: )", uwsgi_opt_add_string_list, &uwsgi.hook_touch, 0}, {"hook-emperor-start", required_argument, 0, "run the specified hook when the Emperor starts", uwsgi_opt_add_string_list, &uwsgi.hook_emperor_start, 0}, {"hook-emperor-stop", required_argument, 0, "run the specified hook when the Emperor send a stop message", uwsgi_opt_add_string_list, &uwsgi.hook_emperor_stop, 0}, {"hook-emperor-reload", required_argument, 0, "run the specified hook when the Emperor send a reload message", uwsgi_opt_add_string_list, &uwsgi.hook_emperor_reload, 0}, {"hook-emperor-lost", required_argument, 0, "run the specified hook when the Emperor connection is lost", uwsgi_opt_add_string_list, &uwsgi.hook_emperor_lost, 0}, {"hook-as-vassal", required_argument, 0, "run the specified hook before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.hook_as_vassal, 0}, {"hook-as-emperor", required_argument, 0, "run the specified hook in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.hook_as_emperor, 0}, {"hook-as-mule", required_argument, 0, "run the specified hook in each mule", uwsgi_opt_add_string_list, &uwsgi.hook_as_mule, 0}, {"hook-as-gateway", required_argument, 0, "run the specified hook in each gateway", uwsgi_opt_add_string_list, &uwsgi.hook_as_gateway, 0}, {"after-request-hook", required_argument, 0, "run the specified function/symbol after each request", uwsgi_opt_add_string_list, &uwsgi.after_request_hooks, 0}, {"after-request-call", required_argument, 0, "run the specified function/symbol after each request", uwsgi_opt_add_string_list, &uwsgi.after_request_hooks, 0}, {"exec-asap", required_argument, 0, "run the specified command as soon as possible", uwsgi_opt_add_string_list, &uwsgi.exec_asap, 0}, {"exec-pre-jail", required_argument, 0, "run the specified command before jailing", uwsgi_opt_add_string_list, &uwsgi.exec_pre_jail, 0}, {"exec-post-jail", required_argument, 0, "run the specified command after jailing", uwsgi_opt_add_string_list, &uwsgi.exec_post_jail, 0}, {"exec-in-jail", required_argument, 0, "run the specified command in jail after initialization", uwsgi_opt_add_string_list, &uwsgi.exec_in_jail, 0}, {"exec-as-root", required_argument, 0, "run the specified command before privileges drop", uwsgi_opt_add_string_list, &uwsgi.exec_as_root, 0}, {"exec-as-user", required_argument, 0, "run the specified command after privileges drop", uwsgi_opt_add_string_list, &uwsgi.exec_as_user, 0}, {"exec-as-user-atexit", required_argument, 0, "run the specified command before app exit and reload", uwsgi_opt_add_string_list, &uwsgi.exec_as_user_atexit, 0}, {"exec-pre-app", required_argument, 0, "run the specified command before app loading", uwsgi_opt_add_string_list, &uwsgi.exec_pre_app, 0}, {"exec-post-app", required_argument, 0, "run the specified command after app loading", uwsgi_opt_add_string_list, &uwsgi.exec_post_app, 0}, {"exec-as-vassal", required_argument, 0, "run the specified command before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.exec_as_vassal, 0}, {"exec-as-emperor", required_argument, 0, "run the specified command in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.exec_as_emperor, 0}, {"mount-asap", required_argument, 0, "mount filesystem as soon as possible", uwsgi_opt_add_string_list, &uwsgi.mount_asap, 0}, {"mount-pre-jail", required_argument, 0, "mount filesystem before jailing", uwsgi_opt_add_string_list, &uwsgi.mount_pre_jail, 0}, {"mount-post-jail", required_argument, 0, "mount filesystem after jailing", uwsgi_opt_add_string_list, &uwsgi.mount_post_jail, 0}, {"mount-in-jail", required_argument, 0, "mount filesystem in jail after initialization", uwsgi_opt_add_string_list, &uwsgi.mount_in_jail, 0}, {"mount-as-root", required_argument, 0, "mount filesystem before privileges drop", uwsgi_opt_add_string_list, &uwsgi.mount_as_root, 0}, {"mount-as-vassal", required_argument, 0, "mount filesystem before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.mount_as_vassal, 0}, {"mount-as-emperor", required_argument, 0, "mount filesystem in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.mount_as_emperor, 0}, {"umount-asap", required_argument, 0, "unmount filesystem as soon as possible", uwsgi_opt_add_string_list, &uwsgi.umount_asap, 0}, {"umount-pre-jail", required_argument, 0, "unmount filesystem before jailing", uwsgi_opt_add_string_list, &uwsgi.umount_pre_jail, 0}, {"umount-post-jail", required_argument, 0, "unmount filesystem after jailing", uwsgi_opt_add_string_list, &uwsgi.umount_post_jail, 0}, {"umount-in-jail", required_argument, 0, "unmount filesystem in jail after initialization", uwsgi_opt_add_string_list, &uwsgi.umount_in_jail, 0}, {"umount-as-root", required_argument, 0, "unmount filesystem before privileges drop", uwsgi_opt_add_string_list, &uwsgi.umount_as_root, 0}, {"umount-as-vassal", required_argument, 0, "unmount filesystem before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.umount_as_vassal, 0}, {"umount-as-emperor", required_argument, 0, "unmount filesystem in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.umount_as_emperor, 0}, {"wait-for-interface", required_argument, 0, "wait for the specified network interface to come up before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_interface, 0}, {"wait-for-interface-timeout", required_argument, 0, "set the timeout for wait-for-interface", uwsgi_opt_set_int, &uwsgi.wait_for_interface_timeout, 0}, {"wait-interface", required_argument, 0, "wait for the specified network interface to come up before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_interface, 0}, {"wait-interface-timeout", required_argument, 0, "set the timeout for wait-for-interface", uwsgi_opt_set_int, &uwsgi.wait_for_interface_timeout, 0}, {"wait-for-iface", required_argument, 0, "wait for the specified network interface to come up before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_interface, 0}, {"wait-for-iface-timeout", required_argument, 0, "set the timeout for wait-for-interface", uwsgi_opt_set_int, &uwsgi.wait_for_interface_timeout, 0}, {"wait-iface", required_argument, 0, "wait for the specified network interface to come up before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_interface, 0}, {"wait-iface-timeout", required_argument, 0, "set the timeout for wait-for-interface", uwsgi_opt_set_int, &uwsgi.wait_for_interface_timeout, 0}, {"wait-for-fs", required_argument, 0, "wait for the specified filesystem item to appear before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_fs, 0}, {"wait-for-file", required_argument, 0, "wait for the specified file to appear before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_fs, 0}, {"wait-for-dir", required_argument, 0, "wait for the specified directory to appear before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_fs, 0}, {"wait-for-mountpoint", required_argument, 0, "wait for the specified mountpoint to appear before running root hooks", uwsgi_opt_add_string_list, &uwsgi.wait_for_mountpoint, 0}, {"wait-for-fs-timeout", required_argument, 0, "set the timeout for wait-for-fs/file/dir", uwsgi_opt_set_int, &uwsgi.wait_for_fs_timeout, 0}, {"wait-for-socket", required_argument, 0, "wait for the specified socket to be ready before loading apps", uwsgi_opt_add_string_list, &uwsgi.wait_for_socket, 0}, {"wait-for-socket-timeout", required_argument, 0, "set the timeout for wait-for-socket", uwsgi_opt_set_int, &uwsgi.wait_for_socket_timeout, 0}, {"call-asap", required_argument, 0, "call the specified function as soon as possible", uwsgi_opt_add_string_list, &uwsgi.call_asap, 0}, {"call-pre-jail", required_argument, 0, "call the specified function before jailing", uwsgi_opt_add_string_list, &uwsgi.call_pre_jail, 0}, {"call-post-jail", required_argument, 0, "call the specified function after jailing", uwsgi_opt_add_string_list, &uwsgi.call_post_jail, 0}, {"call-in-jail", required_argument, 0, "call the specified function in jail after initialization", uwsgi_opt_add_string_list, &uwsgi.call_in_jail, 0}, {"call-as-root", required_argument, 0, "call the specified function before privileges drop", uwsgi_opt_add_string_list, &uwsgi.call_as_root, 0}, {"call-as-user", required_argument, 0, "call the specified function after privileges drop", uwsgi_opt_add_string_list, &uwsgi.call_as_user, 0}, {"call-as-user-atexit", required_argument, 0, "call the specified function before app exit and reload", uwsgi_opt_add_string_list, &uwsgi.call_as_user_atexit, 0}, {"call-pre-app", required_argument, 0, "call the specified function before app loading", uwsgi_opt_add_string_list, &uwsgi.call_pre_app, 0}, {"call-post-app", required_argument, 0, "call the specified function after app loading", uwsgi_opt_add_string_list, &uwsgi.call_post_app, 0}, {"call-as-vassal", required_argument, 0, "call the specified function() before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.call_as_vassal, 0}, {"call-as-vassal1", required_argument, 0, "call the specified function(char *) before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.call_as_vassal1, 0}, {"call-as-vassal3", required_argument, 0, "call the specified function(char *, uid_t, gid_t) before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.call_as_vassal3, 0}, {"call-as-emperor", required_argument, 0, "call the specified function() in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.call_as_emperor, 0}, {"call-as-emperor1", required_argument, 0, "call the specified function(char *) in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.call_as_emperor1, 0}, {"call-as-emperor2", required_argument, 0, "call the specified function(char *, pid_t) in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.call_as_emperor2, 0}, {"call-as-emperor4", required_argument, 0, "call the specified function(char *, pid_t, uid_t, gid_t) in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.call_as_emperor4, 0}, {"ini", required_argument, 0, "load config from ini file", uwsgi_opt_load_ini, NULL, UWSGI_OPT_IMMEDIATE}, #ifdef UWSGI_YAML {"yaml", required_argument, 'y', "load config from yaml file", uwsgi_opt_load_yml, NULL, UWSGI_OPT_IMMEDIATE}, {"yml", required_argument, 'y', "load config from yaml file", uwsgi_opt_load_yml, NULL, UWSGI_OPT_IMMEDIATE}, #endif #ifdef UWSGI_JSON {"json", required_argument, 'j', "load config from json file", uwsgi_opt_load_json, NULL, UWSGI_OPT_IMMEDIATE}, {"js", required_argument, 'j', "load config from json file", uwsgi_opt_load_json, NULL, UWSGI_OPT_IMMEDIATE}, #endif {"weight", required_argument, 0, "weight of the instance (used by clustering/lb/subscriptions)", uwsgi_opt_set_64bit, &uwsgi.weight, 0}, {"auto-weight", required_argument, 0, "set weight of the instance (used by clustering/lb/subscriptions) automatically", uwsgi_opt_true, &uwsgi.auto_weight, 0}, {"no-server", no_argument, 0, "force no-server mode", uwsgi_opt_true, &uwsgi.no_server, 0}, {"command-mode", no_argument, 0, "force command mode", uwsgi_opt_true, &uwsgi.command_mode, UWSGI_OPT_IMMEDIATE}, {"no-defer-accept", no_argument, 0, "disable deferred-accept on sockets", uwsgi_opt_true, &uwsgi.no_defer_accept, 0}, {"tcp-nodelay", no_argument, 0, "enable TCP NODELAY on each request", uwsgi_opt_true, &uwsgi.tcp_nodelay, 0}, {"so-keepalive", no_argument, 0, "enable TCP KEEPALIVEs", uwsgi_opt_true, &uwsgi.so_keepalive, 0}, {"so-send-timeout", no_argument, 0, "set SO_SNDTIMEO", uwsgi_opt_set_int, &uwsgi.so_send_timeout, 0}, {"socket-send-timeout", no_argument, 0, "set SO_SNDTIMEO", uwsgi_opt_set_int, &uwsgi.so_send_timeout, 0}, {"so-write-timeout", no_argument, 0, "set SO_SNDTIMEO", uwsgi_opt_set_int, &uwsgi.so_send_timeout, 0}, {"socket-write-timeout", no_argument, 0, "set SO_SNDTIMEO", uwsgi_opt_set_int, &uwsgi.so_send_timeout, 0}, {"socket-sndbuf", required_argument, 0, "set SO_SNDBUF", uwsgi_opt_set_64bit, &uwsgi.so_sndbuf, 0}, {"socket-rcvbuf", required_argument, 0, "set SO_RCVBUF", uwsgi_opt_set_64bit, &uwsgi.so_rcvbuf, 0}, {"shutdown-sockets", no_argument, 0, "force calling shutdown() in addition to close() when sockets are destroyed", uwsgi_opt_true, &uwsgi.shutdown_sockets, 0}, {"limit-as", required_argument, 0, "limit processes address space/vsz", uwsgi_opt_set_megabytes, &uwsgi.rl.rlim_max, 0}, {"limit-nproc", required_argument, 0, "limit the number of spawnable processes", uwsgi_opt_set_int, &uwsgi.rl_nproc.rlim_max, 0}, {"reload-on-as", required_argument, 0, "reload if address space is higher than specified megabytes", uwsgi_opt_set_megabytes, &uwsgi.reload_on_as, UWSGI_OPT_MEMORY}, {"reload-on-rss", required_argument, 0, "reload if rss memory is higher than specified megabytes", uwsgi_opt_set_megabytes, &uwsgi.reload_on_rss, UWSGI_OPT_MEMORY}, {"evil-reload-on-as", required_argument, 0, "force the master to reload a worker if its address space is higher than specified megabytes", uwsgi_opt_set_megabytes, &uwsgi.evil_reload_on_as, UWSGI_OPT_MASTER | UWSGI_OPT_MEMORY}, {"evil-reload-on-rss", required_argument, 0, "force the master to reload a worker if its rss memory is higher than specified megabytes", uwsgi_opt_set_megabytes, &uwsgi.evil_reload_on_rss, UWSGI_OPT_MASTER | UWSGI_OPT_MEMORY}, {"mem-collector-freq", required_argument, 0, "set the memory collector frequency when evil reloads are in place", uwsgi_opt_set_int, &uwsgi.mem_collector_freq, 0}, {"reload-on-fd", required_argument, 0, "reload if the specified file descriptor is ready", uwsgi_opt_add_string_list, &uwsgi.reload_on_fd, UWSGI_OPT_MASTER}, {"brutal-reload-on-fd", required_argument, 0, "brutal reload if the specified file descriptor is ready", uwsgi_opt_add_string_list, &uwsgi.brutal_reload_on_fd, UWSGI_OPT_MASTER}, #ifdef __linux__ #ifdef MADV_MERGEABLE {"ksm", optional_argument, 0, "enable Linux KSM", uwsgi_opt_set_int, &uwsgi.linux_ksm, 0}, #endif #endif #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) {"pcre-jit", no_argument, 0, "enable pcre jit (if available)", uwsgi_opt_pcre_jit, NULL, UWSGI_OPT_IMMEDIATE}, #endif {"never-swap", no_argument, 0, "lock all memory pages avoiding swapping", uwsgi_opt_true, &uwsgi.never_swap, 0}, {"touch-reload", required_argument, 0, "reload uWSGI if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_reload, UWSGI_OPT_MASTER}, {"touch-workers-reload", required_argument, 0, "trigger reload of (only) workers if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_workers_reload, UWSGI_OPT_MASTER}, {"touch-mules-reload", required_argument, 0, "reload mules if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_mules_reload, UWSGI_OPT_MASTER}, {"touch-spoolers-reload", required_argument, 0, "reload spoolers if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_spoolers_reload, UWSGI_OPT_MASTER}, {"touch-chain-reload", required_argument, 0, "trigger chain reload if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_chain_reload, UWSGI_OPT_MASTER}, {"touch-logrotate", required_argument, 0, "trigger logrotation if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_logrotate, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER}, {"touch-logreopen", required_argument, 0, "trigger log reopen if the specified file is modified/touched", uwsgi_opt_add_string_list, &uwsgi.touch_logreopen, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER}, {"touch-exec", required_argument, 0, "run command when the specified file is modified/touched (syntax: file command)", uwsgi_opt_add_string_list, &uwsgi.touch_exec, UWSGI_OPT_MASTER}, {"touch-signal", required_argument, 0, "signal when the specified file is modified/touched (syntax: file signal)", uwsgi_opt_add_string_list, &uwsgi.touch_signal, UWSGI_OPT_MASTER}, {"fs-reload", required_argument, 0, "graceful reload when the specified filesystem object is modified", uwsgi_opt_add_string_list, &uwsgi.fs_reload, UWSGI_OPT_MASTER}, {"fs-brutal-reload", required_argument, 0, "brutal reload when the specified filesystem object is modified", uwsgi_opt_add_string_list, &uwsgi.fs_brutal_reload, UWSGI_OPT_MASTER}, {"fs-signal", required_argument, 0, "raise a uwsgi signal when the specified filesystem object is modified (syntax: file signal)", uwsgi_opt_add_string_list, &uwsgi.fs_signal, UWSGI_OPT_MASTER}, {"check-mountpoint", required_argument, 0, "destroy the instance if a filesystem is no more reachable (useful for reliable Fuse management)", uwsgi_opt_add_string_list, &uwsgi.mountpoints_check, UWSGI_OPT_MASTER}, {"mountpoint-check", required_argument, 0, "destroy the instance if a filesystem is no more reachable (useful for reliable Fuse management)", uwsgi_opt_add_string_list, &uwsgi.mountpoints_check, UWSGI_OPT_MASTER}, {"check-mount", required_argument, 0, "destroy the instance if a filesystem is no more reachable (useful for reliable Fuse management)", uwsgi_opt_add_string_list, &uwsgi.mountpoints_check, UWSGI_OPT_MASTER}, {"mount-check", required_argument, 0, "destroy the instance if a filesystem is no more reachable (useful for reliable Fuse management)", uwsgi_opt_add_string_list, &uwsgi.mountpoints_check, UWSGI_OPT_MASTER}, {"propagate-touch", no_argument, 0, "over-engineering option for system with flaky signal management", uwsgi_opt_true, &uwsgi.propagate_touch, 0}, {"limit-post", required_argument, 0, "limit request body", uwsgi_opt_set_64bit, &uwsgi.limit_post, 0}, {"no-orphans", no_argument, 0, "automatically kill workers if master dies (can be dangerous for availability)", uwsgi_opt_true, &uwsgi.no_orphans, 0}, {"prio", required_argument, 0, "set processes/threads priority", uwsgi_opt_set_rawint, &uwsgi.prio, 0}, {"cpu-affinity", required_argument, 0, "set cpu affinity", uwsgi_opt_set_int, &uwsgi.cpu_affinity, 0}, {"post-buffering", required_argument, 0, "set size in bytes after which will buffer to disk instead of memory", uwsgi_opt_set_64bit, &uwsgi.post_buffering, 0}, {"post-buffering-bufsize", required_argument, 0, "set buffer size for read() in post buffering mode", uwsgi_opt_set_64bit, &uwsgi.post_buffering_bufsize, 0}, {"body-read-warning", required_argument, 0, "set the amount of allowed memory allocation (in megabytes) for request body before starting printing a warning", uwsgi_opt_set_64bit, &uwsgi.body_read_warning, 0}, {"upload-progress", required_argument, 0, "enable creation of .json files in the specified directory during a file upload", uwsgi_opt_set_str, &uwsgi.upload_progress, 0}, {"no-default-app", no_argument, 0, "do not fallback to default app", uwsgi_opt_true, &uwsgi.no_default_app, 0}, {"manage-script-name", no_argument, 0, "automatically rewrite SCRIPT_NAME and PATH_INFO", uwsgi_opt_true, &uwsgi.manage_script_name, 0}, {"ignore-script-name", no_argument, 0, "ignore SCRIPT_NAME", uwsgi_opt_true, &uwsgi.ignore_script_name, 0}, {"catch-exceptions", no_argument, 0, "report exception as http output (discouraged, use only for testing)", uwsgi_opt_true, &uwsgi.catch_exceptions, 0}, {"reload-on-exception", no_argument, 0, "reload a worker when an exception is raised", uwsgi_opt_true, &uwsgi.reload_on_exception, 0}, {"reload-on-exception-type", required_argument, 0, "reload a worker when a specific exception type is raised", uwsgi_opt_add_string_list, &uwsgi.reload_on_exception_type, 0}, {"reload-on-exception-value", required_argument, 0, "reload a worker when a specific exception value is raised", uwsgi_opt_add_string_list, &uwsgi.reload_on_exception_value, 0}, {"reload-on-exception-repr", required_argument, 0, "reload a worker when a specific exception type+value (language-specific) is raised", uwsgi_opt_add_string_list, &uwsgi.reload_on_exception_repr, 0}, {"exception-handler", required_argument, 0, "add an exception handler", uwsgi_opt_add_string_list, &uwsgi.exception_handlers_instance, UWSGI_OPT_MASTER}, {"enable-metrics", no_argument, 0, "enable metrics subsystem", uwsgi_opt_true, &uwsgi.has_metrics, UWSGI_OPT_MASTER}, {"metric", required_argument, 0, "add a custom metric", uwsgi_opt_add_string_list, &uwsgi.additional_metrics, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER}, {"metric-threshold", required_argument, 0, "add a metric threshold/alarm", uwsgi_opt_add_string_list, &uwsgi.metrics_threshold, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER}, {"metric-alarm", required_argument, 0, "add a metric threshold/alarm", uwsgi_opt_add_string_list, &uwsgi.metrics_threshold, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER}, {"alarm-metric", required_argument, 0, "add a metric threshold/alarm", uwsgi_opt_add_string_list, &uwsgi.metrics_threshold, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER}, {"metrics-dir", required_argument, 0, "export metrics as text files to the specified directory", uwsgi_opt_set_str, &uwsgi.metrics_dir, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER}, {"metrics-dir-restore", no_argument, 0, "restore last value taken from the metrics dir", uwsgi_opt_true, &uwsgi.metrics_dir_restore, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER}, {"metric-dir", required_argument, 0, "export metrics as text files to the specified directory", uwsgi_opt_set_str, &uwsgi.metrics_dir, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER}, {"metric-dir-restore", no_argument, 0, "restore last value taken from the metrics dir", uwsgi_opt_true, &uwsgi.metrics_dir_restore, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER}, {"metrics-no-cores", no_argument, 0, "disable generation of cores-related metrics", uwsgi_opt_true, &uwsgi.metrics_no_cores, UWSGI_OPT_METRICS|UWSGI_OPT_MASTER}, {"udp", required_argument, 0, "run the udp server on the specified address", uwsgi_opt_set_str, &uwsgi.udp_socket, UWSGI_OPT_MASTER}, {"stats", required_argument, 0, "enable the stats server on the specified address", uwsgi_opt_set_str, &uwsgi.stats, UWSGI_OPT_MASTER}, {"stats-server", required_argument, 0, "enable the stats server on the specified address", uwsgi_opt_set_str, &uwsgi.stats, UWSGI_OPT_MASTER}, {"stats-http", no_argument, 0, "prefix stats server json output with http headers", uwsgi_opt_true, &uwsgi.stats_http, UWSGI_OPT_MASTER}, {"stats-minified", no_argument, 0, "minify statistics json output", uwsgi_opt_true, &uwsgi.stats_minified, UWSGI_OPT_MASTER}, {"stats-min", no_argument, 0, "minify statistics json output", uwsgi_opt_true, &uwsgi.stats_minified, UWSGI_OPT_MASTER}, {"stats-push", required_argument, 0, "push the stats json to the specified destination", uwsgi_opt_add_string_list, &uwsgi.requested_stats_pushers, UWSGI_OPT_MASTER|UWSGI_OPT_METRICS}, {"stats-pusher-default-freq", required_argument, 0, "set the default frequency of stats pushers", uwsgi_opt_set_int, &uwsgi.stats_pusher_default_freq, UWSGI_OPT_MASTER}, {"stats-pushers-default-freq", required_argument, 0, "set the default frequency of stats pushers", uwsgi_opt_set_int, &uwsgi.stats_pusher_default_freq, UWSGI_OPT_MASTER}, {"stats-no-cores", no_argument, 0, "disable generation of cores-related stats", uwsgi_opt_true, &uwsgi.stats_no_cores, UWSGI_OPT_MASTER}, {"stats-no-metrics", no_argument, 0, "do not include metrics in stats output", uwsgi_opt_true, &uwsgi.stats_no_metrics, UWSGI_OPT_MASTER}, {"multicast", required_argument, 0, "subscribe to specified multicast group", uwsgi_opt_set_str, &uwsgi.multicast_group, UWSGI_OPT_MASTER}, {"multicast-ttl", required_argument, 0, "set multicast ttl", uwsgi_opt_set_int, &uwsgi.multicast_ttl, 0}, {"multicast-loop", required_argument, 0, "set multicast loop (default 1)", uwsgi_opt_set_int, &uwsgi.multicast_loop, 0}, {"master-fifo", required_argument, 0, "enable the master fifo", uwsgi_opt_add_string_list, &uwsgi.master_fifo, UWSGI_OPT_MASTER}, {"notify-socket", required_argument, 0, "enable the notification socket", uwsgi_opt_set_str, &uwsgi.notify_socket, UWSGI_OPT_MASTER}, {"subscription-notify-socket", required_argument, 0, "set the notification socket for subscriptions", uwsgi_opt_set_str, &uwsgi.subscription_notify_socket, UWSGI_OPT_MASTER}, #ifdef UWSGI_SSL {"legion", required_argument, 0, "became a member of a legion", uwsgi_opt_legion, NULL, UWSGI_OPT_MASTER}, {"legion-mcast", required_argument, 0, "became a member of a legion (shortcut for multicast)", uwsgi_opt_legion_mcast, NULL, UWSGI_OPT_MASTER}, {"legion-node", required_argument, 0, "add a node to a legion", uwsgi_opt_legion_node, NULL, UWSGI_OPT_MASTER}, {"legion-freq", required_argument, 0, "set the frequency of legion packets", uwsgi_opt_set_int, &uwsgi.legion_freq, UWSGI_OPT_MASTER}, {"legion-tolerance", required_argument, 0, "set the tolerance of legion subsystem", uwsgi_opt_set_int, &uwsgi.legion_tolerance, UWSGI_OPT_MASTER}, {"legion-death-on-lord-error", required_argument, 0, "declare itself as a dead node for the specified amount of seconds if one of the lord hooks fails", uwsgi_opt_set_int, &uwsgi.legion_death_on_lord_error, UWSGI_OPT_MASTER}, {"legion-skew-tolerance", required_argument, 0, "set the clock skew tolerance of legion subsystem (default 60 seconds)", uwsgi_opt_set_int, &uwsgi.legion_skew_tolerance, UWSGI_OPT_MASTER}, {"legion-lord", required_argument, 0, "action to call on Lord election", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER}, {"legion-unlord", required_argument, 0, "action to call on Lord dismiss", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER}, {"legion-setup", required_argument, 0, "action to call on legion setup", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER}, {"legion-death", required_argument, 0, "action to call on legion death (shutdown of the instance)", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER}, {"legion-join", required_argument, 0, "action to call on legion join (first time quorum is reached)", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER}, {"legion-node-joined", required_argument, 0, "action to call on new node joining legion", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER}, {"legion-node-left", required_argument, 0, "action to call node leaving legion", uwsgi_opt_legion_hook, NULL, UWSGI_OPT_MASTER}, {"legion-quorum", required_argument, 0, "set the quorum of a legion", uwsgi_opt_legion_quorum, NULL, UWSGI_OPT_MASTER}, {"legion-scroll", required_argument, 0, "set the scroll of a legion", uwsgi_opt_legion_scroll, NULL, UWSGI_OPT_MASTER}, {"legion-scroll-max-size", required_argument, 0, "set max size of legion scroll buffer", uwsgi_opt_set_16bit, &uwsgi.legion_scroll_max_size, 0}, {"legion-scroll-list-max-size", required_argument, 0, "set max size of legion scroll list buffer", uwsgi_opt_set_64bit, &uwsgi.legion_scroll_list_max_size, 0}, {"subscriptions-sign-check", required_argument, 0, "set digest algorithm and certificate directory for secured subscription system", uwsgi_opt_scd, NULL, UWSGI_OPT_MASTER}, {"subscriptions-sign-check-tolerance", required_argument, 0, "set the maximum tolerance (in seconds) of clock skew for secured subscription system", uwsgi_opt_set_int, &uwsgi.subscriptions_sign_check_tolerance, UWSGI_OPT_MASTER}, {"subscriptions-sign-skip-uid", required_argument, 0, "skip signature check for the specified uid when using unix sockets credentials", uwsgi_opt_add_string_list, &uwsgi.subscriptions_sign_skip_uid, UWSGI_OPT_MASTER}, #endif {"subscriptions-credentials-check", required_argument, 0, "add a directory to search for subscriptions key credentials", uwsgi_opt_add_string_list, &uwsgi.subscriptions_credentials_check_dir, UWSGI_OPT_MASTER}, {"subscriptions-use-credentials", no_argument, 0, "enable management of SCM_CREDENTIALS in subscriptions UNIX sockets", uwsgi_opt_true, &uwsgi.subscriptions_use_credentials, 0}, {"subscription-algo", required_argument, 0, "set load balancing algorithm for the subscription system", uwsgi_opt_ssa, NULL, 0}, {"subscription-dotsplit", no_argument, 0, "try to fallback to the next part (dot based) in subscription key", uwsgi_opt_true, &uwsgi.subscription_dotsplit, 0}, {"subscribe-to", required_argument, 0, "subscribe to the specified subscription server", uwsgi_opt_add_string_list, &uwsgi.subscriptions, UWSGI_OPT_MASTER}, {"st", required_argument, 0, "subscribe to the specified subscription server", uwsgi_opt_add_string_list, &uwsgi.subscriptions, UWSGI_OPT_MASTER}, {"subscribe", required_argument, 0, "subscribe to the specified subscription server", uwsgi_opt_add_string_list, &uwsgi.subscriptions, UWSGI_OPT_MASTER}, {"subscribe2", required_argument, 0, "subscribe to the specified subscription server using advanced keyval syntax", uwsgi_opt_add_string_list, &uwsgi.subscriptions2, UWSGI_OPT_MASTER}, {"subscribe-freq", required_argument, 0, "send subscription announce at the specified interval", uwsgi_opt_set_int, &uwsgi.subscribe_freq, 0}, {"subscription-tolerance", required_argument, 0, "set tolerance for subscription servers", uwsgi_opt_set_int, &uwsgi.subscription_tolerance, 0}, {"unsubscribe-on-graceful-reload", no_argument, 0, "force unsubscribe request even during graceful reload", uwsgi_opt_true, &uwsgi.unsubscribe_on_graceful_reload, 0}, {"start-unsubscribed", no_argument, 0, "configure subscriptions but do not send them (useful with master fifo)", uwsgi_opt_true, &uwsgi.subscriptions_blocked, 0}, {"subscribe-with-modifier1", required_argument, 0, "force the specififed modifier1 when subscribing", uwsgi_opt_set_str, &uwsgi.subscribe_with_modifier1, UWSGI_OPT_MASTER}, {"snmp", optional_argument, 0, "enable the embedded snmp server", uwsgi_opt_snmp, NULL, 0}, {"snmp-community", required_argument, 0, "set the snmp community string", uwsgi_opt_snmp_community, NULL, 0}, #ifdef UWSGI_SSL {"ssl-verbose", no_argument, 0, "be verbose about SSL errors", uwsgi_opt_true, &uwsgi.ssl_verbose, 0}, {"ssl-verify-depth", optional_argument, 0, "set maximum certificate verification depth", uwsgi_opt_set_int, &uwsgi.ssl_verify_depth, 0}, #ifdef UWSGI_SSL_SESSION_CACHE // force master, as ssl sessions caching initialize locking early {"ssl-sessions-use-cache", optional_argument, 0, "use uWSGI cache for ssl sessions storage", uwsgi_opt_set_str, &uwsgi.ssl_sessions_use_cache, UWSGI_OPT_MASTER}, {"ssl-session-use-cache", optional_argument, 0, "use uWSGI cache for ssl sessions storage", uwsgi_opt_set_str, &uwsgi.ssl_sessions_use_cache, UWSGI_OPT_MASTER}, {"ssl-sessions-timeout", required_argument, 0, "set SSL sessions timeout (default: 300 seconds)", uwsgi_opt_set_int, &uwsgi.ssl_sessions_timeout, 0}, {"ssl-session-timeout", required_argument, 0, "set SSL sessions timeout (default: 300 seconds)", uwsgi_opt_set_int, &uwsgi.ssl_sessions_timeout, 0}, #endif {"sni", required_argument, 0, "add an SNI-governed SSL context", uwsgi_opt_sni, NULL, 0}, {"sni-dir", required_argument, 0, "check for cert/key/client_ca file in the specified directory and create a sni/ssl context on demand", uwsgi_opt_set_str, &uwsgi.sni_dir, 0}, {"sni-dir-ciphers", required_argument, 0, "set ssl ciphers for sni-dir option", uwsgi_opt_set_str, &uwsgi.sni_dir_ciphers, 0}, {"ssl-enable3", no_argument, 0, "enable SSLv3 (insecure)", uwsgi_opt_true, &uwsgi.sslv3, 0}, {"ssl-enable-sslv3", no_argument, 0, "enable SSLv3 (insecure)", uwsgi_opt_true, &uwsgi.sslv3, 0}, {"ssl-enable-tlsv1", no_argument, 0, "enable TLSv1 (insecure)", uwsgi_opt_true, &uwsgi.tlsv1, 0}, {"ssl-option", no_argument, 0, "set a raw ssl option (numeric value)", uwsgi_opt_add_string_list, &uwsgi.ssl_options, 0}, #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) {"sni-regexp", required_argument, 0, "add an SNI-governed SSL context (the key is a regexp)", uwsgi_opt_sni, NULL, 0}, #endif {"ssl-tmp-dir", required_argument, 0, "store ssl-related temp files in the specified directory", uwsgi_opt_set_str, &uwsgi.ssl_tmp_dir, 0}, #endif {"check-interval", required_argument, 0, "set the interval (in seconds) of master checks", uwsgi_opt_set_int, &uwsgi.master_interval, UWSGI_OPT_MASTER}, {"forkbomb-delay", required_argument, 0, "sleep for the specified number of seconds when a forkbomb is detected", uwsgi_opt_set_int, &uwsgi.forkbomb_delay, UWSGI_OPT_MASTER}, {"binary-path", required_argument, 0, "force binary path", uwsgi_opt_set_str, &uwsgi.binary_path, 0}, {"privileged-binary-patch", required_argument, 0, "patch the uwsgi binary with a new command (before privileges drop)", uwsgi_opt_set_str, &uwsgi.privileged_binary_patch, 0}, {"unprivileged-binary-patch", required_argument, 0, "patch the uwsgi binary with a new command (after privileges drop)", uwsgi_opt_set_str, &uwsgi.unprivileged_binary_patch, 0}, {"privileged-binary-patch-arg", required_argument, 0, "patch the uwsgi binary with a new command and arguments (before privileges drop)", uwsgi_opt_set_str, &uwsgi.privileged_binary_patch_arg, 0}, {"unprivileged-binary-patch-arg", required_argument, 0, "patch the uwsgi binary with a new command and arguments (after privileges drop)", uwsgi_opt_set_str, &uwsgi.unprivileged_binary_patch_arg, 0}, {"async", required_argument, 0, "enable async mode with specified cores", uwsgi_opt_set_int, &uwsgi.async, 0}, {"max-fd", required_argument, 0, "set maximum number of file descriptors (requires root privileges)", uwsgi_opt_set_int, &uwsgi.requested_max_fd, 0}, {"logto", required_argument, 0, "set logfile/udp address", uwsgi_opt_set_str, &uwsgi.logfile, 0}, {"logto2", required_argument, 0, "log to specified file or udp address after privileges drop", uwsgi_opt_set_str, &uwsgi.logto2, 0}, {"log-format", required_argument, 0, "set advanced format for request logging", uwsgi_opt_set_str, &uwsgi.logformat, 0}, {"logformat", required_argument, 0, "set advanced format for request logging", uwsgi_opt_set_str, &uwsgi.logformat, 0}, {"logformat-strftime", no_argument, 0, "apply strftime to logformat output", uwsgi_opt_true, &uwsgi.logformat_strftime, 0}, {"log-format-strftime", no_argument, 0, "apply strftime to logformat output", uwsgi_opt_true, &uwsgi.logformat_strftime, 0}, {"logfile-chown", no_argument, 0, "chown logfiles", uwsgi_opt_true, &uwsgi.logfile_chown, 0}, {"logfile-chmod", required_argument, 0, "chmod logfiles", uwsgi_opt_logfile_chmod, NULL, 0}, {"log-syslog", optional_argument, 0, "log to syslog", uwsgi_opt_set_logger, "syslog", UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER}, {"log-socket", required_argument, 0, "send logs to the specified socket", uwsgi_opt_set_logger, "socket", UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER}, {"req-logger", required_argument, 0, "set/append a request logger", uwsgi_opt_set_req_logger, NULL, UWSGI_OPT_REQ_LOG_MASTER}, {"logger-req", required_argument, 0, "set/append a request logger", uwsgi_opt_set_req_logger, NULL, UWSGI_OPT_REQ_LOG_MASTER}, {"logger", required_argument, 0, "set/append a logger", uwsgi_opt_set_logger, NULL, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER}, {"logger-list", no_argument, 0, "list enabled loggers", uwsgi_opt_true, &uwsgi.loggers_list, 0}, {"loggers-list", no_argument, 0, "list enabled loggers", uwsgi_opt_true, &uwsgi.loggers_list, 0}, {"threaded-logger", no_argument, 0, "offload log writing to a thread", uwsgi_opt_true, &uwsgi.threaded_logger, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER}, {"log-encoder", required_argument, 0, "add an item in the log encoder chain", uwsgi_opt_add_string_list, &uwsgi.requested_log_encoders, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER}, {"log-req-encoder", required_argument, 0, "add an item in the log req encoder chain", uwsgi_opt_add_string_list, &uwsgi.requested_log_req_encoders, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER}, #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) {"log-drain", required_argument, 0, "drain (do not show) log lines matching the specified regexp", uwsgi_opt_add_regexp_list, &uwsgi.log_drain_rules, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER}, {"log-filter", required_argument, 0, "show only log lines matching the specified regexp", uwsgi_opt_add_regexp_list, &uwsgi.log_filter_rules, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER}, {"log-route", required_argument, 0, "log to the specified named logger if regexp applied on logline matches", uwsgi_opt_add_regexp_custom_list, &uwsgi.log_route, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER}, {"log-req-route", required_argument, 0, "log requests to the specified named logger if regexp applied on logline matches", uwsgi_opt_add_regexp_custom_list, &uwsgi.log_req_route, UWSGI_OPT_REQ_LOG_MASTER}, #endif {"use-abort", no_argument, 0, "call abort() on segfault/fpe, could be useful for generating a core dump", uwsgi_opt_true, &uwsgi.use_abort, 0}, {"alarm", required_argument, 0, "create a new alarm, syntax: ", uwsgi_opt_add_string_list, &uwsgi.alarm_list, UWSGI_OPT_MASTER}, {"alarm-cheap", required_argument, 0, "use main alarm thread rather than create dedicated threads for curl-based alarms", uwsgi_opt_true, &uwsgi.alarm_cheap, 0}, {"alarm-freq", required_argument, 0, "tune the anti-loop alarm system (default 3 seconds)", uwsgi_opt_set_int, &uwsgi.alarm_freq, 0}, {"alarm-fd", required_argument, 0, "raise the specified alarm when an fd is read for read (by default it reads 1 byte, set 8 for eventfd)", uwsgi_opt_add_string_list, &uwsgi.alarm_fd_list, UWSGI_OPT_MASTER}, {"alarm-segfault", required_argument, 0, "raise the specified alarm when the segmentation fault handler is executed", uwsgi_opt_add_string_list, &uwsgi.alarm_segfault, UWSGI_OPT_MASTER}, {"segfault-alarm", required_argument, 0, "raise the specified alarm when the segmentation fault handler is executed", uwsgi_opt_add_string_list, &uwsgi.alarm_segfault, UWSGI_OPT_MASTER}, {"alarm-backlog", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER}, {"backlog-alarm", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER}, {"lq-alarm", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER}, {"alarm-lq", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER}, {"alarm-listen-queue", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER}, {"listen-queue-alarm", required_argument, 0, "raise the specified alarm when the socket backlog queue is full", uwsgi_opt_add_string_list, &uwsgi.alarm_backlog, UWSGI_OPT_MASTER}, #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) {"log-alarm", required_argument, 0, "raise the specified alarm when a log line matches the specified regexp, syntax: [,alarm...] ", uwsgi_opt_add_string_list, &uwsgi.alarm_logs_list, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER}, {"alarm-log", required_argument, 0, "raise the specified alarm when a log line matches the specified regexp, syntax: [,alarm...] ", uwsgi_opt_add_string_list, &uwsgi.alarm_logs_list, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER}, {"not-log-alarm", required_argument, 0, "skip the specified alarm when a log line matches the specified regexp, syntax: [,alarm...] ", uwsgi_opt_add_string_list_custom, &uwsgi.alarm_logs_list, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER}, {"not-alarm-log", required_argument, 0, "skip the specified alarm when a log line matches the specified regexp, syntax: [,alarm...] ", uwsgi_opt_add_string_list_custom, &uwsgi.alarm_logs_list, UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER}, #endif {"alarm-list", no_argument, 0, "list enabled alarms", uwsgi_opt_true, &uwsgi.alarms_list, 0}, {"alarms-list", no_argument, 0, "list enabled alarms", uwsgi_opt_true, &uwsgi.alarms_list, 0}, {"alarm-msg-size", required_argument, 0, "set the max size of an alarm message (default 8192)", uwsgi_opt_set_64bit, &uwsgi.alarm_msg_size, 0}, {"log-master", no_argument, 0, "delegate logging to master process", uwsgi_opt_true, &uwsgi.log_master, UWSGI_OPT_MASTER|UWSGI_OPT_LOG_MASTER}, {"log-master-bufsize", required_argument, 0, "set the buffer size for the master logger. bigger log messages will be truncated", uwsgi_opt_set_64bit, &uwsgi.log_master_bufsize, 0}, {"log-master-stream", no_argument, 0, "create the master logpipe as SOCK_STREAM", uwsgi_opt_true, &uwsgi.log_master_stream, 0}, {"log-master-req-stream", no_argument, 0, "create the master requests logpipe as SOCK_STREAM", uwsgi_opt_true, &uwsgi.log_master_req_stream, 0}, {"log-reopen", no_argument, 0, "reopen log after reload", uwsgi_opt_true, &uwsgi.log_reopen, 0}, {"log-truncate", no_argument, 0, "truncate log on startup", uwsgi_opt_true, &uwsgi.log_truncate, 0}, {"log-maxsize", required_argument, 0, "set maximum logfile size", uwsgi_opt_set_64bit, &uwsgi.log_maxsize, UWSGI_OPT_MASTER|UWSGI_OPT_LOG_MASTER}, {"log-backupname", required_argument, 0, "set logfile name after rotation", uwsgi_opt_set_str, &uwsgi.log_backupname, 0}, {"logdate", optional_argument, 0, "prefix logs with date or a strftime string", uwsgi_opt_log_date, NULL, 0}, {"log-date", optional_argument, 0, "prefix logs with date or a strftime string", uwsgi_opt_log_date, NULL, 0}, {"log-prefix", optional_argument, 0, "prefix logs with a string", uwsgi_opt_log_date, NULL, 0}, {"log-zero", no_argument, 0, "log responses without body", uwsgi_opt_true, &uwsgi.logging_options.zero, 0}, {"log-slow", required_argument, 0, "log requests slower than the specified number of milliseconds", uwsgi_opt_set_int, &uwsgi.logging_options.slow, 0}, {"log-4xx", no_argument, 0, "log requests with a 4xx response", uwsgi_opt_true, &uwsgi.logging_options._4xx, 0}, {"log-5xx", no_argument, 0, "log requests with a 5xx response", uwsgi_opt_true, &uwsgi.logging_options._5xx, 0}, {"log-big", required_argument, 0, "log requestes bigger than the specified size", uwsgi_opt_set_64bit, &uwsgi.logging_options.big, 0}, {"log-sendfile", required_argument, 0, "log sendfile requests", uwsgi_opt_true, &uwsgi.logging_options.sendfile, 0}, {"log-ioerror", required_argument, 0, "log requests with io errors", uwsgi_opt_true, &uwsgi.logging_options.ioerror, 0}, {"log-micros", no_argument, 0, "report response time in microseconds instead of milliseconds", uwsgi_opt_true, &uwsgi.log_micros, 0}, {"log-x-forwarded-for", no_argument, 0, "use the ip from X-Forwarded-For header instead of REMOTE_ADDR", uwsgi_opt_true, &uwsgi.logging_options.log_x_forwarded_for, 0}, {"master-as-root", no_argument, 0, "leave master process running as root", uwsgi_opt_true, &uwsgi.master_as_root, 0}, {"drop-after-init", no_argument, 0, "run privileges drop after plugin initialization, superseded by drop-after-apps", uwsgi_opt_true, &uwsgi.drop_after_init, 0}, {"drop-after-apps", no_argument, 0, "run privileges drop after apps loading, superseded by master-as-root", uwsgi_opt_true, &uwsgi.drop_after_apps, 0}, {"force-cwd", required_argument, 0, "force the initial working directory to the specified value", uwsgi_opt_set_str, &uwsgi.force_cwd, 0}, {"binsh", required_argument, 0, "override /bin/sh (used by exec hooks, it always fallback to /bin/sh)", uwsgi_opt_add_string_list, &uwsgi.binsh, 0}, {"chdir", required_argument, 0, "chdir to specified directory before apps loading", uwsgi_opt_set_str, &uwsgi.chdir, 0}, {"chdir2", required_argument, 0, "chdir to specified directory after apps loading", uwsgi_opt_set_str, &uwsgi.chdir2, 0}, {"lazy", no_argument, 0, "set lazy mode (load apps in workers instead of master)", uwsgi_opt_true, &uwsgi.lazy, 0}, {"lazy-apps", no_argument, 0, "load apps in each worker instead of the master", uwsgi_opt_true, &uwsgi.lazy_apps, 0}, {"cheap", no_argument, 0, "set cheap mode (spawn workers only after the first request)", uwsgi_opt_true, &uwsgi.status.is_cheap, UWSGI_OPT_MASTER}, {"cheaper", required_argument, 0, "set cheaper mode (adaptive process spawning)", uwsgi_opt_set_int, &uwsgi.cheaper_count, UWSGI_OPT_MASTER | UWSGI_OPT_CHEAPER}, {"cheaper-initial", required_argument, 0, "set the initial number of processes to spawn in cheaper mode", uwsgi_opt_set_int, &uwsgi.cheaper_initial, UWSGI_OPT_MASTER | UWSGI_OPT_CHEAPER}, {"cheaper-algo", required_argument, 0, "choose to algorithm used for adaptive process spawning", uwsgi_opt_set_str, &uwsgi.requested_cheaper_algo, UWSGI_OPT_MASTER}, {"cheaper-step", required_argument, 0, "number of additional processes to spawn at each overload", uwsgi_opt_set_int, &uwsgi.cheaper_step, UWSGI_OPT_MASTER | UWSGI_OPT_CHEAPER}, {"cheaper-overload", required_argument, 0, "increase workers after specified overload", uwsgi_opt_set_64bit, &uwsgi.cheaper_overload, UWSGI_OPT_MASTER | UWSGI_OPT_CHEAPER}, {"cheaper-algo-list", no_argument, 0, "list enabled cheapers algorithms", uwsgi_opt_true, &uwsgi.cheaper_algo_list, 0}, {"cheaper-algos-list", no_argument, 0, "list enabled cheapers algorithms", uwsgi_opt_true, &uwsgi.cheaper_algo_list, 0}, {"cheaper-list", no_argument, 0, "list enabled cheapers algorithms", uwsgi_opt_true, &uwsgi.cheaper_algo_list, 0}, {"cheaper-rss-limit-soft", required_argument, 0, "don't spawn new workers if total resident memory usage of all workers is higher than this limit", uwsgi_opt_set_64bit, &uwsgi.cheaper_rss_limit_soft, UWSGI_OPT_MASTER | UWSGI_OPT_CHEAPER}, {"cheaper-rss-limit-hard", required_argument, 0, "if total workers resident memory usage is higher try to stop workers", uwsgi_opt_set_64bit, &uwsgi.cheaper_rss_limit_hard, UWSGI_OPT_MASTER | UWSGI_OPT_CHEAPER}, {"idle", required_argument, 0, "set idle mode (put uWSGI in cheap mode after inactivity)", uwsgi_opt_set_int, &uwsgi.idle, UWSGI_OPT_MASTER}, {"die-on-idle", no_argument, 0, "shutdown uWSGI when idle", uwsgi_opt_true, &uwsgi.die_on_idle, 0}, {"mount", required_argument, 0, "load application under mountpoint", uwsgi_opt_add_string_list, &uwsgi.mounts, 0}, {"worker-mount", required_argument, 0, "load application under mountpoint in the specified worker or after workers spawn", uwsgi_opt_add_string_list, &uwsgi.mounts, 0}, {"threads", required_argument, 0, "run each worker in prethreaded mode with the specified number of threads", uwsgi_opt_set_int, &uwsgi.threads, UWSGI_OPT_THREADS}, {"thread-stacksize", required_argument, 0, "set threads stacksize", uwsgi_opt_set_int, &uwsgi.threads_stacksize, UWSGI_OPT_THREADS}, {"threads-stacksize", required_argument, 0, "set threads stacksize", uwsgi_opt_set_int, &uwsgi.threads_stacksize, UWSGI_OPT_THREADS}, {"thread-stack-size", required_argument, 0, "set threads stacksize", uwsgi_opt_set_int, &uwsgi.threads_stacksize, UWSGI_OPT_THREADS}, {"threads-stack-size", required_argument, 0, "set threads stacksize", uwsgi_opt_set_int, &uwsgi.threads_stacksize, UWSGI_OPT_THREADS}, {"vhost", no_argument, 0, "enable virtualhosting mode (based on SERVER_NAME variable)", uwsgi_opt_true, &uwsgi.vhost, 0}, {"vhost-host", no_argument, 0, "enable virtualhosting mode (based on HTTP_HOST variable)", uwsgi_opt_true, &uwsgi.vhost_host, UWSGI_OPT_VHOST}, #ifdef UWSGI_ROUTING {"route", required_argument, 0, "add a route", uwsgi_opt_add_route, "path_info", 0}, {"route-host", required_argument, 0, "add a route based on Host header", uwsgi_opt_add_route, "http_host", 0}, {"route-uri", required_argument, 0, "add a route based on REQUEST_URI", uwsgi_opt_add_route, "request_uri", 0}, {"route-qs", required_argument, 0, "add a route based on QUERY_STRING", uwsgi_opt_add_route, "query_string", 0}, {"route-remote-addr", required_argument, 0, "add a route based on REMOTE_ADDR", uwsgi_opt_add_route, "remote_addr", 0}, {"route-user-agent", required_argument, 0, "add a route based on HTTP_USER_AGENT", uwsgi_opt_add_route, "user_agent", 0}, {"route-remote-user", required_argument, 0, "add a route based on REMOTE_USER", uwsgi_opt_add_route, "remote_user", 0}, {"route-referer", required_argument, 0, "add a route based on HTTP_REFERER", uwsgi_opt_add_route, "referer", 0}, {"route-label", required_argument, 0, "add a routing label (for use with goto)", uwsgi_opt_add_route, NULL, 0}, {"route-if", required_argument, 0, "add a route based on condition", uwsgi_opt_add_route, "if", 0}, {"route-if-not", required_argument, 0, "add a route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0}, {"route-run", required_argument, 0, "always run the specified route action", uwsgi_opt_add_route, "run", 0}, {"final-route", required_argument, 0, "add a final route", uwsgi_opt_add_route, "path_info", 0}, {"final-route-status", required_argument, 0, "add a final route for the specified status", uwsgi_opt_add_route, "status", 0}, {"final-route-host", required_argument, 0, "add a final route based on Host header", uwsgi_opt_add_route, "http_host", 0}, {"final-route-uri", required_argument, 0, "add a final route based on REQUEST_URI", uwsgi_opt_add_route, "request_uri", 0}, {"final-route-qs", required_argument, 0, "add a final route based on QUERY_STRING", uwsgi_opt_add_route, "query_string", 0}, {"final-route-remote-addr", required_argument, 0, "add a final route based on REMOTE_ADDR", uwsgi_opt_add_route, "remote_addr", 0}, {"final-route-user-agent", required_argument, 0, "add a final route based on HTTP_USER_AGENT", uwsgi_opt_add_route, "user_agent", 0}, {"final-route-remote-user", required_argument, 0, "add a final route based on REMOTE_USER", uwsgi_opt_add_route, "remote_user", 0}, {"final-route-referer", required_argument, 0, "add a final route based on HTTP_REFERER", uwsgi_opt_add_route, "referer", 0}, {"final-route-label", required_argument, 0, "add a final routing label (for use with goto)", uwsgi_opt_add_route, NULL, 0}, {"final-route-if", required_argument, 0, "add a final route based on condition", uwsgi_opt_add_route, "if", 0}, {"final-route-if-not", required_argument, 0, "add a final route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0}, {"final-route-run", required_argument, 0, "always run the specified final route action", uwsgi_opt_add_route, "run", 0}, {"error-route", required_argument, 0, "add an error route", uwsgi_opt_add_route, "path_info", 0}, {"error-route-status", required_argument, 0, "add an error route for the specified status", uwsgi_opt_add_route, "status", 0}, {"error-route-host", required_argument, 0, "add an error route based on Host header", uwsgi_opt_add_route, "http_host", 0}, {"error-route-uri", required_argument, 0, "add an error route based on REQUEST_URI", uwsgi_opt_add_route, "request_uri", 0}, {"error-route-qs", required_argument, 0, "add an error route based on QUERY_STRING", uwsgi_opt_add_route, "query_string", 0}, {"error-route-remote-addr", required_argument, 0, "add an error route based on REMOTE_ADDR", uwsgi_opt_add_route, "remote_addr", 0}, {"error-route-user-agent", required_argument, 0, "add an error route based on HTTP_USER_AGENT", uwsgi_opt_add_route, "user_agent", 0}, {"error-route-remote-user", required_argument, 0, "add an error route based on REMOTE_USER", uwsgi_opt_add_route, "remote_user", 0}, {"error-route-referer", required_argument, 0, "add an error route based on HTTP_REFERER", uwsgi_opt_add_route, "referer", 0}, {"error-route-label", required_argument, 0, "add an error routing label (for use with goto)", uwsgi_opt_add_route, NULL, 0}, {"error-route-if", required_argument, 0, "add an error route based on condition", uwsgi_opt_add_route, "if", 0}, {"error-route-if-not", required_argument, 0, "add an error route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0}, {"error-route-run", required_argument, 0, "always run the specified error route action", uwsgi_opt_add_route, "run", 0}, {"response-route", required_argument, 0, "add a response route", uwsgi_opt_add_route, "path_info", 0}, {"response-route-status", required_argument, 0, "add a response route for the specified status", uwsgi_opt_add_route, "status", 0}, {"response-route-host", required_argument, 0, "add a response route based on Host header", uwsgi_opt_add_route, "http_host", 0}, {"response-route-uri", required_argument, 0, "add a response route based on REQUEST_URI", uwsgi_opt_add_route, "request_uri", 0}, {"response-route-qs", required_argument, 0, "add a response route based on QUERY_STRING", uwsgi_opt_add_route, "query_string", 0}, {"response-route-remote-addr", required_argument, 0, "add a response route based on REMOTE_ADDR", uwsgi_opt_add_route, "remote_addr", 0}, {"response-route-user-agent", required_argument, 0, "add a response route based on HTTP_USER_AGENT", uwsgi_opt_add_route, "user_agent", 0}, {"response-route-remote-user", required_argument, 0, "add a response route based on REMOTE_USER", uwsgi_opt_add_route, "remote_user", 0}, {"response-route-referer", required_argument, 0, "add a response route based on HTTP_REFERER", uwsgi_opt_add_route, "referer", 0}, {"response-route-label", required_argument, 0, "add a response routing label (for use with goto)", uwsgi_opt_add_route, NULL, 0}, {"response-route-if", required_argument, 0, "add a response route based on condition", uwsgi_opt_add_route, "if", 0}, {"response-route-if-not", required_argument, 0, "add a response route based on condition (negate version)", uwsgi_opt_add_route, "if-not", 0}, {"response-route-run", required_argument, 0, "always run the specified response route action", uwsgi_opt_add_route, "run", 0}, {"router-list", no_argument, 0, "list enabled routers", uwsgi_opt_true, &uwsgi.router_list, 0}, {"routers-list", no_argument, 0, "list enabled routers", uwsgi_opt_true, &uwsgi.router_list, 0}, #endif {"error-page-403", required_argument, 0, "add an error page (html) for managed 403 response", uwsgi_opt_add_string_list, &uwsgi.error_page_403, 0}, {"error-page-404", required_argument, 0, "add an error page (html) for managed 404 response", uwsgi_opt_add_string_list, &uwsgi.error_page_404, 0}, {"error-page-500", required_argument, 0, "add an error page (html) for managed 500 response", uwsgi_opt_add_string_list, &uwsgi.error_page_500, 0}, {"websockets-ping-freq", required_argument, 0, "set the frequency (in seconds) of websockets automatic ping packets", uwsgi_opt_set_int, &uwsgi.websockets_ping_freq, 0}, {"websocket-ping-freq", required_argument, 0, "set the frequency (in seconds) of websockets automatic ping packets", uwsgi_opt_set_int, &uwsgi.websockets_ping_freq, 0}, {"websockets-pong-tolerance", required_argument, 0, "set the tolerance (in seconds) of websockets ping/pong subsystem", uwsgi_opt_set_int, &uwsgi.websockets_pong_tolerance, 0}, {"websocket-pong-tolerance", required_argument, 0, "set the tolerance (in seconds) of websockets ping/pong subsystem", uwsgi_opt_set_int, &uwsgi.websockets_pong_tolerance, 0}, {"websockets-max-size", required_argument, 0, "set the max allowed size of websocket messages (in Kbytes, default 1024)", uwsgi_opt_set_64bit, &uwsgi.websockets_max_size, 0}, {"websocket-max-size", required_argument, 0, "set the max allowed size of websocket messages (in Kbytes, default 1024)", uwsgi_opt_set_64bit, &uwsgi.websockets_max_size, 0}, {"chunked-input-limit", required_argument, 0, "set the max size of a chunked input part (default 1MB, in bytes)", uwsgi_opt_set_64bit, &uwsgi.chunked_input_limit, 0}, {"chunked-input-timeout", required_argument, 0, "set default timeout for chunked input", uwsgi_opt_set_int, &uwsgi.chunked_input_timeout, 0}, {"clock", required_argument, 0, "set a clock source", uwsgi_opt_set_str, &uwsgi.requested_clock, 0}, {"clock-list", no_argument, 0, "list enabled clocks", uwsgi_opt_true, &uwsgi.clock_list, 0}, {"clocks-list", no_argument, 0, "list enabled clocks", uwsgi_opt_true, &uwsgi.clock_list, 0}, {"add-header", required_argument, 0, "automatically add HTTP headers to response", uwsgi_opt_add_string_list, &uwsgi.additional_headers, 0}, {"rem-header", required_argument, 0, "automatically remove specified HTTP header from the response", uwsgi_opt_add_string_list, &uwsgi.remove_headers, 0}, {"del-header", required_argument, 0, "automatically remove specified HTTP header from the response", uwsgi_opt_add_string_list, &uwsgi.remove_headers, 0}, {"collect-header", required_argument, 0, "store the specified response header in a request var (syntax: header var)", uwsgi_opt_add_string_list, &uwsgi.collect_headers, 0}, {"response-header-collect", required_argument, 0, "store the specified response header in a request var (syntax: header var)", uwsgi_opt_add_string_list, &uwsgi.collect_headers, 0}, {"pull-header", required_argument, 0, "store the specified response header in a request var and remove it from the response (syntax: header var)", uwsgi_opt_add_string_list, &uwsgi.pull_headers, 0}, {"check-static", required_argument, 0, "check for static files in the specified directory", uwsgi_opt_check_static, NULL, UWSGI_OPT_MIME}, {"check-static-docroot", no_argument, 0, "check for static files in the requested DOCUMENT_ROOT", uwsgi_opt_true, &uwsgi.check_static_docroot, UWSGI_OPT_MIME}, {"static-check", required_argument, 0, "check for static files in the specified directory", uwsgi_opt_check_static, NULL, UWSGI_OPT_MIME}, {"static-map", required_argument, 0, "map mountpoint to static directory (or file)", uwsgi_opt_static_map, &uwsgi.static_maps, UWSGI_OPT_MIME}, {"static-map2", required_argument, 0, "like static-map but completely appending the requested resource to the docroot", uwsgi_opt_static_map, &uwsgi.static_maps2, UWSGI_OPT_MIME}, {"static-skip-ext", required_argument, 0, "skip specified extension from staticfile checks", uwsgi_opt_add_string_list, &uwsgi.static_skip_ext, UWSGI_OPT_MIME}, {"static-index", required_argument, 0, "search for specified file if a directory is requested", uwsgi_opt_add_string_list, &uwsgi.static_index, UWSGI_OPT_MIME}, {"static-safe", required_argument, 0, "skip security checks if the file is under the specified path", uwsgi_opt_add_string_list, &uwsgi.static_safe, UWSGI_OPT_MIME}, {"static-cache-paths", required_argument, 0, "put resolved paths in the uWSGI cache for the specified amount of seconds", uwsgi_opt_set_int, &uwsgi.use_static_cache_paths, UWSGI_OPT_MIME|UWSGI_OPT_MASTER}, {"static-cache-paths-name", required_argument, 0, "use the specified cache for static paths", uwsgi_opt_set_str, &uwsgi.static_cache_paths_name, UWSGI_OPT_MIME|UWSGI_OPT_MASTER}, #ifdef __APPLE__ {"mimefile", required_argument, 0, "set mime types file path (default /etc/apache2/mime.types)", uwsgi_opt_add_string_list, &uwsgi.mime_file, UWSGI_OPT_MIME}, {"mime-file", required_argument, 0, "set mime types file path (default /etc/apache2/mime.types)", uwsgi_opt_add_string_list, &uwsgi.mime_file, UWSGI_OPT_MIME}, #else {"mimefile", required_argument, 0, "set mime types file path (default /etc/mime.types)", uwsgi_opt_add_string_list, &uwsgi.mime_file, UWSGI_OPT_MIME}, {"mime-file", required_argument, 0, "set mime types file path (default /etc/mime.types)", uwsgi_opt_add_string_list, &uwsgi.mime_file, UWSGI_OPT_MIME}, #endif {"static-expires-type", required_argument, 0, "set the Expires header based on content type", uwsgi_opt_add_dyn_dict, &uwsgi.static_expires_type, UWSGI_OPT_MIME}, {"static-expires-type-mtime", required_argument, 0, "set the Expires header based on content type and file mtime", uwsgi_opt_add_dyn_dict, &uwsgi.static_expires_type_mtime, UWSGI_OPT_MIME}, #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) {"static-expires", required_argument, 0, "set the Expires header based on filename regexp", uwsgi_opt_add_regexp_dyn_dict, &uwsgi.static_expires, UWSGI_OPT_MIME}, {"static-expires-mtime", required_argument, 0, "set the Expires header based on filename regexp and file mtime", uwsgi_opt_add_regexp_dyn_dict, &uwsgi.static_expires_mtime, UWSGI_OPT_MIME}, {"static-expires-uri", required_argument, 0, "set the Expires header based on REQUEST_URI regexp", uwsgi_opt_add_regexp_dyn_dict, &uwsgi.static_expires_uri, UWSGI_OPT_MIME}, {"static-expires-uri-mtime", required_argument, 0, "set the Expires header based on REQUEST_URI regexp and file mtime", uwsgi_opt_add_regexp_dyn_dict, &uwsgi.static_expires_uri_mtime, UWSGI_OPT_MIME}, {"static-expires-path-info", required_argument, 0, "set the Expires header based on PATH_INFO regexp", uwsgi_opt_add_regexp_dyn_dict, &uwsgi.static_expires_path_info, UWSGI_OPT_MIME}, {"static-expires-path-info-mtime", required_argument, 0, "set the Expires header based on PATH_INFO regexp and file mtime", uwsgi_opt_add_regexp_dyn_dict, &uwsgi.static_expires_path_info_mtime, UWSGI_OPT_MIME}, {"static-gzip", required_argument, 0, "if the supplied regexp matches the static file translation it will search for a gzip version", uwsgi_opt_add_regexp_list, &uwsgi.static_gzip, UWSGI_OPT_MIME}, #endif {"static-gzip-all", no_argument, 0, "check for a gzip version of all requested static files", uwsgi_opt_true, &uwsgi.static_gzip_all, UWSGI_OPT_MIME}, {"static-gzip-dir", required_argument, 0, "check for a gzip version of all requested static files in the specified dir/prefix", uwsgi_opt_add_string_list, &uwsgi.static_gzip_dir, UWSGI_OPT_MIME}, {"static-gzip-prefix", required_argument, 0, "check for a gzip version of all requested static files in the specified dir/prefix", uwsgi_opt_add_string_list, &uwsgi.static_gzip_dir, UWSGI_OPT_MIME}, {"static-gzip-ext", required_argument, 0, "check for a gzip version of all requested static files with the specified ext/suffix", uwsgi_opt_add_string_list, &uwsgi.static_gzip_ext, UWSGI_OPT_MIME}, {"static-gzip-suffix", required_argument, 0, "check for a gzip version of all requested static files with the specified ext/suffix", uwsgi_opt_add_string_list, &uwsgi.static_gzip_ext, UWSGI_OPT_MIME}, {"honour-range", no_argument, 0, "enable support for the HTTP Range header", uwsgi_opt_true, &uwsgi.honour_range, 0}, {"offload-threads", required_argument, 0, "set the number of offload threads to spawn (per-worker, default 0)", uwsgi_opt_set_int, &uwsgi.offload_threads, 0}, {"offload-thread", required_argument, 0, "set the number of offload threads to spawn (per-worker, default 0)", uwsgi_opt_set_int, &uwsgi.offload_threads, 0}, {"file-serve-mode", required_argument, 0, "set static file serving mode", uwsgi_opt_fileserve_mode, NULL, UWSGI_OPT_MIME}, {"fileserve-mode", required_argument, 0, "set static file serving mode", uwsgi_opt_fileserve_mode, NULL, UWSGI_OPT_MIME}, {"disable-sendfile", no_argument, 0, "disable sendfile() and rely on boring read()/write()", uwsgi_opt_true, &uwsgi.disable_sendfile, 0}, {"check-cache", optional_argument, 0, "check for response data in the specified cache (empty for default cache)", uwsgi_opt_set_str, &uwsgi.use_check_cache, 0}, {"close-on-exec", no_argument, 0, "set close-on-exec on connection sockets (could be required for spawning processes in requests)", uwsgi_opt_true, &uwsgi.close_on_exec, 0}, {"close-on-exec2", no_argument, 0, "set close-on-exec on server sockets (could be required for spawning processes in requests)", uwsgi_opt_true, &uwsgi.close_on_exec2, 0}, {"mode", required_argument, 0, "set uWSGI custom mode", uwsgi_opt_set_str, &uwsgi.mode, 0}, {"env", required_argument, 0, "set environment variable", uwsgi_opt_set_env, NULL, 0}, {"envdir", required_argument, 0, "load a daemontools compatible envdir", uwsgi_opt_add_string_list, &uwsgi.envdirs, 0}, {"early-envdir", required_argument, 0, "load a daemontools compatible envdir ASAP", uwsgi_opt_envdir, NULL, UWSGI_OPT_IMMEDIATE}, {"unenv", required_argument, 0, "unset environment variable", uwsgi_opt_unset_env, NULL, 0}, {"vacuum", no_argument, 0, "try to remove all of the generated file/sockets", uwsgi_opt_true, &uwsgi.vacuum, 0}, {"file-write", required_argument, 0, "write the specified content to the specified file (syntax: file=value) before privileges drop", uwsgi_opt_add_string_list, &uwsgi.file_write_list, 0}, #ifdef __linux__ {"cgroup", required_argument, 0, "put the processes in the specified cgroup", uwsgi_opt_add_string_list, &uwsgi.cgroup, 0}, {"cgroup-opt", required_argument, 0, "set value in specified cgroup option", uwsgi_opt_add_string_list, &uwsgi.cgroup_opt, 0}, {"cgroup-dir-mode", required_argument, 0, "set permission for cgroup directory (default is 700)", uwsgi_opt_set_str, &uwsgi.cgroup_dir_mode, 0}, {"namespace", required_argument, 0, "run in a new namespace under the specified rootfs", uwsgi_opt_set_str, &uwsgi.ns, 0}, {"namespace-keep-mount", required_argument, 0, "keep the specified mountpoint in your namespace", uwsgi_opt_add_string_list, &uwsgi.ns_keep_mount, 0}, {"ns", required_argument, 0, "run in a new namespace under the specified rootfs", uwsgi_opt_set_str, &uwsgi.ns, 0}, {"namespace-net", required_argument, 0, "add network namespace", uwsgi_opt_set_str, &uwsgi.ns_net, 0}, {"ns-net", required_argument, 0, "add network namespace", uwsgi_opt_set_str, &uwsgi.ns_net, 0}, #endif {"enable-proxy-protocol", no_argument, 0, "enable PROXY1 protocol support (only for http parsers)", uwsgi_opt_true, &uwsgi.enable_proxy_protocol, 0}, {"reuse-port", no_argument, 0, "enable REUSE_PORT flag on socket (BSD only)", uwsgi_opt_true, &uwsgi.reuse_port, 0}, {"tcp-fast-open", required_argument, 0, "enable TCP_FASTOPEN flag on TCP sockets with the specified qlen value", uwsgi_opt_set_int, &uwsgi.tcp_fast_open, 0}, {"tcp-fastopen", required_argument, 0, "enable TCP_FASTOPEN flag on TCP sockets with the specified qlen value", uwsgi_opt_set_int, &uwsgi.tcp_fast_open, 0}, {"tcp-fast-open-client", no_argument, 0, "use sendto(..., MSG_FASTOPEN, ...) instead of connect() if supported", uwsgi_opt_true, &uwsgi.tcp_fast_open_client, 0}, {"tcp-fastopen-client", no_argument, 0, "use sendto(..., MSG_FASTOPEN, ...) instead of connect() if supported", uwsgi_opt_true, &uwsgi.tcp_fast_open_client, 0}, {"zerg", required_argument, 0, "attach to a zerg server", uwsgi_opt_add_string_list, &uwsgi.zerg_node, 0}, {"zerg-fallback", no_argument, 0, "fallback to normal sockets if the zerg server is not available", uwsgi_opt_true, &uwsgi.zerg_fallback, 0}, {"zerg-server", required_argument, 0, "enable the zerg server on the specified UNIX socket", uwsgi_opt_set_str, &uwsgi.zerg_server, UWSGI_OPT_MASTER}, {"cron", required_argument, 0, "add a cron task", uwsgi_opt_add_cron, NULL, UWSGI_OPT_MASTER}, {"cron2", required_argument, 0, "add a cron task (key=val syntax)", uwsgi_opt_add_cron2, NULL, UWSGI_OPT_MASTER}, {"unique-cron", required_argument, 0, "add a unique cron task", uwsgi_opt_add_unique_cron, NULL, UWSGI_OPT_MASTER}, {"cron-harakiri", required_argument, 0, "set the maximum time (in seconds) we wait for cron command to complete", uwsgi_opt_set_int, &uwsgi.cron_harakiri, 0}, #ifdef UWSGI_SSL {"legion-cron", required_argument, 0, "add a cron task runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_legion_cron, NULL, UWSGI_OPT_MASTER}, {"cron-legion", required_argument, 0, "add a cron task runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_legion_cron, NULL, UWSGI_OPT_MASTER}, {"unique-legion-cron", required_argument, 0, "add a unique cron task runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_unique_legion_cron, NULL, UWSGI_OPT_MASTER}, {"unique-cron-legion", required_argument, 0, "add a unique cron task runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_unique_legion_cron, NULL, UWSGI_OPT_MASTER}, #endif {"loop", required_argument, 0, "select the uWSGI loop engine", uwsgi_opt_set_str, &uwsgi.loop, 0}, {"loop-list", no_argument, 0, "list enabled loop engines", uwsgi_opt_true, &uwsgi.loop_list, 0}, {"loops-list", no_argument, 0, "list enabled loop engines", uwsgi_opt_true, &uwsgi.loop_list, 0}, {"worker-exec", required_argument, 0, "run the specified command as worker", uwsgi_opt_set_str, &uwsgi.worker_exec, 0}, {"worker-exec2", required_argument, 0, "run the specified command as worker (after post_fork hook)", uwsgi_opt_set_str, &uwsgi.worker_exec2, 0}, {"attach-daemon", required_argument, 0, "attach a command/daemon to the master process (the command has to not go in background)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER}, {"attach-control-daemon", required_argument, 0, "attach a command/daemon to the master process (the command has to not go in background), when the daemon dies, the master dies too", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER}, {"smart-attach-daemon", required_argument, 0, "attach a command/daemon to the master process managed by a pidfile (the command has to daemonize)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER}, {"smart-attach-daemon2", required_argument, 0, "attach a command/daemon to the master process managed by a pidfile (the command has to NOT daemonize)", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER}, #ifdef UWSGI_SSL {"legion-attach-daemon", required_argument, 0, "same as --attach-daemon but daemon runs only on legion lord node", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER}, {"legion-smart-attach-daemon", required_argument, 0, "same as --smart-attach-daemon but daemon runs only on legion lord node", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER}, {"legion-smart-attach-daemon2", required_argument, 0, "same as --smart-attach-daemon2 but daemon runs only on legion lord node", uwsgi_opt_add_daemon, NULL, UWSGI_OPT_MASTER}, #endif {"daemons-honour-stdin", no_argument, 0, "do not change the stdin of external daemons to /dev/null", uwsgi_opt_true, &uwsgi.daemons_honour_stdin, UWSGI_OPT_MASTER}, {"attach-daemon2", required_argument, 0, "attach-daemon keyval variant (supports smart modes too)", uwsgi_opt_add_daemon2, NULL, UWSGI_OPT_MASTER}, {"plugins", required_argument, 0, "load uWSGI plugins", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE}, {"plugin", required_argument, 0, "load uWSGI plugins", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE}, {"need-plugins", required_argument, 0, "load uWSGI plugins (exit on error)", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE}, {"need-plugin", required_argument, 0, "load uWSGI plugins (exit on error)", uwsgi_opt_load_plugin, NULL, UWSGI_OPT_IMMEDIATE}, {"plugins-dir", required_argument, 0, "add a directory to uWSGI plugin search path", uwsgi_opt_add_string_list, &uwsgi.plugins_dir, UWSGI_OPT_IMMEDIATE}, {"plugin-dir", required_argument, 0, "add a directory to uWSGI plugin search path", uwsgi_opt_add_string_list, &uwsgi.plugins_dir, UWSGI_OPT_IMMEDIATE}, {"plugins-list", no_argument, 0, "list enabled plugins", uwsgi_opt_true, &uwsgi.plugins_list, 0}, {"plugin-list", no_argument, 0, "list enabled plugins", uwsgi_opt_true, &uwsgi.plugins_list, 0}, {"autoload", no_argument, 0, "try to automatically load plugins when unknown options are found", uwsgi_opt_true, &uwsgi.autoload, UWSGI_OPT_IMMEDIATE}, {"dlopen", required_argument, 0, "blindly load a shared library", uwsgi_opt_load_dl, NULL, UWSGI_OPT_IMMEDIATE}, {"allowed-modifiers", required_argument, 0, "comma separated list of allowed modifiers", uwsgi_opt_set_str, &uwsgi.allowed_modifiers, 0}, {"remap-modifier", required_argument, 0, "remap request modifier from one id to another", uwsgi_opt_set_str, &uwsgi.remap_modifier, 0}, {"dump-options", no_argument, 0, "dump the full list of available options", uwsgi_opt_true, &uwsgi.dump_options, 0}, {"show-config", no_argument, 0, "show the current config reformatted as ini", uwsgi_opt_true, &uwsgi.show_config, 0}, {"binary-append-data", required_argument, 0, "return the content of a resource to stdout for appending to a uwsgi binary (for data:// usage)", uwsgi_opt_binary_append_data, NULL, UWSGI_OPT_IMMEDIATE}, {"print", required_argument, 0, "simple print", uwsgi_opt_print, NULL, 0}, {"iprint", required_argument, 0, "simple print (immediate version)", uwsgi_opt_print, NULL, UWSGI_OPT_IMMEDIATE}, {"exit", optional_argument, 0, "force exit() of the instance", uwsgi_opt_exit, NULL, UWSGI_OPT_IMMEDIATE}, {"cflags", no_argument, 0, "report uWSGI CFLAGS (useful for building external plugins)", uwsgi_opt_cflags, NULL, UWSGI_OPT_IMMEDIATE}, {"dot-h", no_argument, 0, "dump the uwsgi.h used for building the core (useful for building external plugins)", uwsgi_opt_dot_h, NULL, UWSGI_OPT_IMMEDIATE}, {"config-py", no_argument, 0, "dump the uwsgiconfig.py used for building the core (useful for building external plugins)", uwsgi_opt_config_py, NULL, UWSGI_OPT_IMMEDIATE}, {"build-plugin", required_argument, 0, "build a uWSGI plugin for the current binary", uwsgi_opt_build_plugin, NULL, UWSGI_OPT_IMMEDIATE}, {"version", no_argument, 0, "print uWSGI version", uwsgi_opt_print, UWSGI_VERSION, 0}, {"response-headers-limit", required_argument, 0, "set response header maximum size (default: 64k)", uwsgi_opt_set_int, &uwsgi.response_header_limit, 0}, {0, 0, 0, 0, 0, 0, 0} }; void show_config(void) { int i; uwsgi_log("\n;uWSGI instance configuration\n[uwsgi]\n"); for (i = 0; i < uwsgi.exported_opts_cnt; i++) { if (uwsgi.exported_opts[i]->value) { uwsgi_log("%s = %s\n", uwsgi.exported_opts[i]->key, uwsgi.exported_opts[i]->value); } else { uwsgi_log("%s = true\n", uwsgi.exported_opts[i]->key); } } uwsgi_log(";end of configuration\n\n"); } void config_magic_table_fill(char *filename, char **magic_table) { char *tmp = NULL; char *fullname = filename; magic_table['o'] = filename; if (uwsgi_check_scheme(filename) || !strcmp(filename, "-")) { return; } char *section = uwsgi_get_last_char(filename, ':'); if (section) { *section = 0; if (section == filename) { goto reuse; } } // we have a special case for symlinks if (uwsgi_is_link(filename)) { if (filename[0] != '/') { fullname = uwsgi_concat3(uwsgi.cwd, "/", filename); } } else { fullname = uwsgi_expand_path(filename, strlen(filename), NULL); if (!fullname) { exit(1); } char *minimal_name = uwsgi_malloc(strlen(fullname) + 1); memcpy(minimal_name, fullname, strlen(fullname)); minimal_name[strlen(fullname)] = 0; free(fullname); fullname = minimal_name; } magic_table['b'] = uwsgi.binary_path; magic_table['p'] = fullname; // compute filename hash uint32_t hash = djb33x_hash(magic_table['p'], strlen(magic_table['p'])); char *hex = uwsgi_str_to_hex((char *)&hash, 4); magic_table['j'] = uwsgi_concat2n(hex, 8, "", 0); free(hex); struct stat st; if (!lstat(fullname, &st)) { magic_table['i'] = uwsgi_num2str(st.st_ino); } magic_table['s'] = uwsgi_get_last_char(fullname, '/') + 1; magic_table['d'] = uwsgi_concat2n(magic_table['p'], magic_table['s'] - magic_table['p'], "", 0); if (magic_table['d'][strlen(magic_table['d']) - 1] == '/') { tmp = magic_table['d'] + (strlen(magic_table['d']) - 1); #ifdef UWSGI_DEBUG uwsgi_log("tmp = %c\n", *tmp); #endif *tmp = 0; } // clear optional vars magic_table['c'] = ""; magic_table['e'] = ""; magic_table['n'] = magic_table['s']; magic_table['0'] = ""; magic_table['1'] = ""; magic_table['2'] = ""; magic_table['3'] = ""; magic_table['4'] = ""; magic_table['5'] = ""; magic_table['6'] = ""; magic_table['7'] = ""; magic_table['8'] = ""; magic_table['9'] = ""; if (uwsgi_get_last_char(magic_table['d'], '/')) { magic_table['c'] = uwsgi_str(uwsgi_get_last_char(magic_table['d'], '/') + 1); if (magic_table['c'][strlen(magic_table['c']) - 1] == '/') { magic_table['c'][strlen(magic_table['c']) - 1] = 0; } } int base = '0'; char *to_split = uwsgi_str(magic_table['d']); char *p, *ctx = NULL; uwsgi_foreach_token(to_split, "/", p, ctx) { if (base <= '9') { magic_table[base] = p; base++; } else { break; } } if (tmp) *tmp = '/'; if (uwsgi_get_last_char(magic_table['s'], '.')) magic_table['e'] = uwsgi_get_last_char(magic_table['s'], '.') + 1; if (uwsgi_get_last_char(magic_table['s'], '.')) magic_table['n'] = uwsgi_concat2n(magic_table['s'], uwsgi_get_last_char(magic_table['s'], '.') - magic_table['s'], "", 0); reuse: magic_table['x'] = ""; if (section) { magic_table['x'] = section+1; *section = ':'; } // first round ? if (!uwsgi.magic_table_first_round) { magic_table['O'] = magic_table['o']; magic_table['D'] = magic_table['d']; magic_table['S'] = magic_table['s']; magic_table['P'] = magic_table['p']; magic_table['C'] = magic_table['c']; magic_table['E'] = magic_table['e']; magic_table['N'] = magic_table['n']; magic_table['X'] = magic_table['x']; magic_table['I'] = magic_table['i']; magic_table['J'] = magic_table['j']; uwsgi.magic_table_first_round = 1; } } int find_worker_id(pid_t pid) { int i; for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].pid == pid) return i; } return -1; } void warn_pipe() { struct wsgi_request *wsgi_req = current_wsgi_req(); if (uwsgi.threads < 2 && wsgi_req->uri_len > 0) { uwsgi_log_verbose("SIGPIPE: writing to a closed pipe/socket/fd (probably the client disconnected) on request %.*s (ip %.*s) !!!\n", wsgi_req->uri_len, wsgi_req->uri, wsgi_req->remote_addr_len, wsgi_req->remote_addr); } else { uwsgi_log_verbose("SIGPIPE: writing to a closed pipe/socket/fd (probably the client disconnected) !!!\n"); } } // This function is called from signal handler or main thread to wait worker threads. // `uwsgi.workers[uwsgi.mywid].manage_next_request` should be set to 0 to stop worker threads. static void wait_for_threads() { int i, ret; // This option was added because we used pthread_cancel(). // thread cancellation is REALLY flaky if (uwsgi.no_threads_wait) return; // wait for thread termination for (i = 0; i < uwsgi.threads; i++) { if (!pthread_equal(uwsgi.workers[uwsgi.mywid].cores[i].thread_id, pthread_self())) { ret = pthread_join(uwsgi.workers[uwsgi.mywid].cores[i].thread_id, NULL); if (ret) { uwsgi_log("pthread_join() = %d\n", ret); } else { // uwsgi_worker_is_busy() should not consider this thread as busy. uwsgi.workers[uwsgi.mywid].cores[i].in_request = 0; } } } } void gracefully_kill(int signum) { uwsgi_log("Gracefully killing worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid); uwsgi.workers[uwsgi.mywid].manage_next_request = 0; if (uwsgi.threads > 1) { // Stop event_queue_wait() in other threads. // We use loop_stop_pipe only in threaded workers to avoid // unintensional behavior changes in single threaded workers. int fd; if ((fd = uwsgi.loop_stop_pipe[1]) > 0) { close(fd); uwsgi.loop_stop_pipe[1] = 0; } return; } // still not found a way to gracefully reload in async mode if (uwsgi.async > 1) { if (uwsgi.workers[uwsgi.mywid].shutdown_sockets) uwsgi_shutdown_all_sockets(); exit(UWSGI_RELOAD_CODE); } if (!uwsgi.workers[uwsgi.mywid].cores[0].in_request) { if (uwsgi.workers[uwsgi.mywid].shutdown_sockets) uwsgi_shutdown_all_sockets(); exit(UWSGI_RELOAD_CODE); } } void end_me(int signum) { if (getpid() != masterpid && uwsgi.skip_atexit) { _exit(UWSGI_END_CODE); // never here } exit(UWSGI_END_CODE); } static void simple_goodbye_cruel_world() { int prev = uwsgi.workers[uwsgi.mywid].manage_next_request; uwsgi.workers[uwsgi.mywid].manage_next_request = 0; if (prev) { // Avoid showing same message from all threads. uwsgi_log("...The work of process %d is done. Seeya!\n", getpid()); } if (uwsgi.threads > 1) { // Stop event_queue_wait() in other threads. // We use loop_stop_pipe only in threaded workers to avoid // unintensional behavior changes in single threaded workers. int fd; if ((fd = uwsgi.loop_stop_pipe[1]) > 0) { close(fd); uwsgi.loop_stop_pipe[1] = 0; } } } void goodbye_cruel_world() { uwsgi_curse(uwsgi.mywid, 0); if (!uwsgi.gbcw_hook) { simple_goodbye_cruel_world(); } else { uwsgi.gbcw_hook(); } } // brutally destroy void kill_them_all(int signum) { if (uwsgi_instance_is_dying) return; uwsgi.status.brutally_destroying = 1; // unsubscribe if needed uwsgi_unsubscribe_all(); uwsgi_log("SIGINT/SIGTERM received...killing workers...\n"); int i; for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].pid > 0) { uwsgi_curse(i, SIGINT); } } for (i = 0; i < uwsgi.mules_cnt; i++) { if (uwsgi.mules[i].pid > 0) { uwsgi_curse_mule(i, SIGINT); } } uwsgi_destroy_processes(); } // gracefully destroy void gracefully_kill_them_all(int signum) { int waitpid_status; if (uwsgi_instance_is_dying) return; uwsgi.status.gracefully_destroying = 1; // unsubscribe if needed uwsgi_unsubscribe_all(); uwsgi_log_verbose("graceful shutdown triggered...\n"); int i; for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].pid > 0) { if (uwsgi.shutdown_sockets) uwsgi.workers[i].shutdown_sockets = 1; uwsgi_curse(i, SIGHUP); } } for (i = 0; i < uwsgi.mules_cnt; i++) { if (uwsgi.mules[i].pid > 0) { uwsgi_curse_mule(i, SIGHUP); } } for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].pid > 0) { waitpid(uwsgi.workers[i].pid, &waitpid_status, 0); } } uwsgi_destroy_processes(); } // graceful reload void grace_them_all(int signum) { if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying) return; int i; if (uwsgi.lazy) { for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].pid > 0) { uwsgi_curse(i, SIGHUP); } } return; } uwsgi.status.gracefully_reloading = 1; uwsgi_destroy_processes(); uwsgi_log("...gracefully killing workers...\n"); #ifdef UWSGI_SSL uwsgi_legion_announce_death(); #endif if (uwsgi.unsubscribe_on_graceful_reload) { uwsgi_unsubscribe_all(); } for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].pid > 0) { uwsgi_curse(i, SIGHUP); } } for (i = 0; i < uwsgi.mules_cnt; i++) { if (uwsgi.mules[i].pid > 0) { uwsgi_curse_mule(i, SIGHUP); } } } void uwsgi_nuclear_blast() { // the Emperor (as an example) cannot nuke itself if (uwsgi.disable_nuclear_blast) return; if (!uwsgi.workers) { reap_them_all(0); } else if (uwsgi.master_process) { if (getpid() == uwsgi.workers[0].pid) { reap_them_all(0); } } exit(1); } // brutally reload void reap_them_all(int signum) { // avoid reace condition in lazy mode if (uwsgi_instance_is_reloading) return; uwsgi.status.brutally_reloading = 1; if (!uwsgi.workers) return; uwsgi_destroy_processes(); uwsgi_log("...brutally killing workers...\n"); #ifdef UWSGI_SSL uwsgi_legion_announce_death(); #endif // unsubscribe if needed uwsgi_unsubscribe_all(); int i; for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].pid > 0) uwsgi_curse(i, SIGTERM); } for (i = 0; i < uwsgi.mules_cnt; i++) { if (uwsgi.mules[i].pid > 0) { uwsgi_curse_mule(i, SIGTERM); } } } void harakiri() { uwsgi_log("\nKilling the current process (pid: %d app_id: %d)...\n", uwsgi.mypid, uwsgi.wsgi_req->app_id); if (!uwsgi.master_process) { uwsgi_log("*** if you want your workers to be automatically respawned consider enabling the uWSGI master process ***\n"); } exit(0); } void stats(int signum) { //fix this for better logging(this cause races) struct uwsgi_app *ua = NULL; int i, j; if (uwsgi.mywid == 0) { show_config(); uwsgi_log("\tworkers total requests: %lu\n", uwsgi.workers[0].requests); uwsgi_log("-----------------\n"); for (j = 1; j <= uwsgi.numproc; j++) { for (i = 0; i < uwsgi.workers[j].apps_cnt; i++) { ua = &uwsgi.workers[j].apps[i]; if (ua) { uwsgi_log("\tworker %d app %d [%.*s] requests: %lu exceptions: %lu\n", j, i, ua->mountpoint_len, ua->mountpoint, ua->requests, ua->exceptions); } } uwsgi_log("-----------------\n"); } } else { uwsgi_log("worker %d total requests: %lu\n", uwsgi.mywid, uwsgi.workers[0].requests); for (i = 0; i < uwsgi.workers[uwsgi.mywid].apps_cnt; i++) { ua = &uwsgi.workers[uwsgi.mywid].apps[i]; if (ua) { uwsgi_log("\tapp %d [%.*s] requests: %lu exceptions: %lu\n", i, ua->mountpoint_len, ua->mountpoint, ua->requests, ua->exceptions); } } uwsgi_log("-----------------\n"); } uwsgi_log("\n"); } void what_i_am_doing() { struct wsgi_request *wsgi_req; int i; char ctime_storage[26]; uwsgi_backtrace(uwsgi.backtrace_depth); if (uwsgi.cores > 1) { for (i = 0; i < uwsgi.cores; i++) { wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[i].req; if (wsgi_req->uri_len > 0) { #if defined(__sun__) && !defined(__clang__) ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, ctime_storage, 26); #else ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, ctime_storage); #endif if (uwsgi.harakiri_options.workers > 0 && uwsgi.workers[uwsgi.mywid].harakiri < uwsgi_now()) { uwsgi_log("HARAKIRI: --- uWSGI worker %d core %d (pid: %d) WAS managing request %.*s since %.*s ---\n", (int) uwsgi.mywid, i, (int) uwsgi.mypid, wsgi_req->uri_len, wsgi_req->uri, 24, ctime_storage); } else { uwsgi_log("SIGUSR2: --- uWSGI worker %d core %d (pid: %d) is managing request %.*s since %.*s ---\n", (int) uwsgi.mywid, i, (int) uwsgi.mypid, wsgi_req->uri_len, wsgi_req->uri, 24, ctime_storage); } } } } else { wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[0].req; if (wsgi_req->uri_len > 0) { #if defined(__sun__) && !defined(__clang__) ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, ctime_storage, 26); #else ctime_r((const time_t *) &wsgi_req->start_of_request_in_sec, ctime_storage); #endif if (uwsgi.harakiri_options.workers > 0 && uwsgi.workers[uwsgi.mywid].harakiri < uwsgi_now()) { uwsgi_log("HARAKIRI: --- uWSGI worker %d (pid: %d) WAS managing request %.*s since %.*s ---\n", (int) uwsgi.mywid, (int) uwsgi.mypid, wsgi_req->uri_len, wsgi_req->uri, 24, ctime_storage); } else { uwsgi_log("SIGUSR2: --- uWSGI worker %d (pid: %d) is managing request %.*s since %.*s ---\n", (int) uwsgi.mywid, (int) uwsgi.mypid, wsgi_req->uri_len, wsgi_req->uri, 24, ctime_storage); } } else if (uwsgi.harakiri_options.workers > 0 && uwsgi.workers[uwsgi.mywid].harakiri < uwsgi_now() && uwsgi.workers[uwsgi.mywid].sig) { uwsgi_log("HARAKIRI: --- uWSGI worker %d (pid: %d) WAS handling signal %d ---\n", (int) uwsgi.mywid, (int) uwsgi.mypid, uwsgi.workers[uwsgi.mywid].signum); } } } int unconfigured_hook(struct wsgi_request *wsgi_req) { if (wsgi_req->uh->modifier1 == 0 && !uwsgi.no_default_app) { if (uwsgi_apps_cnt > 0 && uwsgi.default_app > -1) { struct uwsgi_app *ua = &uwsgi_apps[uwsgi.default_app]; if (uwsgi.p[ua->modifier1]->request != unconfigured_hook) { wsgi_req->uh->modifier1 = ua->modifier1; return uwsgi.p[ua->modifier1]->request(wsgi_req); } } } uwsgi_log("-- unavailable modifier requested: %d --\n", wsgi_req->uh->modifier1); return -1; } static void unconfigured_after_hook(struct wsgi_request *wsgi_req) { return; } struct uwsgi_plugin unconfigured_plugin = { .name = "unconfigured", .request = unconfigured_hook, .after_request = unconfigured_after_hook, }; void uwsgi_exec_atexit(void) { if (getpid() == masterpid) { uwsgi_hooks_run(uwsgi.hook_as_user_atexit, "atexit", 0); // now run exit scripts needed by the user struct uwsgi_string_list *usl; uwsgi_foreach(usl, uwsgi.exec_as_user_atexit) { uwsgi_log("running \"%s\" (as uid: %d gid: %d) ...\n", usl->value, (int) getuid(), (int) getgid()); int ret = uwsgi_run_command_and_wait(NULL, usl->value); if (ret != 0) { uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret); } } uwsgi_foreach(usl, uwsgi.call_as_user_atexit) { if (uwsgi_call_symbol(usl->value)) { uwsgi_log("unable to call function \"%s\"\n", usl->value); } } } } static void vacuum(void) { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; if (uwsgi.restore_tc) { if (getpid() == masterpid) { if (tcsetattr(0, TCSANOW, &uwsgi.termios)) { uwsgi_error("vacuum()/tcsetattr()"); } } } if (uwsgi.vacuum) { if (getpid() == masterpid) { if (chdir(uwsgi.cwd)) { uwsgi_error("chdir()"); } if (uwsgi.pidfile && !uwsgi.uid) { if (unlink(uwsgi.pidfile)) { uwsgi_error("unlink()"); } else { uwsgi_log("VACUUM: pidfile removed.\n"); } } if (uwsgi.pidfile2) { if (unlink(uwsgi.pidfile2)) { uwsgi_error("unlink()"); } else { uwsgi_log("VACUUM: pidfile2 removed.\n"); } } if (uwsgi.safe_pidfile && !uwsgi.uid) { if (unlink(uwsgi.safe_pidfile)) { uwsgi_error("unlink()"); } else { uwsgi_log("VACUUM: safe pidfile removed.\n"); } } if (uwsgi.safe_pidfile2) { if (unlink(uwsgi.safe_pidfile2)) { uwsgi_error("unlink()"); } else { uwsgi_log("VACUUM: safe pidfile2 removed.\n"); } } if (uwsgi.chdir) { if (chdir(uwsgi.chdir)) { uwsgi_error("chdir()"); } } while (uwsgi_sock) { if (uwsgi_sock->family == AF_UNIX && uwsgi_sock->name[0] != '@') { struct stat st; if (!stat(uwsgi_sock->name, &st)) { if (st.st_ino != uwsgi_sock->inode) { uwsgi_log("VACUUM WARNING: unix socket %s changed inode. Skip removal\n", uwsgi_sock->name); goto next; } } if (unlink(uwsgi_sock->name)) { uwsgi_error("unlink()"); } else { uwsgi_log("VACUUM: unix socket %s removed.\n", uwsgi_sock->name); } } next: uwsgi_sock = uwsgi_sock->next; } if (uwsgi.stats) { // is a unix socket ? if (!strchr(uwsgi.stats, ':') && uwsgi.stats[0] != '@') { if (unlink(uwsgi.stats)) { uwsgi_error("unlink()"); } else { uwsgi_log("VACUUM: unix socket %s (stats) removed.\n", uwsgi.stats); } } } } } } int signal_pidfile(int sig, char *filename) { int ret = 0; size_t size = 0; char *buffer = uwsgi_open_and_read(filename, &size, 1, NULL); if (size > 0) { if (kill((pid_t) atoi(buffer), sig)) { uwsgi_error("signal_pidfile()/kill()"); ret = -1; } } else { uwsgi_log("error: invalid pidfile\n"); ret = -1; } free(buffer); return ret; } /*static*/ void uwsgi_command_signal(char *opt) { int tmp_signal; char *colon = strchr(opt, ','); if (!colon) { uwsgi_log("invalid syntax for signal, must be addr,signal\n"); exit(1); } colon[0] = 0; tmp_signal = atoi(colon + 1); if (tmp_signal < 0 || tmp_signal > 255) { uwsgi_log("invalid signal number\n"); exit(3); } uint8_t uwsgi_signal = tmp_signal; int ret = uwsgi_remote_signal_send(opt, uwsgi_signal); if (ret < 0) { uwsgi_log("unable to deliver signal %d to node %s\n", uwsgi_signal, opt); exit(1); } if (ret == 0) { uwsgi_log("node %s rejected signal %d\n", opt, uwsgi_signal); exit(2); } uwsgi_log("signal %d delivered to node %s\n", uwsgi_signal, opt); exit(0); } static void fixup_argv_and_environ(int argc, char **argv, char **environ, char **envp) { uwsgi.orig_argv = argv; uwsgi.argv = argv; uwsgi.argc = argc; uwsgi.environ = UWSGI_ENVIRON; // avoid messing with fake environ if (envp && *environ != *envp) return; #if defined(__linux__) || defined(__sun__) int i; int env_count = 0; uwsgi.argv = uwsgi_malloc(sizeof(char *) * (argc + 1)); for (i = 0; i < argc; i++) { if (i == 0 || argv[0] + uwsgi.max_procname + 1 == argv[i]) { uwsgi.max_procname += strlen(argv[i]) + 1; } uwsgi.argv[i] = strdup(argv[i]); } // required by execve uwsgi.argv[i] = NULL; uwsgi.max_procname++; for (i = 0; environ[i] != NULL; i++) { // useless //if ((environ[0] + uwsgi.max_procname + 1) == environ[i]) { uwsgi.max_procname += strlen(environ[i]) + 1; //} env_count++; } uwsgi.environ = uwsgi_malloc(sizeof(char *) * (env_count+1)); for (i = 0; i < env_count; i++) { uwsgi.environ[i] = strdup(environ[i]); #ifdef UWSGI_DEBUG uwsgi_log("ENVIRON: %s\n", uwsgi.environ[i]); #endif environ[i] = uwsgi.environ[i]; } uwsgi.environ[env_count] = NULL; #ifdef UWSGI_DEBUG uwsgi_log("max space for custom process name = %d\n", uwsgi.max_procname); #endif //environ = uwsgi.environ; #endif } void uwsgi_plugins_atexit(void) { int j; if (!uwsgi.workers) return; // the master cannot run atexit handlers... if (uwsgi.master_process && uwsgi.workers[0].pid == getpid()) return; for (j = 0; j < uwsgi.gp_cnt; j++) { if (uwsgi.gp[j]->atexit) { uwsgi.gp[j]->atexit(); } } for (j = 0; j < 256; j++) { if (uwsgi.p[j]->atexit) { uwsgi.p[j]->atexit(); } } } void uwsgi_backtrace(int depth) { #if defined(__GLIBC__) || (defined(__APPLE__) && !defined(NO_EXECINFO)) || defined(UWSGI_HAS_EXECINFO) #include void **btrace = uwsgi_malloc(sizeof(void *) * depth); size_t bt_size, i; char **bt_strings; bt_size = backtrace(btrace, depth); bt_strings = backtrace_symbols(btrace, bt_size); struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); uwsgi_buffer_append(ub, "*** backtrace of ",17); uwsgi_buffer_num64(ub, (int64_t) getpid()); uwsgi_buffer_append(ub, " ***\n", 5); for (i = 0; i < bt_size; i++) { uwsgi_buffer_append(ub, bt_strings[i], strlen(bt_strings[i])); uwsgi_buffer_append(ub, "\n", 1); } free(btrace); uwsgi_buffer_append(ub, "*** end of backtrace ***\n", 25); uwsgi_log("%.*s", ub->pos, ub->buf); struct uwsgi_string_list *usl = uwsgi.alarm_segfault; while(usl) { uwsgi_alarm_trigger(usl->value, ub->buf, ub->pos); usl = usl->next; } uwsgi_buffer_destroy(ub); #endif } void uwsgi_segfault(int signum) { uwsgi_log("!!! uWSGI process %d got Segmentation Fault !!!\n", (int) getpid()); uwsgi_backtrace(uwsgi.backtrace_depth); if (uwsgi.use_abort) abort(); // restore default handler to generate core signal(signum, SIG_DFL); kill(getpid(), signum); // never here... exit(1); } void uwsgi_fpe(int signum) { uwsgi_log("!!! uWSGI process %d got Floating Point Exception !!!\n", (int) getpid()); uwsgi_backtrace(uwsgi.backtrace_depth); if (uwsgi.use_abort) abort(); // restore default handler to generate core signal(signum, SIG_DFL); kill(getpid(), signum); // never here... exit(1); } void uwsgi_flush_logs() { struct pollfd pfd; if (!uwsgi.master_process) return; if (!uwsgi.log_master) return; if (uwsgi.workers) { if (uwsgi.workers[0].pid == getpid()) { goto check; } } if (uwsgi.mywid == 0) goto check; return; check: // this buffer could not be initialized !!! if (uwsgi.log_master) { uwsgi.log_master_buf = uwsgi_malloc(uwsgi.log_master_bufsize); } // check for data in logpipe pfd.events = POLLIN; pfd.fd = uwsgi.shared->worker_log_pipe[0]; if (pfd.fd == -1) pfd.fd = 2; while (poll(&pfd, 1, 0) > 0) { if (uwsgi_master_log()) { break; } } } static void plugins_list(void) { int i; uwsgi_log("\n*** uWSGI loaded generic plugins ***\n"); for (i = 0; i < uwsgi.gp_cnt; i++) { uwsgi_log("%s\n", uwsgi.gp[i]->name); } uwsgi_log("\n*** uWSGI loaded request plugins ***\n"); for (i = 0; i < 256; i++) { if (uwsgi.p[i] == &unconfigured_plugin) continue; uwsgi_log("%d: %s\n", i, uwsgi.p[i]->name); } uwsgi_log("--- end of plugins list ---\n\n"); } static void loggers_list(void) { struct uwsgi_logger *ul = uwsgi.loggers; uwsgi_log("\n*** uWSGI loaded loggers ***\n"); while (ul) { uwsgi_log("%s\n", ul->name); ul = ul->next; } uwsgi_log("--- end of loggers list ---\n\n"); } static void cheaper_algo_list(void) { struct uwsgi_cheaper_algo *uca = uwsgi.cheaper_algos; uwsgi_log("\n*** uWSGI loaded cheaper algorithms ***\n"); while (uca) { uwsgi_log("%s\n", uca->name); uca = uca->next; } uwsgi_log("--- end of cheaper algorithms list ---\n\n"); } #ifdef UWSGI_ROUTING static void router_list(void) { struct uwsgi_router *ur = uwsgi.routers; uwsgi_log("\n*** uWSGI loaded routers ***\n"); while (ur) { uwsgi_log("%s\n", ur->name); ur = ur->next; } uwsgi_log("--- end of routers list ---\n\n"); } #endif static void loop_list(void) { struct uwsgi_loop *loop = uwsgi.loops; uwsgi_log("\n*** uWSGI loaded loop engines ***\n"); while (loop) { uwsgi_log("%s\n", loop->name); loop = loop->next; } uwsgi_log("--- end of loop engines list ---\n\n"); } static void imperial_monitor_list(void) { struct uwsgi_imperial_monitor *uim = uwsgi.emperor_monitors; uwsgi_log("\n*** uWSGI loaded imperial monitors ***\n"); while (uim) { uwsgi_log("%s\n", uim->scheme); uim = uim->next; } uwsgi_log("--- end of imperial monitors list ---\n\n"); } static void clocks_list(void) { struct uwsgi_clock *clocks = uwsgi.clocks; uwsgi_log("\n*** uWSGI loaded clocks ***\n"); while (clocks) { uwsgi_log("%s\n", clocks->name); clocks = clocks->next; } uwsgi_log("--- end of clocks list ---\n\n"); } static void alarms_list(void) { struct uwsgi_alarm *alarms = uwsgi.alarms; uwsgi_log("\n*** uWSGI loaded alarms ***\n"); while (alarms) { uwsgi_log("%s\n", alarms->name); alarms = alarms->next; } uwsgi_log("--- end of alarms list ---\n\n"); } static time_t uwsgi_unix_seconds() { return time(NULL); } static uint64_t uwsgi_unix_microseconds() { struct timeval tv; gettimeofday(&tv, NULL); return ((uint64_t) tv.tv_sec * 1000000) + tv.tv_usec; } static struct uwsgi_clock uwsgi_unix_clock = { .name = "unix", .seconds = uwsgi_unix_seconds, .microseconds = uwsgi_unix_microseconds, }; void uwsgi_init_random() { srand((unsigned int) (uwsgi.start_tv.tv_usec * uwsgi.start_tv.tv_sec)); } #ifdef UWSGI_AS_SHARED_LIBRARY int uwsgi_init(int argc, char *argv[], char *envp[]) { #else int main(int argc, char *argv[], char *envp[]) { #endif uwsgi_setup(argc, argv, envp); return uwsgi_run(); } static char *uwsgi_at_file_read(char *filename) { size_t size = 0; char *buffer = uwsgi_open_and_read(filename, &size, 1, NULL); if (size > 1) { if (buffer[size-2] == '\n' || buffer[size-2] == '\r') { buffer[size-2] = 0; } } return buffer; } void uwsgi_setup(int argc, char *argv[], char *envp[]) { int i; struct utsname uuts; // signal mask is inherited, and sme process manager could make a real mess... sigset_t smask; sigfillset(&smask); if (sigprocmask(SIG_UNBLOCK, &smask, NULL)) { uwsgi_error("sigprocmask()"); } signal(SIGCHLD, SIG_DFL); signal(SIGSEGV, uwsgi_segfault); signal(SIGFPE, uwsgi_fpe); signal(SIGHUP, SIG_IGN); signal(SIGTERM, SIG_IGN); signal(SIGPIPE, SIG_IGN); //initialize masterpid with a default value masterpid = getpid(); memset(&uwsgi, 0, sizeof(struct uwsgi_server)); uwsgi_proto_hooks_setup(); uwsgi.cwd = uwsgi_get_cwd(); init_magic_table(uwsgi.magic_table); // initialize schemes uwsgi_setup_schemes(); // initialize the clock uwsgi_register_clock(&uwsgi_unix_clock); uwsgi_set_clock("unix"); // fallback config atexit(uwsgi_fallback_config); // manage/flush logs atexit(uwsgi_flush_logs); // clear sockets, pidfiles... atexit(vacuum); // call user scripts atexit(uwsgi_exec_atexit); #ifdef UWSGI_SSL // call legions death hooks atexit(uwsgi_legion_atexit); #endif // allocate main shared memory uwsgi.shared = (struct uwsgi_shared *) uwsgi_calloc_shared(sizeof(struct uwsgi_shared)); // initialize request plugin to void for (i = 0; i < 256; i++) { uwsgi.p[i] = &unconfigured_plugin; } // set default values uwsgi_init_default(); // detect cpu cores #if defined(_SC_NPROCESSORS_ONLN) uwsgi.cpus = sysconf(_SC_NPROCESSORS_ONLN); #elif defined(_SC_NPROCESSORS_CONF) uwsgi.cpus = sysconf(_SC_NPROCESSORS_CONF); #endif // set default logit hook uwsgi.logit = uwsgi_logit_simple; #ifdef UWSGI_BLACKLIST if (!uwsgi_file_to_string_list(UWSGI_BLACKLIST, &uwsgi.blacklist)) { uwsgi_log("you cannot run this build of uWSGI without a blacklist file\n"); exit(1); } #endif #ifdef UWSGI_WHITELIST if (!uwsgi_file_to_string_list(UWSGI_WHITELIST, &uwsgi.whitelist)) { uwsgi_log("you cannot run this build of uWSGI without a whitelist file\n"); exit(1); } #endif // get startup time gettimeofday(&uwsgi.start_tv, NULL); // initialize random engine uwsgi_init_random(); setlinebuf(stdout); uwsgi.rl.rlim_cur = 0; uwsgi.rl.rlim_max = 0; // are we under systemd ? char *notify_socket = getenv("NOTIFY_SOCKET"); if (notify_socket) { uwsgi_systemd_init(notify_socket); } uwsgi_notify("initializing uWSGI"); // check if we are under the Emperor uwsgi_check_emperor(); char *screen_env = getenv("TERM"); if (screen_env) { if (!strcmp(screen_env, "screen")) { uwsgi.screen_session = getenv("STY"); } } // count/set the current reload status uwsgi_setup_reload(); #ifdef __CYGWIN__ SYSTEM_INFO si; GetSystemInfo(&si); uwsgi.page_size = si.dwPageSize; #else uwsgi.page_size = getpagesize(); #endif uwsgi.binary_path = uwsgi_get_binary_path(argv[0]); if(uwsgi.response_header_limit == 0) uwsgi.response_header_limit = UMAX16; // ok we can now safely play with argv and environ fixup_argv_and_environ(argc, argv, UWSGI_ENVIRON, envp); if (gethostname(uwsgi.hostname, 255)) { uwsgi_error("gethostname()"); } uwsgi.hostname_len = strlen(uwsgi.hostname); #ifdef UWSGI_ROUTING uwsgi_register_embedded_routers(); #endif // call here to allows plugin to override hooks uwsgi_register_base_hooks(); uwsgi_register_logchunks(); uwsgi_log_encoders_register_embedded(); // register base metrics (so plugins can override them) uwsgi_metrics_collectors_setup(); //initialize embedded plugins UWSGI_LOAD_EMBEDDED_PLUGINS // now a bit of magic, if the executable basename contains a 'uwsgi_' string, // try to automatically load a plugin #ifdef UWSGI_DEBUG uwsgi_log("executable name: %s\n", uwsgi.binary_path); #endif uwsgi_autoload_plugins_by_name(argv[0]); // build the options structure build_options(); // set a couple of 'static' magic vars uwsgi.magic_table['v'] = uwsgi.cwd; uwsgi.magic_table['h'] = uwsgi.hostname; uwsgi.magic_table['t'] = uwsgi_64bit2str(uwsgi_now()); uwsgi.magic_table['T'] = uwsgi_64bit2str(uwsgi_micros()); uwsgi.magic_table['V'] = UWSGI_VERSION; uwsgi.magic_table['k'] = uwsgi_num2str(uwsgi.cpus); uwsgi.magic_table['['] = "\033"; uwsgi.magic_table['u'] = uwsgi_num2str((int)getuid()); struct passwd *pw = getpwuid(getuid()); uwsgi.magic_table['U'] = pw ? pw->pw_name : uwsgi.magic_table['u']; uwsgi.magic_table['g'] = uwsgi_num2str((int)getgid()); struct group *gr = getgrgid(getgid()); uwsgi.magic_table['G'] = gr ? gr->gr_name : uwsgi.magic_table['g']; // you can embed a ini file in the uWSGi binary with default options #ifdef UWSGI_EMBED_CONFIG uwsgi_ini_config("", uwsgi.magic_table); // rebuild options if a custom ini is set build_options(); #endif //parse environ parse_sys_envs(UWSGI_ENVIRON); // parse commandline options uwsgi_commandline_config(); // second pass: ENVs uwsgi_apply_config_pass('$', (char *(*)(char *)) getenv); // third pass: FILEs uwsgi_apply_config_pass('@', uwsgi_at_file_read); // last pass: REFERENCEs uwsgi_apply_config_pass('%', uwsgi_manage_placeholder); // ok, the options dictionary is available, lets manage it uwsgi_configure(); // fixup cwd if (uwsgi.force_cwd) uwsgi.cwd = uwsgi.force_cwd; // run "asap" hooks uwsgi_hooks_run(uwsgi.hook_asap, "asap", 1); struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, uwsgi.mount_asap) { uwsgi_log("mounting \"%s\" (asap)...\n", usl->value); if (uwsgi_mount_hook(usl->value)) exit(1); } uwsgi_foreach(usl, uwsgi.umount_asap) { uwsgi_log("un-mounting \"%s\" (asap)...\n", usl->value); if (uwsgi_umount_hook(usl->value)) exit(1); } uwsgi_foreach(usl, uwsgi.exec_asap) { uwsgi_log("running \"%s\" (asap)...\n", usl->value); int ret = uwsgi_run_command_and_wait(NULL, usl->value); if (ret != 0) { uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret); exit(1); } } uwsgi_foreach(usl, uwsgi.call_asap) { if (uwsgi_call_symbol(usl->value)) { uwsgi_log("unable to call function \"%s\"\n", usl->value); exit(1); } } // manage envdirs ASAP uwsgi_envdirs(uwsgi.envdirs); // --get management struct uwsgi_string_list *get_list = uwsgi.get_list; while(get_list) { char *v = uwsgi_get_exported_opt(get_list->value); if (v) { fprintf(stdout, "%s\n", v); } get_list = get_list->next; } if (uwsgi.get_list) { exit(0); } // initial log setup (files and daemonization) uwsgi_setup_log(); #ifndef __CYGWIN__ // enable never-swap mode if (uwsgi.never_swap) { if (mlockall(MCL_CURRENT | MCL_FUTURE)) { uwsgi_error("mlockall()"); } } #endif if (uwsgi.flock2) uwsgi_opt_flock(NULL, uwsgi.flock2, NULL); if (uwsgi.flock_wait2) uwsgi_opt_flock(NULL, uwsgi.flock_wait2, NULL); // setup master logging if (uwsgi.log_master && !uwsgi.daemonize2) uwsgi_setup_log_master(); // setup offload engines uwsgi_offload_engines_register_all(); // setup main loops uwsgi_register_loop("simple", simple_loop); uwsgi_register_loop("async", async_loop); // setup cheaper algos uwsgi_register_cheaper_algo("spare", uwsgi_cheaper_algo_spare); uwsgi_register_cheaper_algo("backlog", uwsgi_cheaper_algo_backlog); uwsgi_register_cheaper_algo("manual", uwsgi_cheaper_algo_manual); // setup imperial monitors uwsgi_register_imperial_monitor("dir", uwsgi_imperial_monitor_directory_init, uwsgi_imperial_monitor_directory); uwsgi_register_imperial_monitor("glob", uwsgi_imperial_monitor_glob_init, uwsgi_imperial_monitor_glob); // setup stats pushers uwsgi_stats_pusher_setup(); // register embedded alarms uwsgi_register_embedded_alarms(); /* uWSGI IS CONFIGURED !!! */ if (uwsgi.dump_options) { struct option *lopt = uwsgi.long_options; while (lopt && lopt->name) { fprintf(stdout, "%s\n", lopt->name); lopt++; } exit(0); } if (uwsgi.show_config) show_config(); if (uwsgi.plugins_list) plugins_list(); if (uwsgi.loggers_list) loggers_list(); if (uwsgi.cheaper_algo_list) cheaper_algo_list(); #ifdef UWSGI_ROUTING if (uwsgi.router_list) router_list(); #endif if (uwsgi.loop_list) loop_list(); if (uwsgi.imperial_monitor_list) imperial_monitor_list(); if (uwsgi.clock_list) clocks_list(); if (uwsgi.alarms_list) alarms_list(); // set the clock if (uwsgi.requested_clock) uwsgi_set_clock(uwsgi.requested_clock); if (uwsgi.binary_path == uwsgi.argv[0]) { uwsgi.binary_path = uwsgi_str(uwsgi.argv[0]); } uwsgi_log_initial("*** Starting uWSGI %s (%dbit) on [%.*s] ***\n", UWSGI_VERSION, (int) (sizeof(void *)) * 8, 24, ctime((const time_t *) &uwsgi.start_tv.tv_sec)); #ifdef UWSGI_DEBUG uwsgi_log("***\n*** You are running a DEBUG version of uWSGI, please disable debug in your build profile and recompile it ***\n***\n"); #endif uwsgi_log_initial("compiled with version: %s on %s\n", __VERSION__, UWSGI_BUILD_DATE); #ifdef __sun__ if (uname(&uuts) < 0) { #else if (uname(&uuts)) { #endif uwsgi_error("uname()"); } else { uwsgi_log_initial("os: %s-%s %s\n", uuts.sysname, uuts.release, uuts.version); uwsgi_log_initial("nodename: %s\n", uuts.nodename); uwsgi_log_initial("machine: %s\n", uuts.machine); } uwsgi_log_initial("clock source: %s\n", uwsgi.clock->name); #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) if (uwsgi.pcre_jit) { uwsgi_log_initial("pcre jit enabled\n"); } else { uwsgi_log_initial("pcre jit disabled\n"); } #endif #ifdef __BIG_ENDIAN__ uwsgi_log_initial("*** big endian arch detected ***\n"); #endif uwsgi_log_initial("detected number of CPU cores: %d\n", uwsgi.cpus); uwsgi_log_initial("current working directory: %s\n", uwsgi.cwd); if (uwsgi.screen_session) { uwsgi_log("*** running under screen session %s ***\n", uwsgi.screen_session); } if (uwsgi.pidfile && !uwsgi.is_a_reload) { uwsgi_write_pidfile(uwsgi.pidfile); } uwsgi_log_initial("detected binary path: %s\n", uwsgi.binary_path); if (uwsgi.is_a_reload) { struct rlimit rl; if (!getrlimit(RLIMIT_NOFILE, &rl)) { uwsgi.max_fd = rl.rlim_cur; } } #ifdef UWSGI_ROUTING uwsgi_routing_dump(); #else uwsgi_log("!!! no internal routing support, rebuild with pcre support !!!\n"); #endif // initialize shared sockets uwsgi_setup_shared_sockets(); #ifdef __linux__ if (uwsgi.setns_preopen) { uwsgi_setns_preopen(); } // eventually join a linux namespace if (uwsgi.setns) { uwsgi_setns(uwsgi.setns); } #endif // start the Emperor if needed if (uwsgi.early_emperor && uwsgi.emperor) { uwsgi_emperor_start(); } if (!uwsgi.reloads) { uwsgi_hooks_run(uwsgi.hook_pre_jail, "pre-jail", 1); struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, uwsgi.mount_pre_jail) { uwsgi_log("mounting \"%s\" (pre-jail)...\n", usl->value); if (uwsgi_mount_hook(usl->value)) { exit(1); } } uwsgi_foreach(usl, uwsgi.umount_pre_jail) { uwsgi_log("un-mounting \"%s\" (pre-jail)...\n", usl->value); if (uwsgi_umount_hook(usl->value)) { exit(1); } } // run the pre-jail scripts uwsgi_foreach(usl, uwsgi.exec_pre_jail) { uwsgi_log("running \"%s\" (pre-jail)...\n", usl->value); int ret = uwsgi_run_command_and_wait(NULL, usl->value); if (ret != 0) { uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret); exit(1); } } uwsgi_foreach(usl, uwsgi.call_pre_jail) { if (uwsgi_call_symbol(usl->value)) { uwsgi_log("unable to call function \"%s\"\n", usl->value); exit(1); } } } // we could now patch the binary if (uwsgi.privileged_binary_patch) { uwsgi.argv[0] = uwsgi.privileged_binary_patch; execvp(uwsgi.privileged_binary_patch, uwsgi.argv); uwsgi_error("execvp()"); exit(1); } if (uwsgi.privileged_binary_patch_arg) { uwsgi_exec_command_with_args(uwsgi.privileged_binary_patch_arg); } // call jail systems for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->jail) { uwsgi.gp[i]->jail(uwsgi_start, uwsgi.argv); } } // TODO pluginize basic Linux namespace support #if defined(__linux__) && !defined(__ia64__) if (uwsgi.ns) { linux_namespace_start((void *) uwsgi.argv); // never here } else { #endif uwsgi_start((void *) uwsgi.argv); #if defined(__linux__) && !defined(__ia64__) } #endif if (uwsgi.safe_pidfile && !uwsgi.is_a_reload) { uwsgi_write_pidfile_explicit(uwsgi.safe_pidfile, masterpid); } } int uwsgi_start(void *v_argv) { int i, j; #ifdef __linux__ uwsgi_set_cgroup(); #if !defined(__ia64__) if (uwsgi.ns) { linux_namespace_jail(); } #endif #endif uwsgi_hooks_run(uwsgi.hook_in_jail, "in-jail", 1); struct uwsgi_string_list *usl; uwsgi_foreach(usl, uwsgi.mount_in_jail) { uwsgi_log("mounting \"%s\" (in-jail)...\n", usl->value); if (uwsgi_mount_hook(usl->value)) { exit(1); } } uwsgi_foreach(usl, uwsgi.umount_in_jail) { uwsgi_log("un-mounting \"%s\" (in-jail)...\n", usl->value); if (uwsgi_umount_hook(usl->value)) { exit(1); } } uwsgi_foreach(usl, uwsgi.exec_in_jail) { uwsgi_log("running \"%s\" (in-jail)...\n", usl->value); int ret = uwsgi_run_command_and_wait(NULL, usl->value); if (ret != 0) { uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret); exit(1); } } uwsgi_foreach(usl, uwsgi.call_in_jail) { if (uwsgi_call_symbol(usl->value)) { uwsgi_log("unable to call function \"%s\"\n", usl->value); exit(1); } } uwsgi_file_write_do(uwsgi.file_write_list); if (!uwsgi.master_as_root && !uwsgi.chown_socket && !uwsgi.drop_after_init && !uwsgi.drop_after_apps) { uwsgi_as_root(); } // wait for socket uwsgi_foreach(usl, uwsgi.wait_for_socket) { if (uwsgi_wait_for_socket(usl->value)) exit(1); } if (uwsgi.logto2) { if (!uwsgi.is_a_reload || uwsgi.log_reopen) { logto(uwsgi.logto2); } } if (uwsgi.chdir) { uwsgi_log("chdir() to %s\n", uwsgi.chdir); if (chdir(uwsgi.chdir)) { uwsgi_error("chdir()"); exit(1); } } if (uwsgi.pidfile2 && !uwsgi.is_a_reload) { uwsgi_write_pidfile(uwsgi.pidfile2); } if (!uwsgi.master_process && !uwsgi.command_mode) { uwsgi_log_initial("*** WARNING: you are running uWSGI without its master process manager ***\n"); } #ifdef RLIMIT_NPROC if (uwsgi.rl_nproc.rlim_max > 0) { uwsgi.rl_nproc.rlim_cur = uwsgi.rl_nproc.rlim_max; uwsgi_log_initial("limiting number of processes to %d...\n", (int) uwsgi.rl_nproc.rlim_max); if (setrlimit(RLIMIT_NPROC, &uwsgi.rl_nproc)) { uwsgi_error("setrlimit()"); } } if (!getrlimit(RLIMIT_NPROC, &uwsgi.rl_nproc)) { if (uwsgi.rl_nproc.rlim_cur != RLIM_INFINITY) { uwsgi_log_initial("your processes number limit is %d\n", (int) uwsgi.rl_nproc.rlim_cur); if ((int) uwsgi.rl_nproc.rlim_cur < uwsgi.numproc + uwsgi.master_process) { uwsgi.numproc = uwsgi.rl_nproc.rlim_cur - 1; uwsgi_log_initial("!!! number of workers adjusted to %d due to system limits !!!\n", uwsgi.numproc); } } } #endif #ifndef __OpenBSD__ if (uwsgi.rl.rlim_max > 0) { uwsgi.rl.rlim_cur = uwsgi.rl.rlim_max; uwsgi_log_initial("limiting address space of processes...\n"); if (setrlimit(RLIMIT_AS, &uwsgi.rl)) { uwsgi_error("setrlimit()"); } } if (uwsgi.prio != 0) { #ifdef __HAIKU__ if (set_thread_priority(find_thread(NULL), uwsgi.prio) == B_BAD_THREAD_ID) { uwsgi_error("set_thread_priority()"); #else if (setpriority(PRIO_PROCESS, 0, uwsgi.prio)) { uwsgi_error("setpriority()"); #endif } else { uwsgi_log_initial("scheduler priority set to %d\n", uwsgi.prio); } } if (!getrlimit(RLIMIT_AS, &uwsgi.rl)) { //check for overflow if (uwsgi.rl.rlim_max != (rlim_t) RLIM_INFINITY) { uwsgi_log_initial("your process address space limit is %lld bytes (%lld MB)\n", (long long) uwsgi.rl.rlim_max, (long long) uwsgi.rl.rlim_max / 1024 / 1024); } } #endif uwsgi_log_initial("your memory page size is %d bytes\n", uwsgi.page_size); // automatically fix options sanitize_args(); if (uwsgi.requested_max_fd) { uwsgi.rl.rlim_cur = uwsgi.requested_max_fd; uwsgi.rl.rlim_max = uwsgi.requested_max_fd; if (setrlimit(RLIMIT_NOFILE, &uwsgi.rl)) { uwsgi_error("setrlimit()"); } } if (!getrlimit(RLIMIT_NOFILE, &uwsgi.rl)) { uwsgi.max_fd = uwsgi.rl.rlim_cur; uwsgi_log_initial("detected max file descriptor number: %lu\n", (unsigned long) uwsgi.max_fd); } // start the Emperor if needed if (!uwsgi.early_emperor && uwsgi.emperor) { uwsgi_emperor_start(); } // end of generic initialization // build mime.types dictionary if (uwsgi.build_mime_dict) { if (!uwsgi.mime_file) #ifdef __APPLE__ uwsgi_string_new_list(&uwsgi.mime_file, "/etc/apache2/mime.types"); #else uwsgi_string_new_list(&uwsgi.mime_file, "/etc/mime.types"); #endif struct uwsgi_string_list *umd = uwsgi.mime_file; while (umd) { if (!access(umd->value, R_OK)) { uwsgi_build_mime_dict(umd->value); } else { uwsgi_log("!!! no %s file found !!!\n", umd->value); } umd = umd->next; } } if (uwsgi.async > 1) { if ((unsigned long) uwsgi.max_fd < (unsigned long) uwsgi.async) { uwsgi_log_initial("- your current max open files limit is %lu, this is lower than requested async cores !!! -\n", (unsigned long) uwsgi.max_fd); uwsgi.rl.rlim_cur = uwsgi.async; uwsgi.rl.rlim_max = uwsgi.async; if (!setrlimit(RLIMIT_NOFILE, &uwsgi.rl)) { uwsgi_log("max open files limit raised to %lu\n", (unsigned long) uwsgi.rl.rlim_cur); uwsgi.async = uwsgi.rl.rlim_cur; uwsgi.max_fd = uwsgi.rl.rlim_cur; } else { uwsgi.async = (int) uwsgi.max_fd; } } uwsgi_log_initial("- async cores set to %d - fd table size: %d\n", uwsgi.async, (int) uwsgi.max_fd); } #ifdef UWSGI_DEBUG uwsgi_log("cores allocated...\n"); #endif if (uwsgi.vhost) { uwsgi_log_initial("VirtualHosting mode enabled.\n"); } // setup locking uwsgi_setup_locking(); if (uwsgi.use_thunder_lock) { uwsgi_log_initial("thunder lock: enabled\n"); } else { uwsgi_log_initial("thunder lock: disabled (you can enable it with --thunder-lock)\n"); } // allocate rpc structures uwsgi_rpc_init(); // initialize sharedareas uwsgi_sharedareas_init(); uwsgi.snmp_lock = uwsgi_lock_init("snmp"); // setup queue if (uwsgi.queue_size > 0) { uwsgi_init_queue(); } uwsgi_cache_create_all(); if (uwsgi.use_check_cache) { uwsgi.check_cache = uwsgi_cache_by_name(uwsgi.use_check_cache); if (!uwsgi.check_cache) { uwsgi_log("unable to find cache \"%s\"\n", uwsgi.use_check_cache); exit(1); } } if (uwsgi.use_static_cache_paths) { if (uwsgi.static_cache_paths_name) { uwsgi.static_cache_paths = uwsgi_cache_by_name(uwsgi.static_cache_paths_name); if (!uwsgi.static_cache_paths) { uwsgi_log("unable to find cache \"%s\"\n", uwsgi.static_cache_paths_name); exit(1); } } else { if (!uwsgi.caches) { uwsgi_log("caching of static paths requires uWSGI caching !!!\n"); exit(1); } uwsgi.static_cache_paths = uwsgi.caches; } } // initialize the alarm subsystem uwsgi_alarms_init(); // initialize the exception handlers uwsgi_exception_setup_handlers(); // initialize socket protocols (do it after caching !!!) uwsgi_protocols_register(); /* plugin initialization */ for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->init) { uwsgi.gp[i]->init(); } } if (!uwsgi.no_server) { // systemd/upstart/zerg socket activation if (!uwsgi.is_a_reload) { uwsgi_setup_systemd(); uwsgi_setup_upstart(); uwsgi_setup_zerg(); uwsgi_setup_emperor(); } //check for inherited sockets if (uwsgi.is_a_reload) { uwsgi_setup_inherited_sockets(); } //now bind all the unbound sockets uwsgi_bind_sockets(); if (!uwsgi.master_as_root && !uwsgi.drop_after_init && !uwsgi.drop_after_apps) { uwsgi_as_root(); } // put listening socket in non-blocking state and set the protocol uwsgi_set_sockets_protocols(); } // initialize request plugin only if workers or master are available if (uwsgi.sockets || uwsgi.master_process || uwsgi.no_server || uwsgi.command_mode || uwsgi.loop) { for (i = 0; i < 256; i++) { if (uwsgi.p[i]->init) { uwsgi.p[i]->init(); } } } if (!uwsgi.master_as_root && !uwsgi.drop_after_apps) { uwsgi_as_root(); } /* gp/plugin initialization */ for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->post_init) { uwsgi.gp[i]->post_init(); } } // again check for workers/sockets... if (uwsgi.sockets || uwsgi.master_process || uwsgi.no_server || uwsgi.command_mode || uwsgi.loop) { for (i = 0; i < 256; i++) { if (uwsgi.p[i]->post_init) { uwsgi.p[i]->post_init(); } } } uwsgi.current_wsgi_req = simple_current_wsgi_req; if (uwsgi.has_threads) { if (uwsgi.threads > 1) uwsgi.current_wsgi_req = threaded_current_wsgi_req; (void) pthread_attr_init(&uwsgi.threads_attr); if (uwsgi.threads_stacksize) { if (pthread_attr_setstacksize(&uwsgi.threads_attr, uwsgi.threads_stacksize * 1024) == 0) { uwsgi_log("threads stack size set to %luk\n", (unsigned long) uwsgi.threads_stacksize); } else { uwsgi_log("!!! unable to set requested threads stacksize !!!\n"); } } pthread_mutex_init(&uwsgi.lock_static, NULL); // again check for workers/sockets... if (uwsgi.sockets || uwsgi.master_process || uwsgi.no_server || uwsgi.command_mode || uwsgi.loop) { for (i = 0; i < 256; i++) { if (uwsgi.p[i]->enable_threads) uwsgi.p[i]->enable_threads(); } } } // users of the --loop option should know what they are doing... really... #ifndef UWSGI_DEBUG if (uwsgi.loop) goto unsafe; #endif if (!uwsgi.sockets && !ushared->gateways_cnt && !uwsgi.no_server && !uwsgi.udp_socket && !uwsgi.emperor && !uwsgi.command_mode && !uwsgi.daemons_cnt && !uwsgi.crons && !uwsgi.spoolers && !uwsgi.emperor_proxy #ifdef __linux__ && !uwsgi.setns_socket #endif #ifdef UWSGI_SSL && !uwsgi.legions #endif ) { uwsgi_log("The -s/--socket option is missing and stdin is not a socket.\n"); exit(1); } else if (!uwsgi.sockets && ushared->gateways_cnt && !uwsgi.no_server && !uwsgi.master_process) { // here we will have a zombie... sorry uwsgi_log("...you should enable the master process... really...\n"); if (uwsgi.force_gateway) { struct uwsgi_gateway *ug = &ushared->gateways[0]; ug->loop(0, ug->data); // when we are here the gateway is dead :( } exit(0); } if (!uwsgi.sockets) uwsgi.numproc = 0; if (uwsgi.command_mode) { uwsgi.sockets = NULL; uwsgi.numproc = 1; // hack to destroy the instance after command exit uwsgi.status.brutally_destroying = 1; } #ifndef UWSGI_DEBUG unsafe: #endif #ifdef UWSGI_DEBUG struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; int so_bufsize; socklen_t so_bufsize_len; while (uwsgi_sock) { so_bufsize_len = sizeof(int); if (getsockopt(uwsgi_sock->fd, SOL_SOCKET, SO_RCVBUF, &so_bufsize, &so_bufsize_len)) { uwsgi_error("getsockopt()"); } else { uwsgi_debug("uwsgi socket %d SO_RCVBUF size: %d\n", i, so_bufsize); } so_bufsize_len = sizeof(int); if (getsockopt(uwsgi_sock->fd, SOL_SOCKET, SO_SNDBUF, &so_bufsize, &so_bufsize_len)) { uwsgi_error("getsockopt()"); } else { uwsgi_debug("uwsgi socket %d SO_SNDBUF size: %d\n", i, so_bufsize); } uwsgi_sock = uwsgi_sock->next; } #endif #ifndef UNBIT if (uwsgi.sockets) uwsgi_log("your server socket listen backlog is limited to %d connections\n", uwsgi.listen_queue); #endif uwsgi_log("your mercy for graceful operations on workers is %d seconds\n", uwsgi.worker_reload_mercy); if (uwsgi.crons) { struct uwsgi_cron *ucron = uwsgi.crons; while (ucron) { #ifdef UWSGI_SSL if (ucron->legion) { uwsgi_log("[uwsgi-cron] command \"%s\" registered as cron task for legion \"%s\"\n", ucron->command, ucron->legion); ucron = ucron->next; continue; } #endif uwsgi_log("[uwsgi-cron] command \"%s\" registered as cron task\n", ucron->command); ucron = ucron->next; } } // initialize post buffering values if (uwsgi.post_buffering > 0) uwsgi_setup_post_buffering(); // initialize workers/master shared memory segments uwsgi_setup_workers(); // create signal pipes if master is enabled if (uwsgi.master_process) { for (i = 1; i <= uwsgi.numproc; i++) { create_signal_pipe(uwsgi.workers[i].signal_pipe); } } // set masterpid uwsgi.mypid = getpid(); masterpid = uwsgi.mypid; uwsgi.workers[0].pid = masterpid; // initialize mules and farms uwsgi_setup_mules_and_farms(); if (uwsgi.command_mode) { uwsgi_log("*** Operational MODE: command ***\n"); } else if (!uwsgi.numproc) { uwsgi_log("*** Operational MODE: no-workers ***\n"); } else if (uwsgi.threads > 1) { if (uwsgi.numproc > 1) { uwsgi_log("*** Operational MODE: preforking+threaded ***\n"); } else { uwsgi_log("*** Operational MODE: threaded ***\n"); } } else if (uwsgi.async > 1) { if (uwsgi.numproc > 1) { uwsgi_log("*** Operational MODE: preforking+async ***\n"); } else { uwsgi_log("*** Operational MODE: async ***\n"); } } else if (uwsgi.numproc > 1) { uwsgi_log("*** Operational MODE: preforking ***\n"); } else { uwsgi_log("*** Operational MODE: single process ***\n"); } // set a default request structure (for loading apps...) uwsgi.wsgi_req = &uwsgi.workers[0].cores[0].req; // ok, let's initialize the metrics subsystem uwsgi_setup_metrics(); // cores are allocated, lets allocate logformat (if required) if (uwsgi.logformat) { uwsgi_build_log_format(uwsgi.logformat); uwsgi.logit = uwsgi_logit_lf; // TODO check it //if (uwsgi.logformat_strftime) { //uwsgi.logit = uwsgi_logit_lf_strftime; //} uwsgi.logvectors = uwsgi_malloc(sizeof(struct iovec *) * uwsgi.cores); for (j = 0; j < uwsgi.cores; j++) { uwsgi.logvectors[j] = uwsgi_malloc(sizeof(struct iovec) * uwsgi.logformat_vectors); uwsgi.logvectors[j][uwsgi.logformat_vectors - 1].iov_base = "\n"; uwsgi.logvectors[j][uwsgi.logformat_vectors - 1].iov_len = 1; } } // initialize locks and socket as soon as possible, as the master could enqueue tasks if (uwsgi.spoolers != NULL) { create_signal_pipe(uwsgi.shared->spooler_signal_pipe); struct uwsgi_spooler *uspool = uwsgi.spoolers; while (uspool) { // lock is required even in EXTERNAL mode uspool->lock = uwsgi_lock_init(uwsgi_concat2("spooler on ", uspool->dir)); if (uspool->mode == UWSGI_SPOOLER_EXTERNAL) goto next; create_signal_pipe(uspool->signal_pipe); next: uspool = uspool->next; } } // preinit apps (create the language environment) for (i = 0; i < 256; i++) { if (uwsgi.p[i]->preinit_apps) { uwsgi.p[i]->preinit_apps(); } } for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->preinit_apps) { uwsgi.gp[i]->preinit_apps(); } } //init apps hook (if not lazy) if (!uwsgi.lazy && !uwsgi.lazy_apps) { uwsgi_init_all_apps(); } // Register uwsgi atexit plugin callbacks after all applications have // been loaded. This ensures plugin atexit callbacks are called prior // to application registered atexit callbacks. atexit(uwsgi_plugins_atexit); if (!uwsgi.master_as_root) { uwsgi_as_root(); } // postinit apps (setup specific features after app initialization) for (i = 0; i < 256; i++) { if (uwsgi.p[i]->postinit_apps) { uwsgi.p[i]->postinit_apps(); } } for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->postinit_apps) { uwsgi.gp[i]->postinit_apps(); } } // initialize after_request hooks uwsgi_foreach(usl, uwsgi.after_request_hooks) { usl->custom_ptr = dlsym(RTLD_DEFAULT, usl->value); if (!usl->custom_ptr) { uwsgi_log("unable to find symbol/function \"%s\"\n", usl->value); exit(1); } uwsgi_log("added \"%s(struct wsgi_request *)\" to the after-request chain\n", usl->value); } if (uwsgi.daemonize2) { masterpid = uwsgi_daemonize2(); } if (uwsgi.no_server) { uwsgi_log("no-server mode requested. Goodbye.\n"); exit(0); } if (!uwsgi.master_process && uwsgi.numproc == 0) { exit(0); } if (!uwsgi.single_interpreter && uwsgi.numproc > 0) { uwsgi_log("*** uWSGI is running in multiple interpreter mode ***\n"); } // check for request plugins, and eventually print a warning int rp_available = 0; for (i = 0; i < 256; i++) { if (uwsgi.p[i] != &unconfigured_plugin) { rp_available = 1; break; } } if (!rp_available && !ushared->gateways_cnt) { uwsgi_log("!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!\n"); uwsgi_log("no request plugin is loaded, you will not be able to manage requests.\n"); uwsgi_log("you may need to install the package for your language of choice, or simply load it with --plugin.\n"); uwsgi_log("!!!!!!!!!!! END OF WARNING !!!!!!!!!!\n"); } #ifdef __linux__ #ifdef MADV_MERGEABLE if (uwsgi.linux_ksm > 0) { uwsgi_log("[uwsgi-KSM] enabled with frequency: %d\n", uwsgi.linux_ksm); } #endif #endif if (uwsgi.master_process) { // initialize threads with shared state uwsgi_alarm_thread_start(); uwsgi_exceptions_handler_thread_start(); // initialize a mutex to avoid glibc problem with pthread+fork() if (uwsgi.threaded_logger) { pthread_mutex_init(&uwsgi.threaded_logger_lock, NULL); } if (uwsgi.is_a_reload) { uwsgi_log("gracefully (RE)spawned uWSGI master process (pid: %d)\n", uwsgi.mypid); } else { uwsgi_log("spawned uWSGI master process (pid: %d)\n", uwsgi.mypid); } } // security in multiuser environment: allow only a subset of modifiers if (uwsgi.allowed_modifiers) { for (i = 0; i < 256; i++) { if (!uwsgi_list_has_num(uwsgi.allowed_modifiers, i)) { uwsgi.p[i]->request = unconfigured_hook; uwsgi.p[i]->after_request = unconfigured_after_hook; } } } // master fixup for (i = 0; i < 256; i++) { if (uwsgi.p[i]->master_fixup) { uwsgi.p[i]->master_fixup(0); } } struct uwsgi_spooler *uspool = uwsgi.spoolers; while (uspool) { if (uspool->mode == UWSGI_SPOOLER_EXTERNAL) goto next2; uspool->pid = spooler_start(uspool); next2: uspool = uspool->next; } if (!uwsgi.master_process) { if (uwsgi.numproc == 1) { uwsgi_log("spawned uWSGI worker 1 (and the only) (pid: %d, cores: %d)\n", masterpid, uwsgi.cores); } else { uwsgi_log("spawned uWSGI worker 1 (pid: %d, cores: %d)\n", masterpid, uwsgi.cores); } uwsgi.workers[1].pid = masterpid; uwsgi.workers[1].id = 1; uwsgi.workers[1].last_spawn = uwsgi_now(); uwsgi.workers[1].manage_next_request = 1; uwsgi.mywid = 1; uwsgi.respawn_delta = uwsgi_now(); } else { // setup internal signalling system create_signal_pipe(uwsgi.shared->worker_signal_pipe); uwsgi.signal_socket = uwsgi.shared->worker_signal_pipe[1]; } // uWSGI is ready uwsgi_notify_ready(); uwsgi.current_time = uwsgi_now(); // here we spawn the workers... if (!uwsgi.status.is_cheap) { if (uwsgi.cheaper && uwsgi.cheaper_count) { int nproc = uwsgi.cheaper_initial; if (!nproc) nproc = uwsgi.cheaper_count; for (i = 1; i <= uwsgi.numproc; i++) { if (i <= nproc) { if (uwsgi_respawn_worker(i)) break; uwsgi.respawn_delta = uwsgi_now(); } else { uwsgi.workers[i].cheaped = 1; } } } else { for (i = 2 - uwsgi.master_process; i < uwsgi.numproc + 1; i++) { if (uwsgi_respawn_worker(i)) break; uwsgi.respawn_delta = uwsgi_now(); } } } if (uwsgi.safe_pidfile2 && !uwsgi.is_a_reload) { uwsgi_write_pidfile_explicit(uwsgi.safe_pidfile2, masterpid); } // END OF INITIALIZATION return 0; } // this lives in a worker thread and periodically scans for memory usage // when evil reloaders are in place void *mem_collector(void *foobar) { // block all signals sigset_t smask; sigfillset(&smask); pthread_sigmask(SIG_BLOCK, &smask, NULL); uwsgi_log_verbose("mem-collector thread started for worker %d\n", uwsgi.mywid); for(;;) { sleep(uwsgi.mem_collector_freq); uint64_t rss = 0, vsz = 0; get_memusage(&rss, &vsz); uwsgi.workers[uwsgi.mywid].rss_size = rss; uwsgi.workers[uwsgi.mywid].vsz_size = vsz; } return NULL; } int uwsgi_run() { // !!! from now on, we could be in the master or in a worker !!! int i; if (getpid() == masterpid && uwsgi.master_process == 1) { #ifdef UWSGI_AS_SHARED_LIBRARY int ml_ret = master_loop(uwsgi.argv, uwsgi.environ); if (ml_ret == -1) { return 0; } #else (void) master_loop(uwsgi.argv, uwsgi.environ); #endif //from now on the process is a real worker } #if defined(__linux__) && defined(PR_SET_PDEATHSIG) // avoid workers running without master at all costs !!! (dangerous) if (uwsgi.master_process && uwsgi.no_orphans) { if (prctl(PR_SET_PDEATHSIG, SIGKILL)) { uwsgi_error("uwsgi_run()/prctl()"); } } #endif if (uwsgi.evil_reload_on_rss || uwsgi.evil_reload_on_as) { pthread_t t; pthread_create(&t, NULL, mem_collector, NULL); } // eventually maps (or disable) sockets for the worker uwsgi_map_sockets(); // eventually set cpu affinity poilicies (OS-dependent) uwsgi_set_cpu_affinity(); if (uwsgi.worker_exec) { char *w_argv[2]; w_argv[0] = uwsgi.worker_exec; w_argv[1] = NULL; uwsgi.sockets->arg &= (~O_NONBLOCK); if (fcntl(uwsgi.sockets->fd, F_SETFL, uwsgi.sockets->arg) < 0) { uwsgi_error("fcntl()"); exit(1); } if (uwsgi.sockets->fd != 0 && !uwsgi.honour_stdin) { if (dup2(uwsgi.sockets->fd, 0) < 0) { uwsgi_error("dup2()"); } } execvp(w_argv[0], w_argv); // never here uwsgi_error("execvp()"); exit(1); } if (uwsgi.master_as_root) { uwsgi_as_root(); } // set default wsgi_req (for loading apps); uwsgi.wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[0].req; if (uwsgi.offload_threads > 0) { uwsgi.offload_thread = uwsgi_malloc(sizeof(struct uwsgi_thread *) * uwsgi.offload_threads); for(i=0;ipost_fork) { uwsgi.p[i]->post_fork(); } } for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->post_fork) { uwsgi.gp[i]->post_fork(); } } uwsgi_hooks_run(uwsgi.hook_post_fork, "post-fork", 1); if (uwsgi.worker_exec2) { char *w_argv[2]; w_argv[0] = uwsgi.worker_exec2; w_argv[1] = NULL; uwsgi.sockets->arg &= (~O_NONBLOCK); if (fcntl(uwsgi.sockets->fd, F_SETFL, uwsgi.sockets->arg) < 0) { uwsgi_error("fcntl()"); exit(1); } if (uwsgi.sockets->fd != 0 && !uwsgi.honour_stdin) { if (dup2(uwsgi.sockets->fd, 0) < 0) { uwsgi_error("dup2()"); } } execvp(w_argv[0], w_argv); // never here uwsgi_error("execvp()"); exit(1); } // must be run before running apps // check for worker override for (i = 0; i < 256; i++) { if (uwsgi.p[i]->worker) { if (uwsgi.p[i]->worker()) { _exit(0); } } } for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->worker) { if (uwsgi.gp[i]->worker()) { _exit(0); } } } uwsgi_worker_run(); // never here _exit(0); } void uwsgi_worker_run() { int i; if (uwsgi.lazy || uwsgi.lazy_apps) { uwsgi_init_all_apps(); } // some apps could be mounted only on specific workers uwsgi_init_worker_mount_apps(); if (uwsgi.async > 1) { // a stack of unused cores uwsgi.async_queue_unused = uwsgi_malloc(sizeof(struct wsgi_request *) * uwsgi.async); // fill it with default values for (i = 0; i < uwsgi.async; i++) { uwsgi.async_queue_unused[i] = &uwsgi.workers[uwsgi.mywid].cores[i].req; } // the first available core is the last one uwsgi.async_queue_unused_ptr = uwsgi.async - 1; } // setup UNIX signals for the worker if (uwsgi.harakiri_options.workers > 0 && !uwsgi.master_process) { signal(SIGALRM, (void *) &harakiri); } uwsgi_unix_signal(SIGHUP, gracefully_kill); uwsgi_unix_signal(SIGINT, end_me); uwsgi_unix_signal(SIGTERM, end_me); uwsgi_unix_signal(SIGUSR1, stats); signal(SIGUSR2, (void *) &what_i_am_doing); if (!uwsgi.ignore_sigpipe) { signal(SIGPIPE, (void *) &warn_pipe); } // worker initialization done // run fixup handler for (i = 0; i < 256; i++) { if (uwsgi.p[i]->fixup) { uwsgi.p[i]->fixup(); } } if (uwsgi.chdir2) { uwsgi_log("chdir() to %s\n", uwsgi.chdir2); if (chdir(uwsgi.chdir2)) { uwsgi_error("chdir()"); exit(1); } } //re - initialize wsgi_req(can be full of init_uwsgi_app data) for (i = 0; i < uwsgi.cores; i++) { memset(&uwsgi.workers[uwsgi.mywid].cores[i].req, 0, sizeof(struct wsgi_request)); uwsgi.workers[uwsgi.mywid].cores[i].req.async_id = i; } // eventually remap plugins if (uwsgi.remap_modifier) { char *map, *ctx = NULL; uwsgi_foreach_token(uwsgi.remap_modifier, ",", map, ctx) { char *colon = strchr(map, ':'); if (colon) { colon[0] = 0; int rm_src = atoi(map); int rm_dst = atoi(colon + 1); uwsgi.p[rm_dst]->request = uwsgi.p[rm_src]->request; uwsgi.p[rm_dst]->after_request = uwsgi.p[rm_src]->after_request; } } } if (uwsgi.cores > 1) { uwsgi.workers[uwsgi.mywid].cores[0].thread_id = pthread_self(); } uwsgi_ignition(); // never here exit(0); } void uwsgi_ignition() { int i; for (i = 0; i < 256; i++) { if (uwsgi.p[i]->hijack_worker) { uwsgi.p[i]->hijack_worker(); } } for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->hijack_worker) { uwsgi.gp[i]->hijack_worker(); } } // create a pthread key, storing per-thread wsgi_request structure if (uwsgi.threads > 1) { if (pthread_key_create(&uwsgi.tur_key, NULL)) { uwsgi_error("pthread_key_create()"); exit(1); } } if (pipe(&uwsgi.loop_stop_pipe[0])) { uwsgi_error("pipe()") exit(1); } // mark the worker as "accepting" (this is a mark used by chain reloading) uwsgi.workers[uwsgi.mywid].accepting = 1; // ready to accept request, if i am a vassal signal Emperor about it if (uwsgi.has_emperor && uwsgi.mywid == 1) { char byte = 5; if (write(uwsgi.emperor_fd, &byte, 1) != 1) { uwsgi_error("emperor-i-am-ready-to-accept/write()"); uwsgi_log_verbose("lost communication with the Emperor, goodbye...\n"); gracefully_kill_them_all(0); exit(1); } } // run accepting hooks uwsgi_hooks_run(uwsgi.hook_accepting, "accepting", 1); if (uwsgi.workers[uwsgi.mywid].respawn_count == 1) { uwsgi_hooks_run(uwsgi.hook_accepting_once, "accepting-once", 1); } if (uwsgi.mywid == 1) { uwsgi_hooks_run(uwsgi.hook_accepting1, "accepting1", 1); if (uwsgi.workers[uwsgi.mywid].respawn_count == 1) { uwsgi_hooks_run(uwsgi.hook_accepting1_once, "accepting1-once", 1); } } if (uwsgi.loop) { void (*u_loop) (void) = uwsgi_get_loop(uwsgi.loop); if (!u_loop) { uwsgi_log("unavailable loop engine !!!\n"); exit(1); } if (uwsgi.mywid == 1) { uwsgi_log("*** running %s loop engine [addr:%p] ***\n", uwsgi.loop, u_loop); } u_loop(); uwsgi_log("your loop engine died. R.I.P.\n"); } else { if (uwsgi.async < 2) { simple_loop(); } else { async_loop(); } } // main thread waits other threads. if (uwsgi.threads > 1) { wait_for_threads(); } // end of the process... end_me(0); } /* what happens here ? we transform the uwsgi_option structure to a struct option for passing it to getopt_long A short options string is built. This function could be called multiple times, so it will free previous areas */ void build_options() { int options_count = 0; int pos = 0; int i; // first count the base options struct uwsgi_option *op = uwsgi_base_options; while (op->name) { options_count++; op++; } for (i = 0; i < 256; i++) { if (uwsgi.p[i]->options) { options_count += uwsgi_count_options(uwsgi.p[i]->options); } } for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->options) { options_count += uwsgi_count_options(uwsgi.gp[i]->options); } } // add custom options struct uwsgi_custom_option *uco = uwsgi.custom_options; while (uco) { options_count++; uco = uco->next; } if (uwsgi.options) free(uwsgi.options); // rebuild uwsgi.options area uwsgi.options = uwsgi_calloc(sizeof(struct uwsgi_option) * (options_count + 1)); op = uwsgi_base_options; while (op->name) { memcpy(&uwsgi.options[pos], op, sizeof(struct uwsgi_option)); pos++; op++; } for (i = 0; i < 256; i++) { if (uwsgi.p[i]->options) { int c = uwsgi_count_options(uwsgi.p[i]->options); memcpy(&uwsgi.options[pos], uwsgi.p[i]->options, sizeof(struct uwsgi_option) * c); pos += c; } } for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->options) { int c = uwsgi_count_options(uwsgi.gp[i]->options); memcpy(&uwsgi.options[pos], uwsgi.gp[i]->options, sizeof(struct uwsgi_option) * c); pos += c; } } uco = uwsgi.custom_options; while (uco) { uwsgi.options[pos].name = uco->name; if (uco->has_args) { uwsgi.options[pos].type = required_argument; } else { uwsgi.options[pos].type = no_argument; } // custom options should be immediate uwsgi.options[pos].flags = UWSGI_OPT_IMMEDIATE; // help shows the option definition uwsgi.options[pos].help = uco->value; uwsgi.options[pos].data = uco; uwsgi.options[pos].func = uwsgi_opt_custom; pos++; uco = uco->next; } pos = 0; if (uwsgi.long_options) free(uwsgi.long_options); uwsgi.long_options = uwsgi_calloc(sizeof(struct option) * (options_count + 1)); if (uwsgi.short_options) free(uwsgi.short_options); uwsgi.short_options = uwsgi_calloc((options_count * 3) + 1); // build long_options (this time with custom_options) op = uwsgi.options; while (op->name) { uwsgi.long_options[pos].name = op->name; uwsgi.long_options[pos].has_arg = op->type; uwsgi.long_options[pos].flag = 0; // add 1000 to avoid short_options collision uwsgi.long_options[pos].val = 1000 + pos; if (op->shortcut) { char shortcut = (char) op->shortcut; // avoid duplicates in short_options if (!strchr(uwsgi.short_options, shortcut)) { strncat(uwsgi.short_options, &shortcut, 1); if (op->type == optional_argument) { strcat(uwsgi.short_options, "::"); } else if (op->type == required_argument) { strcat(uwsgi.short_options, ":"); } } } op++; pos++; } } /* this function builds the help output from the uwsgi.options structure */ void uwsgi_help(char *opt, char *val, void *none) { size_t max_size = 0; fprintf(stdout, "Usage: %s [options...]\n", uwsgi.binary_path); struct uwsgi_option *op = uwsgi.options; while (op && op->name) { if (strlen(op->name) > max_size) { max_size = strlen(op->name); } op++; } max_size++; op = uwsgi.options; while (op && op->name) { if (op->shortcut) { fprintf(stdout, " -%c|--%-*s %s\n", op->shortcut, (int) max_size - 3, op->name, op->help); } else { fprintf(stdout, " --%-*s %s\n", (int) max_size, op->name, op->help); } op++; } exit(0); } /* initialize all apps */ void uwsgi_init_all_apps() { int i, j; uwsgi_hooks_run(uwsgi.hook_pre_app, "pre app", 1); // now run the pre-app scripts struct uwsgi_string_list *usl = uwsgi.exec_pre_app; while (usl) { uwsgi_log("running \"%s\" (pre app)...\n", usl->value); int ret = uwsgi_run_command_and_wait(NULL, usl->value); if (ret != 0) { uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret); exit(1); } usl = usl->next; } uwsgi_foreach(usl, uwsgi.call_pre_app) { if (uwsgi_call_symbol(usl->value)) { uwsgi_log("unable to call function \"%s\"\n", usl->value); exit(1); } } for (i = 0; i < 256; i++) { if (uwsgi.p[i]->init_apps) { uwsgi.p[i]->init_apps(); } } for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->init_apps) { uwsgi.gp[i]->init_apps(); } } struct uwsgi_string_list *app_mps = uwsgi.mounts; while (app_mps) { char *what = strchr(app_mps->value, '='); if (what) { what[0] = 0; what++; for (j = 0; j < 256; j++) { if (uwsgi.p[j]->mount_app) { uwsgi_log("mounting %s on %s\n", what, app_mps->value); if (uwsgi.p[j]->mount_app(app_mps->value, what) != -1) break; } } what--; what[0] = '='; } else { uwsgi_log("invalid mountpoint: %s\n", app_mps->value); exit(1); } app_mps = app_mps->next; } // no app initialized and virtualhosting enabled if (uwsgi_apps_cnt == 0 && uwsgi.numproc > 0 && !uwsgi.command_mode) { if (uwsgi.need_app) { if (!uwsgi.lazy) uwsgi_log("*** no app loaded. GAME OVER ***\n"); exit(UWSGI_FAILED_APP_CODE); } else { uwsgi_log("*** no app loaded. going in full dynamic mode ***\n"); } } uwsgi_hooks_run(uwsgi.hook_post_app, "post app", 1); usl = uwsgi.exec_post_app; while (usl) { uwsgi_log("running \"%s\" (post app)...\n", usl->value); int ret = uwsgi_run_command_and_wait(NULL, usl->value); if (ret != 0) { uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret); exit(1); } usl = usl->next; } uwsgi_foreach(usl, uwsgi.call_post_app) { if (uwsgi_call_symbol(usl->value)) { uwsgi_log("unable to call function \"%s\"\n", usl->value); } } } void uwsgi_init_worker_mount_apps() { /* int i,j; for (i = 0; i < uwsgi.mounts_cnt; i++) { char *what = strchr(uwsgi.mounts[i], '='); if (what) { what[0] = 0; what++; for (j = 0; j < 256; j++) { if (uwsgi.p[j]->mount_app) { if (!uwsgi_startswith(uwsgi.mounts[i], "worker://", 9)) { uwsgi_log("mounting %s on %s\n", what, uwsgi.mounts[i]+9); if (uwsgi.p[j]->mount_app(uwsgi.mounts[i] + 9, what, 1) != -1) break; } } } what--; what[0] = '='; } else { uwsgi_log("invalid mountpoint: %s\n", uwsgi.mounts[i]); exit(1); } } */ } void uwsgi_opt_true(char *opt, char *value, void *key) { int *ptr = (int *) key; *ptr = 1; if (value) { if (!strcasecmp("false", value) || !strcasecmp("off", value) || !strcasecmp("no", value) || !strcmp("0", value)) { *ptr = 0; } } } void uwsgi_opt_false(char *opt, char *value, void *key) { int *ptr = (int *) key; *ptr = 0; if (value) { if (!strcasecmp("false", value) || !strcasecmp("off", value) || !strcasecmp("no", value) || !strcmp("0", value)) { *ptr = 1; } } } void uwsgi_opt_set_immediate_gid(char *opt, char *value, void *none) { gid_t gid = 0; if (is_a_number(value)) gid = atoi(value); if (gid == 0) { struct group *ugroup = getgrnam(value); if (ugroup) gid = ugroup->gr_gid; } if (gid <= 0) { uwsgi_log("uwsgi_opt_set_immediate_gid(): invalid gid %d\n", (int) gid); exit(1); } if (setgid(gid)) { uwsgi_error("uwsgi_opt_set_immediate_gid()/setgid()"); exit(1); } if (setgroups(0, NULL)) { uwsgi_error("uwsgi_opt_set_immediate_gid()/setgroups()"); exit(1); } gid = getgid(); if (!gid) { exit(1); } uwsgi_log("immediate gid: %d\n", (int) gid); } void uwsgi_opt_set_immediate_uid(char *opt, char *value, void *none) { uid_t uid = 0; if (is_a_number(value)) uid = atoi(value); if (uid == 0) { struct passwd *upasswd = getpwnam(value); if (upasswd) uid = upasswd->pw_uid; } if (uid <= 0) { uwsgi_log("uwsgi_opt_set_immediate_uid(): invalid uid %d\n", uid); exit(1); } if (setuid(uid)) { uwsgi_error("uwsgi_opt_set_immediate_uid()/setuid()"); exit(1); } uid = getuid(); if (!uid) { exit(1); } uwsgi_log("immediate uid: %d\n", (int) uid); } void uwsgi_opt_safe_fd(char *opt, char *value, void *foobar) { int fd = atoi(value); if (fd < 0) { uwsgi_log("invalid file descriptor: %d\n", fd); exit(1); } uwsgi_add_safe_fd(fd); } void uwsgi_opt_set_int(char *opt, char *value, void *key) { int *ptr = (int *) key; if (value) { *ptr = atoi((char *) value); } else { *ptr = 1; } if (*ptr < 0) { uwsgi_log("invalid value for option \"%s\": must be > 0\n", opt); exit(1); } } void uwsgi_opt_uid(char *opt, char *value, void *key) { uid_t uid = 0; if (is_a_number(value)) uid = atoi(value); if (!uid) { struct passwd *p = getpwnam(value); if (p) { uid = p->pw_uid; } else { uwsgi_log("unable to find user %s\n", value); exit(1); } } if (key) { uid_t *ptr = (uid_t *) key; *ptr = uid; } } void uwsgi_opt_gid(char *opt, char *value, void *key) { gid_t gid = 0; if (is_a_number(value)) gid = atoi(value); if (!gid) { struct group *g = getgrnam(value); if (g) { gid = g->gr_gid; } else { uwsgi_log("unable to find group %s\n", value); exit(1); } } if (key) { gid_t *ptr = (gid_t *) key; *ptr = gid; } } void uwsgi_opt_set_rawint(char *opt, char *value, void *key) { int *ptr = (int *) key; if (value) { *ptr = atoi((char *) value); } else { *ptr = 1; } } void uwsgi_opt_set_64bit(char *opt, char *value, void *key) { uint64_t *ptr = (uint64_t *) key; if (value) { *ptr = (strtoul(value, NULL, 10)); } else { *ptr = 1; } } void uwsgi_opt_set_16bit(char *opt, char *value, void *key) { uint16_t *ptr = (uint16_t *) key; if (value) { unsigned long n = strtoul(value, NULL, 10); if (n > 65535) n = 65535; *ptr = n; } else { *ptr = 1; } } void uwsgi_opt_set_megabytes(char *opt, char *value, void *key) { uint64_t *ptr = (uint64_t *) key; *ptr = (uint64_t)strtoul(value, NULL, 10) * 1024 * 1024; } void uwsgi_opt_set_str(char *opt, char *value, void *key) { char **ptr = (char **) key; if (!value) { *ptr = ""; return; } *ptr = (char *) value; } void uwsgi_opt_set_null(char *opt, char *value, void *key) { char **ptr = (char **) key; *ptr = NULL; } void uwsgi_opt_set_logger(char *opt, char *value, void *prefix) { if (!value) value = ""; if (prefix) { uwsgi_string_new_list(&uwsgi.requested_logger, uwsgi_concat3((char *) prefix, ":", value)); } else { uwsgi_string_new_list(&uwsgi.requested_logger, uwsgi_str(value)); } } void uwsgi_opt_set_req_logger(char *opt, char *value, void *prefix) { if (!value) value = ""; if (prefix) { uwsgi_string_new_list(&uwsgi.requested_req_logger, uwsgi_concat3((char *) prefix, ":", value)); } else { uwsgi_string_new_list(&uwsgi.requested_req_logger, uwsgi_str(value)); } } void uwsgi_opt_set_str_spaced(char *opt, char *value, void *key) { char **ptr = (char **) key; *ptr = uwsgi_concat2((char *) value, " "); } void uwsgi_opt_add_string_list(char *opt, char *value, void *list) { struct uwsgi_string_list **ptr = (struct uwsgi_string_list **) list; uwsgi_string_new_list(ptr, value); } void uwsgi_opt_add_addr_list(char *opt, char *value, void *list) { struct uwsgi_string_list **ptr = (struct uwsgi_string_list **) list; int af = AF_INET; #ifdef AF_INET6 void *ip = uwsgi_malloc(16); if (strchr(value, ':')) { af = AF_INET6; } #else void *ip = uwsgi_malloc(4); #endif if (inet_pton(af, value, ip) <= 0) { uwsgi_log("%s: invalid address\n", opt); uwsgi_error("uwsgi_opt_add_addr_list()"); exit(1); } struct uwsgi_string_list *usl = uwsgi_string_new_list(ptr, ip); usl->custom = af; usl->custom_ptr = value; } void uwsgi_opt_add_string_list_custom(char *opt, char *value, void *list) { struct uwsgi_string_list **ptr = (struct uwsgi_string_list **) list; struct uwsgi_string_list *usl = uwsgi_string_new_list(ptr, value); usl->custom = 1; } #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) void uwsgi_opt_add_regexp_list(char *opt, char *value, void *list) { struct uwsgi_regexp_list **ptr = (struct uwsgi_regexp_list **) list; uwsgi_regexp_new_list(ptr, value); } void uwsgi_opt_add_regexp_custom_list(char *opt, char *value, void *list) { char *space = strchr(value, ' '); if (!space) { uwsgi_log("invalid custom regexp syntax: must be \n"); exit(1); } char *custom = uwsgi_concat2n(value, space - value, "", 0); struct uwsgi_regexp_list **ptr = (struct uwsgi_regexp_list **) list; uwsgi_regexp_custom_new_list(ptr, space + 1, custom); } #endif void uwsgi_opt_add_shared_socket(char *opt, char *value, void *protocol) { struct uwsgi_socket *us = uwsgi_new_shared_socket(generate_socket_name(value)); if (!strcmp(opt, "undeferred-shared-socket")) { us->no_defer = 1; } } void uwsgi_opt_add_socket(char *opt, char *value, void *protocol) { struct uwsgi_socket *uwsgi_sock = uwsgi_new_socket(generate_socket_name(value)); uwsgi_sock->name_len = strlen(uwsgi_sock->name); uwsgi_sock->proto_name = protocol; } #ifdef UWSGI_SSL void uwsgi_opt_add_ssl_socket(char *opt, char *value, void *protocol) { char *client_ca = NULL; // build socket, certificate and key file char *sock = uwsgi_str(value); char *crt = strchr(sock, ','); if (!crt) { uwsgi_log("invalid https-socket syntax must be socket,crt,key\n"); exit(1); } *crt = '\0'; crt++; char *key = strchr(crt, ','); if (!key) { uwsgi_log("invalid https-socket syntax must be socket,crt,key\n"); exit(1); } *key = '\0'; key++; char *ciphers = strchr(key, ','); if (ciphers) { *ciphers = '\0'; ciphers++; client_ca = strchr(ciphers, ','); if (client_ca) { *client_ca = '\0'; client_ca++; } } struct uwsgi_socket *uwsgi_sock = uwsgi_new_socket(generate_socket_name(sock)); uwsgi_sock->name_len = strlen(uwsgi_sock->name); uwsgi_sock->proto_name = protocol; // ok we have the socket, initialize ssl if required if (!uwsgi.ssl_initialized) { uwsgi_ssl_init(); } // initialize ssl context uwsgi_sock->ssl_ctx = uwsgi_ssl_new_server_context(uwsgi_sock->name, crt, key, ciphers, client_ca); if (!uwsgi_sock->ssl_ctx) { exit(1); } } #endif void uwsgi_opt_add_socket_no_defer(char *opt, char *value, void *protocol) { struct uwsgi_socket *uwsgi_sock = uwsgi_new_socket(generate_socket_name(value)); uwsgi_sock->name_len = strlen(uwsgi_sock->name); uwsgi_sock->proto_name = protocol; uwsgi_sock->no_defer = 1; } void uwsgi_opt_add_lazy_socket(char *opt, char *value, void *protocol) { struct uwsgi_socket *uwsgi_sock = uwsgi_new_socket(generate_socket_name(value)); uwsgi_sock->proto_name = protocol; uwsgi_sock->bound = 1; uwsgi_sock->lazy = 1; } void uwsgi_opt_set_placeholder(char *opt, char *value, void *ph) { char *p = strchr(value, '='); if (!p) { uwsgi_log("invalid placeholder/--set value\n"); exit(1); } p[0] = 0; add_exported_option_do(uwsgi_str(value), p + 1, 0, ph ? 1 : 0); p[0] = '='; } void uwsgi_opt_ssa(char *opt, char *value, void *foobar) { uwsgi_subscription_set_algo(value); } #ifdef UWSGI_SSL void uwsgi_opt_scd(char *opt, char *value, void *foobar) { // openssl could not be initialized if (!uwsgi.ssl_initialized) { uwsgi_ssl_init(); } char *colon = strchr(value, ':'); if (!colon) { uwsgi_log("invalid syntax for '%s', must be: :\n", opt); exit(1); } char *algo = uwsgi_concat2n(value, (colon - value), "", 0); uwsgi.subscriptions_sign_check_md = EVP_get_digestbyname(algo); if (!uwsgi.subscriptions_sign_check_md) { uwsgi_log("unable to find digest algorithm: %s\n", algo); exit(1); } free(algo); uwsgi.subscriptions_sign_check_dir = colon + 1; } #endif void uwsgi_opt_set_umask(char *opt, char *value, void *mode) { int error = 0; mode_t mask = uwsgi_mode_t(value, &error); if (error) { uwsgi_log("invalid umask: %s\n", value); } umask(mask); uwsgi.do_not_change_umask = 1; } void uwsgi_opt_exit(char *opt, char *value, void *none) { int exit_code = 1; if (value) { exit_code = atoi(value); } exit(exit_code); } void uwsgi_opt_print(char *opt, char *value, void *str) { if (str) { fprintf(stdout, "%s\n", (char *) str); exit(0); } fprintf(stdout, "%s\n", value); } void uwsgi_opt_set_uid(char *opt, char *value, void *none) { if (is_a_number(value)) uwsgi.uid = atoi(value); if (!uwsgi.uid) uwsgi.uidname = value; } void uwsgi_opt_set_gid(char *opt, char *value, void *none) { if (is_a_number(value)) uwsgi.gid = atoi(value); if (!uwsgi.gid) uwsgi.gidname = value; } #ifdef UWSGI_CAP void uwsgi_opt_set_cap(char *opt, char *value, void *none) { uwsgi.cap_count = uwsgi_build_cap(value, &uwsgi.cap); if (uwsgi.cap_count == 0) { uwsgi_log("[security] empty capabilities mask !!!\n"); exit(1); } } void uwsgi_opt_set_emperor_cap(char *opt, char *value, void *none) { uwsgi.emperor_cap_count = uwsgi_build_cap(value, &uwsgi.emperor_cap); if (uwsgi.emperor_cap_count == 0) { uwsgi_log("[security] empty capabilities mask !!!\n"); exit(1); } } #endif #ifdef __linux__ void uwsgi_opt_set_unshare(char *opt, char *value, void *mask) { uwsgi_build_unshare(value, (int *) mask); } #endif void uwsgi_opt_set_env(char *opt, char *value, void *none) { if (putenv(value)) { uwsgi_error("putenv()"); } } void uwsgi_opt_unset_env(char *opt, char *value, void *none) { #ifdef UNSETENV_VOID unsetenv(value); #else if (unsetenv(value)) { uwsgi_error("unsetenv()"); } #endif } void uwsgi_opt_pidfile_signal(char *opt, char *pidfile, void *sig) { long *signum_fake_ptr = (long *) sig; int signum = (long) signum_fake_ptr; exit(signal_pidfile(signum, pidfile)); } void uwsgi_opt_load_dl(char *opt, char *value, void *none) { if (!dlopen(value, RTLD_NOW | RTLD_GLOBAL)) { uwsgi_log("%s\n", dlerror()); } } void uwsgi_opt_load_plugin(char *opt, char *value, void *none) { char *plugins_list = uwsgi_concat2(value, ""); char *p, *ctx = NULL; uwsgi_foreach_token(plugins_list, ",", p, ctx) { #ifdef UWSGI_DEBUG uwsgi_debug("loading plugin %s\n", p); #endif if (uwsgi_load_plugin(-1, p, NULL)) { build_options(); } else if (!uwsgi_startswith(opt, "need-", 5)) { uwsgi_log("unable to load plugin \"%s\"\n", p); exit(1); } } free(p); free(plugins_list); } void uwsgi_opt_check_static(char *opt, char *value, void *foobar) { uwsgi_dyn_dict_new(&uwsgi.check_static, value, strlen(value), NULL, 0); uwsgi_log("[uwsgi-static] added check for %s\n", value); uwsgi.build_mime_dict = 1; } void uwsgi_opt_add_dyn_dict(char *opt, char *value, void *dict) { char *equal = strchr(value, '='); if (!equal) { uwsgi_log("invalid dictionary syntax for %s\n", opt); exit(1); } struct uwsgi_dyn_dict **udd = (struct uwsgi_dyn_dict **) dict; uwsgi_dyn_dict_new(udd, value, equal - value, equal + 1, strlen(equal + 1)); } #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) void uwsgi_opt_add_regexp_dyn_dict(char *opt, char *value, void *dict) { char *space = strchr(value, ' '); if (!space) { uwsgi_log("invalid dictionary syntax for %s\n", opt); exit(1); } struct uwsgi_dyn_dict **udd = (struct uwsgi_dyn_dict **) dict; struct uwsgi_dyn_dict *new_udd = uwsgi_dyn_dict_new(udd, value, space - value, space + 1, strlen(space + 1)); char *regexp = uwsgi_concat2n(value, space - value, "", 0); if (uwsgi_regexp_build(regexp, &new_udd->pattern)) { exit(1); } free(regexp); } #endif void uwsgi_opt_fileserve_mode(char *opt, char *value, void *foobar) { if (!strcasecmp("x-sendfile", value)) { uwsgi.file_serve_mode = 2; } else if (!strcasecmp("xsendfile", value)) { uwsgi.file_serve_mode = 2; } else if (!strcasecmp("x-accel-redirect", value)) { uwsgi.file_serve_mode = 1; } else if (!strcasecmp("xaccelredirect", value)) { uwsgi.file_serve_mode = 1; } else if (!strcasecmp("nginx", value)) { uwsgi.file_serve_mode = 1; } } void uwsgi_opt_static_map(char *opt, char *value, void *static_maps) { struct uwsgi_dyn_dict **maps = (struct uwsgi_dyn_dict **) static_maps; char *mountpoint = uwsgi_str(value); char *docroot = strchr(mountpoint, '='); if (!docroot) { uwsgi_log("invalid document root in static map, syntax mountpoint=docroot\n"); exit(1); } docroot[0] = 0; docroot++; uwsgi_dyn_dict_new(maps, mountpoint, strlen(mountpoint), docroot, strlen(docroot)); uwsgi_log_initial("[uwsgi-static] added mapping for %s => %s\n", mountpoint, docroot); uwsgi.build_mime_dict = 1; } int uwsgi_zerg_attach(char *value) { int count = 8; int zerg_fd = uwsgi_connect(value, 30, 0); if (zerg_fd < 0) { uwsgi_log("--- unable to connect to zerg server %s ---\n", value); return -1; } int last_count = count; int *zerg = uwsgi_attach_fd(zerg_fd, &count, "uwsgi-zerg", 10); if (zerg == NULL) { if (last_count != count) { close(zerg_fd); zerg_fd = uwsgi_connect(value, 30, 0); if (zerg_fd < 0) { uwsgi_log("--- unable to connect to zerg server %s ---\n", value); return -1; } zerg = uwsgi_attach_fd(zerg_fd, &count, "uwsgi-zerg", 10); } } if (zerg == NULL) { uwsgi_log("--- invalid data received from zerg-server ---\n"); close(zerg_fd); return -1; } if (!uwsgi.zerg) { uwsgi.zerg = zerg; } else { int pos = 0; for (;;) { if (uwsgi.zerg[pos] == -1) { uwsgi.zerg = realloc(uwsgi.zerg, (sizeof(int) * (pos)) + (sizeof(int) * count + 1)); if (!uwsgi.zerg) { uwsgi_error("realloc()"); exit(1); } memcpy(&uwsgi.zerg[pos], zerg, (sizeof(int) * count + 1)); break; } pos++; } free(zerg); } close(zerg_fd); return 0; } void uwsgi_opt_signal(char *opt, char *value, void *foobar) { uwsgi_command_signal(value); } void uwsgi_opt_log_date(char *opt, char *value, void *foobar) { uwsgi.logdate = 1; if (value) { if (strcasecmp("true", value) && strcasecmp("1", value) && strcasecmp("on", value) && strcasecmp("yes", value)) { uwsgi.log_strftime = value; } } } void uwsgi_opt_chmod_socket(char *opt, char *value, void *foobar) { int i; uwsgi.chmod_socket = 1; if (value) { if (strlen(value) == 1 && *value == '1') { return; } if (strlen(value) != 3) { uwsgi_log("invalid chmod value: %s\n", value); exit(1); } for (i = 0; i < 3; i++) { if (value[i] < '0' || value[i] > '7') { uwsgi_log("invalid chmod value: %s\n", value); exit(1); } } uwsgi.chmod_socket_value = (uwsgi.chmod_socket_value << 3) + (value[0] - '0'); uwsgi.chmod_socket_value = (uwsgi.chmod_socket_value << 3) + (value[1] - '0'); uwsgi.chmod_socket_value = (uwsgi.chmod_socket_value << 3) + (value[2] - '0'); } } void uwsgi_opt_logfile_chmod(char *opt, char *value, void *foobar) { int i; if (strlen(value) != 3) { uwsgi_log("invalid chmod value: %s\n", value); exit(1); } for (i = 0; i < 3; i++) { if (value[i] < '0' || value[i] > '7') { uwsgi_log("invalid chmod value: %s\n", value); exit(1); } } uwsgi.chmod_logfile_value = (uwsgi.chmod_logfile_value << 3) + (value[0] - '0'); uwsgi.chmod_logfile_value = (uwsgi.chmod_logfile_value << 3) + (value[1] - '0'); uwsgi.chmod_logfile_value = (uwsgi.chmod_logfile_value << 3) + (value[2] - '0'); } void uwsgi_opt_max_vars(char *opt, char *value, void *foobar) { uwsgi.max_vars = atoi(value); uwsgi.vec_size = 4 + 1 + (4 * uwsgi.max_vars); } void uwsgi_opt_deprecated(char *opt, char *value, void *message) { uwsgi_log("[WARNING] option \"%s\" is deprecated: %s\n", opt, (char *) message); } void uwsgi_opt_load(char *opt, char *filename, void *none) { // here we need to avoid setting upper magic vars int orig_magic = uwsgi.magic_table_first_round; uwsgi.magic_table_first_round = 1; if (uwsgi_endswith(filename, ".ini")) { uwsgi_opt_load_ini(opt, filename, none); goto end; } #ifdef UWSGI_XML if (uwsgi_endswith(filename, ".xml")) { uwsgi_opt_load_xml(opt, filename, none); goto end; } #endif #ifdef UWSGI_YAML if (uwsgi_endswith(filename, ".yaml")) { uwsgi_opt_load_yml(opt, filename, none); goto end; } if (uwsgi_endswith(filename, ".yml")) { uwsgi_opt_load_yml(opt, filename, none); goto end; } #endif #ifdef UWSGI_JSON if (uwsgi_endswith(filename, ".json")) { uwsgi_opt_load_json(opt, filename, none); goto end; } if (uwsgi_endswith(filename, ".js")) { uwsgi_opt_load_json(opt, filename, none); goto end; } #endif // fallback to pluggable system uwsgi_opt_load_config(opt, filename, none); end: uwsgi.magic_table_first_round = orig_magic; } void uwsgi_opt_logic(char *opt, char *arg, void *func) { if (uwsgi.logic_opt) { uwsgi_log("recursive logic in options is not supported (option = %s)\n", opt); exit(1); } uwsgi.logic_opt = (int (*)(char *, char *)) func; uwsgi.logic_opt_cycles = 0; if (arg) { uwsgi.logic_opt_arg = uwsgi_str(arg); } else { uwsgi.logic_opt_arg = NULL; } } void uwsgi_opt_noop(char *opt, char *foo, void *bar) { } void uwsgi_opt_load_ini(char *opt, char *filename, void *none) { config_magic_table_fill(filename, uwsgi.magic_table); uwsgi_ini_config(filename, uwsgi.magic_table); } void uwsgi_opt_load_config(char *opt, char *filename, void *none) { struct uwsgi_configurator *uc = uwsgi.configurators; while(uc) { if (uwsgi_endswith(filename, uc->name)) { config_magic_table_fill(filename, uwsgi.magic_table); uc->func(filename, uwsgi.magic_table); return; } uc = uc->next; } uwsgi_log("unable to load configuration from %s\n", filename); exit(1); } #ifdef UWSGI_XML void uwsgi_opt_load_xml(char *opt, char *filename, void *none) { config_magic_table_fill(filename, uwsgi.magic_table); uwsgi_xml_config(filename, uwsgi.wsgi_req, uwsgi.magic_table); } #endif #ifdef UWSGI_YAML void uwsgi_opt_load_yml(char *opt, char *filename, void *none) { config_magic_table_fill(filename, uwsgi.magic_table); uwsgi_yaml_config(filename, uwsgi.magic_table); } #endif #ifdef UWSGI_JSON void uwsgi_opt_load_json(char *opt, char *filename, void *none) { config_magic_table_fill(filename, uwsgi.magic_table); uwsgi_json_config(filename, uwsgi.magic_table); } #endif void uwsgi_opt_add_custom_option(char *opt, char *value, void *none) { struct uwsgi_custom_option *uco = uwsgi.custom_options, *old_uco; if (!uco) { uwsgi.custom_options = uwsgi_malloc(sizeof(struct uwsgi_custom_option)); uco = uwsgi.custom_options; } else { while (uco) { old_uco = uco; uco = uco->next; } uco = uwsgi_malloc(sizeof(struct uwsgi_custom_option)); old_uco->next = uco; } char *copy = uwsgi_str(value); char *equal = strchr(copy, '='); if (!equal) { uwsgi_log("invalid %s syntax, must be newoption=template\n", value); exit(1); } *equal = 0; uco->name = copy; uco->value = equal + 1; uco->has_args = 0; // a little hack, we allow the user to skip the first 2 arguments (yes.. it is silly...but users tend to make silly things...) if (strstr(uco->value, "$1") || strstr(uco->value, "$2") || strstr(uco->value, "$3")) { uco->has_args = 1; } uco->next = NULL; build_options(); } void uwsgi_opt_flock(char *opt, char *filename, void *none) { int fd = open(filename, O_RDWR); if (fd < 0) { uwsgi_error_open(filename); exit(1); } if (uwsgi_fcntl_is_locked(fd)) { uwsgi_log("uWSGI ERROR: %s is locked by another instance\n", filename); exit(1); } } void uwsgi_opt_flock_wait(char *opt, char *filename, void *none) { int fd = open(filename, O_RDWR); if (fd < 0) { uwsgi_error_open(filename); exit(1); } if (uwsgi_fcntl_lock(fd)) { exit(1); } } // report CFLAGS used for compiling the server // use that values to build external plugins void uwsgi_opt_cflags(char *opt, char *filename, void *foobar) { fprintf(stdout, "%s\n", uwsgi_get_cflags()); exit(0); } char *uwsgi_get_cflags() { size_t len = sizeof(UWSGI_CFLAGS) -1; char *src = UWSGI_CFLAGS; char *ptr = uwsgi_malloc((len / 2) + 1); char *base = ptr; size_t i; unsigned int u; for (i = 0; i < len; i += 2) { sscanf(src + i, "%2x", &u); *ptr++ = (char) u; } *ptr ++= 0; return base; } // report uwsgi.h used for compiling the server // use that values to build external plugins extern char *uwsgi_dot_h; char *uwsgi_get_dot_h() { char *src = uwsgi_dot_h; size_t len = strlen(src); char *ptr = uwsgi_malloc((len / 2) + 1); char *base = ptr; size_t i; unsigned int u; for (i = 0; i < len; i += 2) { sscanf(src + i, "%2x", &u); *ptr++ = (char) u; } #ifdef UWSGI_ZLIB struct uwsgi_buffer *ub = uwsgi_zlib_decompress(base, ptr-base); if (!ub) { free(base); return ""; } // add final null byte uwsgi_buffer_append(ub, "\0", 1); free(base); // base is the final blob base = ub->buf; ub->buf = NULL; uwsgi_buffer_destroy(ub); #else // add final null byte *ptr = '\0'; #endif return base; } void uwsgi_opt_dot_h(char *opt, char *filename, void *foobar) { fprintf(stdout, "%s\n", uwsgi_get_dot_h()); exit(0); } extern char *uwsgi_config_py; char *uwsgi_get_config_py() { char *src = uwsgi_config_py; size_t len = strlen(src); char *ptr = uwsgi_malloc((len / 2) + 1); char *base = ptr; size_t i; unsigned int u; for (i = 0; i < len; i += 2) { sscanf(src + i, "%2x", &u); *ptr++ = (char) u; } #ifdef UWSGI_ZLIB struct uwsgi_buffer *ub = uwsgi_zlib_decompress(base, ptr-base); if (!ub) { free(base); return ""; } // add final null byte uwsgi_buffer_append(ub, "\0", 1); free(base); // base is the final blob base = ub->buf; ub->buf = NULL; uwsgi_buffer_destroy(ub); #else // add final null byte *ptr = '\0'; #endif return base; } void uwsgi_opt_config_py(char *opt, char *filename, void *foobar) { fprintf(stdout, "%s\n", uwsgi_get_config_py()); exit(0); } void uwsgi_opt_build_plugin(char *opt, char *directory, void *foobar) { uwsgi_build_plugin(directory); exit(1); } void uwsgi_opt_connect_and_read(char *opt, char *address, void *foobar) { char buf[8192]; int fd = uwsgi_connect(address, -1, 0); while (fd >= 0) { int ret = uwsgi_waitfd(fd, -1); if (ret <= 0) { exit(0); } ssize_t len = read(fd, buf, 8192); if (len <= 0) { exit(0); } uwsgi_log("%.*s", (int) len, buf); } uwsgi_error("uwsgi_connect()"); exit(1); } void uwsgi_opt_extract(char *opt, char *address, void *foobar) { size_t len = 0; char *buf; buf = uwsgi_open_and_read(address, &len, 0, NULL); if (len > 0) { if (write(1, buf, len) != (ssize_t) len) { uwsgi_error("write()"); exit(1); }; }; exit(0); } void uwsgi_print_sym(char *opt, char *symbol, void *foobar) { char **sym = dlsym(RTLD_DEFAULT, symbol); if (sym) { uwsgi_log("%s", *sym); exit(0); } char *symbol_start = uwsgi_concat2(symbol, "_start"); char *symbol_end = uwsgi_concat2(symbol, "_end"); char *sym_s = dlsym(RTLD_DEFAULT, symbol_start); char *sym_e = dlsym(RTLD_DEFAULT, symbol_end); if (sym_s && sym_e) { uwsgi_log("%.*s", sym_e - sym_s, sym_s); } exit(0); } void uwsgi_update_pidfiles() { if (uwsgi.pidfile) { uwsgi_write_pidfile(uwsgi.pidfile); } if (uwsgi.pidfile2) { uwsgi_write_pidfile(uwsgi.pidfile2); } if (uwsgi.safe_pidfile) { uwsgi_write_pidfile(uwsgi.safe_pidfile); } if (uwsgi.safe_pidfile2) { uwsgi_write_pidfile(uwsgi.safe_pidfile2); } } void uwsgi_opt_binary_append_data(char *opt, char *value, void *none) { size_t size; char *buf = uwsgi_open_and_read(value, &size, 0, NULL); uint64_t file_len = size; if (write(1, buf, size) != (ssize_t) size) { uwsgi_error("uwsgi_opt_binary_append_data()/write()"); exit(1); } if (write(1, &file_len, 8) != 8) { uwsgi_error("uwsgi_opt_binary_append_data()/write()"); exit(1); } exit(0); } uwsgi-2.0.29/core/websockets.c000066400000000000000000000360741477626554400162450ustar00rootroot00000000000000#include "uwsgi.h" /* uWSGI websockets functions sponsored by 20Tab S.r.l. */ extern struct uwsgi_server uwsgi; #define REQ_DATA wsgi_req->method_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri, wsgi_req->remote_addr_len, wsgi_req->remote_addr static struct uwsgi_buffer *uwsgi_websocket_message(struct wsgi_request *wsgi_req, char *msg, size_t len, uint8_t opcode) { struct uwsgi_buffer *ub = wsgi_req->websocket_send_buf; if (!ub) { wsgi_req->websocket_send_buf = uwsgi_buffer_new(10 + len); ub = wsgi_req->websocket_send_buf; } else { // reset the buffer ub->pos = 0; } if (uwsgi_buffer_u8(ub, opcode)) goto error; if (len < 126) { if (uwsgi_buffer_u8(ub, len)) goto error; } else if (len <= (uint16_t) 0xffff) { if (uwsgi_buffer_u8(ub, 126)) goto error; if (uwsgi_buffer_u16be(ub, len)) goto error; } else { if (uwsgi_buffer_u8(ub, 127)) goto error; if (uwsgi_buffer_u64be(ub, len)) goto error; } if (uwsgi_buffer_append(ub, msg, len)) goto error; return ub; error: return NULL; } static int uwsgi_websockets_ping(struct wsgi_request *wsgi_req) { if (uwsgi_response_write_body_do(wsgi_req, uwsgi.websockets_ping->buf, uwsgi.websockets_ping->pos)) { return -1; } wsgi_req->websocket_last_ping = uwsgi_now(); return 0; } static int uwsgi_websockets_pong(struct wsgi_request *wsgi_req) { return uwsgi_response_write_body_do(wsgi_req, uwsgi.websockets_pong->buf, uwsgi.websockets_pong->pos); } static int uwsgi_websockets_close(struct wsgi_request *wsgi_req) { return uwsgi_response_write_body_do(wsgi_req, uwsgi.websockets_close->buf, uwsgi.websockets_close->pos); } static int uwsgi_websockets_check_pingpong(struct wsgi_request *wsgi_req) { time_t now = uwsgi_now(); // first round if (wsgi_req->websocket_last_ping == 0) { return uwsgi_websockets_ping(wsgi_req); } // pong not received ? if (wsgi_req->websocket_last_pong < wsgi_req->websocket_last_ping) { if (now - wsgi_req->websocket_last_ping > uwsgi.websockets_pong_tolerance) { uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) no PONG received in %d seconds !!!\n", REQ_DATA, uwsgi.websockets_pong_tolerance); return -1; } return 0; } // pong received, send another ping if (now - wsgi_req->websocket_last_ping >= uwsgi.websockets_ping_freq) { return uwsgi_websockets_ping(wsgi_req); } return 0; } static int uwsgi_websocket_send_do(struct wsgi_request *wsgi_req, char *msg, size_t len, uint8_t opcode) { struct uwsgi_buffer *ub = uwsgi_websocket_message(wsgi_req, msg, len, opcode); if (!ub) return -1; return uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); } static int uwsgi_websocket_send_from_sharedarea_do(struct wsgi_request *wsgi_req, int id, uint64_t pos, uint64_t len, uint8_t opcode) { struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, pos); if (!sa) return -1; if (!len) { len = sa->honour_used ? sa->used-pos : ((sa->max_pos+1)-pos); } uwsgi_rlock(sa->lock); sa->hits++; struct uwsgi_buffer *ub = uwsgi_websocket_message(wsgi_req, sa->area, len, opcode); uwsgi_rwunlock(sa->lock); if (!ub) return -1; return uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); } int uwsgi_websocket_send(struct wsgi_request *wsgi_req, char *msg, size_t len) { if (wsgi_req->websocket_closed) { return -1; } ssize_t ret = uwsgi_websocket_send_do(wsgi_req, msg, len, 0x81); if (ret < 0) { wsgi_req->websocket_closed = 1; } return ret; } int uwsgi_websocket_send_from_sharedarea(struct wsgi_request *wsgi_req, int id, uint64_t pos, uint64_t len) { if (wsgi_req->websocket_closed) { return -1; } ssize_t ret = uwsgi_websocket_send_from_sharedarea_do(wsgi_req, id, pos, len, 0x81); if (ret < 0) { wsgi_req->websocket_closed = 1; } return ret; } int uwsgi_websocket_send_binary(struct wsgi_request *wsgi_req, char *msg, size_t len) { if (wsgi_req->websocket_closed) { return -1; } ssize_t ret = uwsgi_websocket_send_do(wsgi_req, msg, len, 0x82); if (ret < 0) { wsgi_req->websocket_closed = 1; } return ret; } int uwsgi_websocket_send_binary_from_sharedarea(struct wsgi_request *wsgi_req, int id, uint64_t pos, uint64_t len) { if (wsgi_req->websocket_closed) { return -1; } ssize_t ret = uwsgi_websocket_send_from_sharedarea_do(wsgi_req, id, pos, len, 0x82); if (ret < 0) { wsgi_req->websocket_closed = 1; } return ret; } static void uwsgi_websocket_parse_header(struct wsgi_request *wsgi_req) { uint8_t byte1 = wsgi_req->websocket_buf->buf[0]; uint8_t byte2 = wsgi_req->websocket_buf->buf[1]; wsgi_req->websocket_is_fin = byte1 >> 7; wsgi_req->websocket_opcode = byte1 & 0xf; wsgi_req->websocket_has_mask = byte2 >> 7; wsgi_req->websocket_size = byte2 & 0x7f; } static struct uwsgi_buffer *uwsgi_websockets_parse(struct wsgi_request *wsgi_req) { // de-mask buffer uint8_t *ptr = (uint8_t *) (wsgi_req->websocket_buf->buf + (wsgi_req->websocket_pktsize - wsgi_req->websocket_size)); size_t i; if (wsgi_req->websocket_has_mask) { uint8_t *mask = ptr-4; for(i=0;iwebsocket_size;i++) { ptr[i] = ptr[i] ^ mask[i%4]; } } struct uwsgi_buffer *ub = NULL; if (wsgi_req->websocket_opcode == 0) { if (uwsgi.websockets_continuation_buffer == NULL) { uwsgi_log("Error continuation with empty previous buffer"); goto error; } ub = uwsgi.websockets_continuation_buffer; } else { ub = uwsgi_buffer_new(wsgi_req->websocket_size); } if (uwsgi_buffer_append(ub, (char *) ptr, wsgi_req->websocket_size)) goto error; if (uwsgi_buffer_decapitate(wsgi_req->websocket_buf, wsgi_req->websocket_pktsize)) goto error; wsgi_req->websocket_phase = 0; wsgi_req->websocket_need = 2; if (wsgi_req->websocket_is_fin) { uwsgi.websockets_continuation_buffer = NULL; /// Freeing websockets_continuation_buffer is done by the caller return ub; } uwsgi.websockets_continuation_buffer = ub; /// Message is not complete, send empty dummy buffer to signal waiting for full message ub = uwsgi_buffer_new(1); uwsgi_buffer_append(ub, "\0", 1); return ub; error: uwsgi_buffer_destroy(ub); if (uwsgi.websockets_continuation_buffer != NULL && ub != uwsgi.websockets_continuation_buffer) { uwsgi_buffer_destroy(uwsgi.websockets_continuation_buffer); } uwsgi.websockets_continuation_buffer = NULL; return NULL; } static ssize_t uwsgi_websockets_recv_pkt(struct wsgi_request *wsgi_req, int nb) { int ret = -1; for(;;) { ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->websocket_buf->buf + wsgi_req->websocket_buf->pos, wsgi_req->websocket_buf->len - wsgi_req->websocket_buf->pos); if (rlen > 0) return rlen; if (rlen == 0) return -1; if (rlen < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) { if (nb) { if (uwsgi_websockets_check_pingpong(wsgi_req)) { return -1; } return 0; } goto wait; } uwsgi_req_error("uwsgi_websockets_recv_pkt()"); return -1; } wait: ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.websockets_ping_freq); if (ret > 0) { rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->websocket_buf->buf + wsgi_req->websocket_buf->pos, wsgi_req->websocket_buf->len - wsgi_req->websocket_buf->pos); if (rlen > 0) return rlen; if (rlen <= 0) return -1; } if (ret < 0) { uwsgi_req_error("uwsgi_websockets_recv_pkt()"); return -1; } // send unsolicited pong if (uwsgi_websockets_check_pingpong(wsgi_req)) { return -1; } } return -1; } static struct uwsgi_buffer *uwsgi_websocket_recv_do(struct wsgi_request *wsgi_req, int nb) { if (!wsgi_req->websocket_buf) { // this buffer will be destroyed on connection close wsgi_req->websocket_buf = uwsgi_buffer_new(uwsgi.page_size); // need 2 byte header wsgi_req->websocket_need = 2; } for(;;) { size_t remains = wsgi_req->websocket_buf->pos; // i have data; if (remains >= wsgi_req->websocket_need) { switch(wsgi_req->websocket_phase) { // header case 0: uwsgi_websocket_parse_header(wsgi_req); wsgi_req->websocket_pktsize = 2 + (wsgi_req->websocket_has_mask*4); if (wsgi_req->websocket_size == 126) { wsgi_req->websocket_need += 2; wsgi_req->websocket_phase = 1; wsgi_req->websocket_pktsize += 2; } else if (wsgi_req->websocket_size == 127) { wsgi_req->websocket_need += 8; wsgi_req->websocket_phase = 1; wsgi_req->websocket_pktsize += 8; } else { wsgi_req->websocket_phase = 2; } break; // size case 1: if (wsgi_req->websocket_size == 126) { wsgi_req->websocket_size = uwsgi_be16(wsgi_req->websocket_buf->buf+2); } else if (wsgi_req->websocket_size == 127) { wsgi_req->websocket_size = uwsgi_be64(wsgi_req->websocket_buf->buf+2); } else { uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) BUG error in websocket parser\n", REQ_DATA); return NULL; } if (wsgi_req->websocket_size > (uwsgi.websockets_max_size*1024)) { uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) invalid packet size received: %llu, max allowed: %llu\n", REQ_DATA, wsgi_req->websocket_size, uwsgi.websockets_max_size * 1024); return NULL; } wsgi_req->websocket_phase = 2; break; // mask check case 2: if (wsgi_req->websocket_has_mask) { wsgi_req->websocket_need += 4; wsgi_req->websocket_phase = 3; } else { wsgi_req->websocket_need += wsgi_req->websocket_size; wsgi_req->websocket_pktsize += wsgi_req->websocket_size; wsgi_req->websocket_phase = 4; } break; // mask case 3: wsgi_req->websocket_pktsize += wsgi_req->websocket_size; wsgi_req->websocket_need += wsgi_req->websocket_size; wsgi_req->websocket_phase = 4; break; // message case 4: switch (wsgi_req->websocket_opcode) { // message case 0: case 1: case 2: return uwsgi_websockets_parse(wsgi_req); // close case 0x8: uwsgi_websockets_close(wsgi_req); return NULL; // ping case 0x9: if (uwsgi_websockets_pong(wsgi_req)) { return NULL; } break; // pong case 0xA: wsgi_req->websocket_last_pong = uwsgi_now(); break; default: break; } // reset the status wsgi_req->websocket_phase = 0; wsgi_req->websocket_need = 2; // decapitate the buffer if (uwsgi_buffer_decapitate(wsgi_req->websocket_buf, wsgi_req->websocket_pktsize)) return NULL; break; // oops default: uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) BUG error in websocket parser\n", REQ_DATA); return NULL; } } // need more data else { if (uwsgi_buffer_ensure(wsgi_req->websocket_buf, uwsgi.page_size)) return NULL; ssize_t len = uwsgi_websockets_recv_pkt(wsgi_req, nb); if (len <= 0) { if (nb == 1 && len == 0) { // return an empty buffer to signal blocking event return uwsgi_buffer_new(0); } return NULL; } // update buffer size wsgi_req->websocket_buf->pos+=len; } } return NULL; } static void clear_continuation_buffer() { if (uwsgi.websockets_continuation_buffer != NULL) { uwsgi_buffer_destroy(uwsgi.websockets_continuation_buffer); uwsgi.websockets_continuation_buffer = NULL; } } struct uwsgi_buffer *uwsgi_websocket_recv(struct wsgi_request *wsgi_req) { if (wsgi_req->websocket_closed) { return NULL; } struct uwsgi_buffer *ub = uwsgi_websocket_recv_do(wsgi_req, 0); if (!ub) { clear_continuation_buffer(); wsgi_req->websocket_closed = 1; } return ub; } struct uwsgi_buffer *uwsgi_websocket_recv_nb(struct wsgi_request *wsgi_req) { if (wsgi_req->websocket_closed) { return NULL; } struct uwsgi_buffer *ub = uwsgi_websocket_recv_do(wsgi_req, 1); if (!ub) { clear_continuation_buffer(); wsgi_req->websocket_closed = 1; } return ub; } ssize_t uwsgi_websockets_simple_send(struct wsgi_request *wsgi_req, struct uwsgi_buffer *ub) { ssize_t len = wsgi_req->socket->proto_write(wsgi_req, ub->buf, ub->pos); if (wsgi_req->write_errors > 0) { return -1; } return len; } int uwsgi_websocket_handshake(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *origin, uint16_t origin_len, char *proto, uint16_t proto_len) { #ifdef UWSGI_SSL if (!key_len) { key = wsgi_req->http_sec_websocket_key; key_len = wsgi_req->http_sec_websocket_key_len; } if (key_len == 0) return -1; char sha1[20]; if (uwsgi_response_prepare_headers(wsgi_req, "101 Web Socket Protocol Handshake", 33)) return -1; if (uwsgi_response_add_header(wsgi_req, "Upgrade", 7, "WebSocket", 9)) return -1; if (uwsgi_response_add_header(wsgi_req, "Connection", 10, "Upgrade", 7)) return -1; // if origin was requested or proto_len is specified, send it back if (wsgi_req->http_origin_len > 0 || origin_len > 0) { if (!origin_len) { origin = wsgi_req->http_origin; origin_len = wsgi_req->http_origin_len; } if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Origin", 20, origin, origin_len)) return -1; } else { if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Origin", 20, "*", 1)) return -1; } // if protocol was requested or proto_len is specified, send it back if (wsgi_req->http_sec_websocket_protocol_len > 0 || proto_len > 0) { if (!proto_len) { proto = wsgi_req->http_sec_websocket_protocol; proto_len = wsgi_req->http_sec_websocket_protocol_len; } if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Protocol", 22, proto, proto_len)) return -1; } // generate websockets sha1 and encode it to base64 if (!uwsgi_sha1_2n(key, key_len, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", 36, sha1)) return -1; size_t b64_len = 0; char *b64 = uwsgi_base64_encode(sha1, 20, &b64_len); if (!b64) return -1; if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Accept", 20, b64, b64_len)) { free(b64); return -1; } free(b64); wsgi_req->websocket_last_pong = uwsgi_now(); return uwsgi_response_write_headers_do(wsgi_req); #else uwsgi_log("you need to build uWSGI with SSL support to use the websocket handshake api function !!!\n"); return -1; #endif } void uwsgi_websockets_init() { uwsgi.websockets_pong = uwsgi_buffer_new(2); uwsgi_buffer_append(uwsgi.websockets_pong, "\x8A\0", 2); uwsgi.websockets_ping = uwsgi_buffer_new(2); uwsgi_buffer_append(uwsgi.websockets_ping, "\x89\0", 2); uwsgi.websockets_close = uwsgi_buffer_new(2); uwsgi_buffer_append(uwsgi.websockets_close, "\x88\0", 2); uwsgi.websockets_ping_freq = 30; uwsgi.websockets_pong_tolerance = 3; uwsgi.websockets_max_size = 1024; uwsgi.websockets_continuation_buffer = NULL; } uwsgi-2.0.29/core/writer.c000066400000000000000000000557371477626554400154170ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; int uwsgi_response_add_content_length(struct wsgi_request *wsgi_req, uint64_t cl) { char buf[sizeof(UMAX64_STR)+1]; int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%llu", (unsigned long long) cl); if (ret <= 0 || ret >= (int) (sizeof(UMAX64_STR)+1)) { wsgi_req->write_errors++; return -1; } return uwsgi_response_add_header(wsgi_req, "Content-Length", 14, buf, ret); } int uwsgi_response_add_expires(struct wsgi_request *wsgi_req, uint64_t t) { // 30+1 char expires[31]; int len = uwsgi_http_date((time_t) t, expires); if (!len) { wsgi_req->write_errors++; return -1; } return uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, len); } int uwsgi_response_add_date(struct wsgi_request *wsgi_req, char *hkey, uint16_t hlen, uint64_t t) { // 30+1 char d[31]; int len = uwsgi_http_date((time_t) t, d); if (!len) { wsgi_req->write_errors++; return -1; } return uwsgi_response_add_header(wsgi_req, hkey, hlen, d, len); } int uwsgi_response_add_last_modified(struct wsgi_request *wsgi_req, uint64_t t) { // 30+1 char lm[31]; int len = uwsgi_http_date((time_t) t, lm); if (!len) { wsgi_req->write_errors++; return -1; } return uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, lm, len); } int uwsgi_response_add_content_range(struct wsgi_request *wsgi_req, int64_t start, int64_t end, int64_t cl) { char buf[6+(sizeof(UMAX64_STR)*3)+4]; int ret = -1; if (start == -1 && end == -1 && cl >= 0) { ret = snprintf(buf, sizeof(buf), "bytes */%lld", (long long) cl); } else if (start < 0 || end < start || end >= cl) { uwsgi_log("uwsgi_response_add_content_range is called with wrong arguments:" "start=%lld end=%lld content-length=%lld\n", start, end, cl); wsgi_req->write_errors++; return -1; } else { ret = snprintf(buf, sizeof(buf), "bytes %lld-%lld/%lld", (long long) start, (long long) end, (long long) cl); } if (ret <= 0 || ret >= (int) (6+(sizeof(UMAX64_STR)*3)+4)) { wsgi_req->write_errors++; return -1; } return uwsgi_response_add_header(wsgi_req, "Content-Range", 13, buf, ret); } int uwsgi_response_prepare_headers_int(struct wsgi_request *wsgi_req, int status) { char status_str[11]; uwsgi_num2str2(status, status_str); return uwsgi_response_prepare_headers(wsgi_req, status_str, 3); } // status could be NNN or NNN message int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status, uint16_t status_len) { if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || status_len < 3 || wsgi_req->write_errors) return -1; if (!wsgi_req->headers) { wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size); wsgi_req->headers->limit = uwsgi.response_header_limit; } // reset the buffer (could be useful for rollbacks...) wsgi_req->headers->pos = 0; // reset headers count wsgi_req->header_cnt = 0; struct uwsgi_buffer *hh = NULL; wsgi_req->status = uwsgi_str3_num(status); #ifdef UWSGI_ROUTING // apply error routes if (wsgi_req->is_error_routing == 0) { if (uwsgi_apply_error_routes(wsgi_req) == UWSGI_ROUTE_BREAK) { // from now on ignore write body requests... wsgi_req->ignore_body = 1; return -1; } wsgi_req->is_error_routing = 0; } #endif if (status_len <= 4) { char *new_sc = NULL; size_t new_sc_len = 0; uint16_t sc_len = 0; const char *sc = uwsgi_http_status_msg(status, &sc_len); if (sc) { new_sc = uwsgi_concat3n(status, 3, " ", 1, (char *)sc, sc_len); new_sc_len = 4+sc_len; } else { new_sc = uwsgi_concat2n(status, 3, " Unknown", 8); new_sc_len = 11; } hh = wsgi_req->socket->proto_prepare_headers(wsgi_req, new_sc, new_sc_len); free(new_sc); } else { hh = wsgi_req->socket->proto_prepare_headers(wsgi_req, status, status_len); } if (!hh) {wsgi_req->write_errors++; return -1;} if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error; uwsgi_buffer_destroy(hh); return 0; error: uwsgi_buffer_destroy(hh); wsgi_req->write_errors++; return -1; } //each protocol has its header generator static int uwsgi_response_add_header_do(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) { // pull/collect the header ? struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, uwsgi.pull_headers) { if (!uwsgi_strnicmp(key, key_len, usl->value, usl->custom)) { if (!uwsgi_req_append(wsgi_req, usl->custom_ptr, usl->custom2, value, value_len)) { wsgi_req->write_errors++ ; return -1; } return 0; } } uwsgi_foreach(usl, uwsgi.collect_headers) { if (!uwsgi_strnicmp(key, key_len, usl->value, usl->custom)) { if (!uwsgi_req_append(wsgi_req, usl->custom_ptr, usl->custom2, value, value_len)) { wsgi_req->write_errors++ ; return -1; } } } if (!wsgi_req->headers) { wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size); wsgi_req->headers->limit = uwsgi.response_header_limit; } struct uwsgi_buffer *hh = wsgi_req->socket->proto_add_header(wsgi_req, key, key_len, value, value_len); if (!hh) { wsgi_req->write_errors++ ; return -1;} if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error; wsgi_req->header_cnt++; uwsgi_buffer_destroy(hh); return 0; error: uwsgi_buffer_destroy(hh); wsgi_req->write_errors++; return -1; } int uwsgi_response_add_header(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) { if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || wsgi_req->write_errors) return -1; struct uwsgi_string_list *rh = uwsgi.remove_headers; while(rh) { if (!uwsgi_strnicmp(key, key_len, rh->value, rh->len)) { return 0; } rh = rh->next; } rh = wsgi_req->remove_headers; while(rh) { if (!uwsgi_strnicmp(key, key_len, rh->value, rh->len)) { return 0; } rh = rh->next; } return uwsgi_response_add_header_do(wsgi_req, key, key_len, value, value_len); } int uwsgi_response_add_header_force(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) { if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || wsgi_req->write_errors) return -1; return uwsgi_response_add_header_do(wsgi_req, key, key_len, value, value_len); } static int uwsgi_response_write_headers_do0(struct wsgi_request *wsgi_req) { if (wsgi_req->headers_sent || !wsgi_req->headers || wsgi_req->response_size || wsgi_req->write_errors) { return UWSGI_OK; } #ifdef UWSGI_ROUTING // apply response routes if (wsgi_req->is_response_routing == 0) { if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) { // from now on ignore write body requests... wsgi_req->ignore_body = 1; return -1; } wsgi_req->is_response_routing = 0; } #endif struct uwsgi_string_list *ah = uwsgi.additional_headers; while(ah) { if (uwsgi_response_add_header(wsgi_req, NULL, 0, ah->value, ah->len)) return -1; ah = ah->next; } ah = wsgi_req->additional_headers; while(ah) { if (uwsgi_response_add_header(wsgi_req, NULL, 0, ah->value, ah->len)) return -1; ah = ah->next; } if (wsgi_req->socket->proto_fix_headers(wsgi_req)) { wsgi_req->write_errors++ ; return -1;} return UWSGI_AGAIN; } int uwsgi_response_write_headers_do(struct wsgi_request *wsgi_req) { int ret = uwsgi_response_write_headers_do0(wsgi_req); if (ret != UWSGI_AGAIN) return ret; for(;;) { errno = 0; int ret = wsgi_req->socket->proto_write_headers(wsgi_req, wsgi_req->headers->buf, wsgi_req->headers->pos); if (ret < 0) { if (!uwsgi.ignore_write_errors) { uwsgi_req_error("uwsgi_response_write_headers_do()"); } wsgi_req->write_errors++; return -1; } if (ret == UWSGI_OK) { break; } if (!uwsgi_is_again()) continue; ret = uwsgi_wait_write_req(wsgi_req); if (ret < 0) { wsgi_req->write_errors++; return -1;} if (ret == 0) { uwsgi_log("uwsgi_response_write_headers_do() TIMEOUT !!!\n"); wsgi_req->write_errors++; return -1; } } wsgi_req->headers_size += wsgi_req->write_pos; // reset for the next write wsgi_req->write_pos = 0; wsgi_req->headers_sent = 1; return UWSGI_OK; } /* private function for highly optimized writes (1 single syscall for headers and body) */ static int uwsgi_response_writev_headers_and_body_do(struct wsgi_request *wsgi_req, char *buf, size_t len) { struct iovec iov[2]; int ret = uwsgi_response_write_headers_do0(wsgi_req); if (ret != UWSGI_AGAIN) return ret; iov[0].iov_base = wsgi_req->headers->buf; iov[0].iov_len = wsgi_req->headers->pos; iov[1].iov_base = buf; iov[1].iov_len = len; size_t iov_len = 2; for(;;) { errno = 0; // no need to use writev if a single iovec remains if (iov_len == 1) { buf = iov[0].iov_base; len = iov[0].iov_len; // update counters wsgi_req->headers_size += wsgi_req->headers->pos; wsgi_req->headers_sent = 1; wsgi_req->response_size += wsgi_req->write_pos - wsgi_req->headers_size; wsgi_req->write_pos = 0; goto fallback; } int ret = wsgi_req->socket->proto_writev(wsgi_req, iov, &iov_len); if (ret < 0) { if (!uwsgi.ignore_write_errors) { uwsgi_req_error("uwsgi_response_writev_headers_and_body_do()"); } wsgi_req->write_errors++; return -1; } if (ret == UWSGI_OK) { break; } if (!uwsgi_is_again()) continue; ret = uwsgi_wait_write_req(wsgi_req); if (ret < 0) { wsgi_req->write_errors++; return -1;} if (ret == 0) { uwsgi_log("uwsgi_response_writev_headers_and_body_do() TIMEOUT !!!\n"); wsgi_req->write_errors++; return -1; } } wsgi_req->headers_size += wsgi_req->headers->pos; wsgi_req->response_size += len; wsgi_req->headers_sent = 1; // reset for the next write wsgi_req->write_pos = 0; return UWSGI_OK; fallback: for(;;) { errno = 0; int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len); if (ret < 0) { if (!uwsgi.ignore_write_errors) { // here we use the parent name uwsgi_req_error("uwsgi_response_write_body_do()"); } wsgi_req->write_errors++; return -1; } if (ret == UWSGI_OK) { break; } if (!uwsgi_is_again()) continue; ret = uwsgi_wait_write_req(wsgi_req); if (ret < 0) { wsgi_req->write_errors++; return -1;} if (ret == 0) { // here we use the parent name uwsgi_log("uwsgi_response_write_body_do() TIMEOUT !!!\n"); wsgi_req->write_errors++; return -1; } } wsgi_req->response_size += wsgi_req->write_pos; // reset for the next write wsgi_req->write_pos = 0; return UWSGI_OK; } // this is the function called by all request plugins to send chunks to the client int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_t len) { if (wsgi_req->write_errors) return -1; if (wsgi_req->ignore_body) return UWSGI_OK; #ifdef UWSGI_ROUTING // special case here, we could need to set transformations before if (!wsgi_req->headers_sent) { // apply response routes if (wsgi_req->is_response_routing == 0) { if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) { // from now on ignore write body requests... wsgi_req->ignore_body = 1; return -1; } wsgi_req->is_response_routing = 0; } } #endif // if the transformation chain returns 1, we are in buffering mode if (wsgi_req->transformed_chunk_len == 0 && wsgi_req->transformations) { int t_ret = uwsgi_apply_transformations(wsgi_req, buf, len); if (t_ret == 0) { buf = wsgi_req->transformed_chunk; len = wsgi_req->transformed_chunk_len; // reset transformation wsgi_req->transformed_chunk = NULL; wsgi_req->transformed_chunk_len = 0; goto write; } if (t_ret == 1) { return UWSGI_OK; } wsgi_req->write_errors++; return -1; } write: // send headers if not already sent if (!wsgi_req->headers_sent) { if (wsgi_req->socket->proto_writev && len > 0 && wsgi_req->headers) { return uwsgi_response_writev_headers_and_body_do(wsgi_req, buf, len); } int ret = uwsgi_response_write_headers_do(wsgi_req); if (ret == UWSGI_OK) goto sendbody; if (ret == UWSGI_AGAIN) return UWSGI_AGAIN; wsgi_req->write_errors++; return -1; } sendbody: if (len == 0) return UWSGI_OK; for(;;) { errno = 0; int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len); if (ret < 0) { if (!uwsgi.ignore_write_errors) { uwsgi_req_error("uwsgi_response_write_body_do()"); } wsgi_req->write_errors++; return -1; } if (ret == UWSGI_OK) { break; } if (!uwsgi_is_again()) continue; ret = uwsgi_wait_write_req(wsgi_req); if (ret < 0) { wsgi_req->write_errors++; return -1;} if (ret == 0) { uwsgi_log("uwsgi_response_write_body_do() TIMEOUT !!!\n"); wsgi_req->write_errors++; return -1; } } wsgi_req->response_size += wsgi_req->write_pos; // reset for the next write wsgi_req->write_pos = 0; return UWSGI_OK; } int uwsgi_response_writev_body_do(struct wsgi_request *wsgi_req, struct iovec *iov, size_t len) { if (wsgi_req->write_errors) return -1; if (wsgi_req->ignore_body) return UWSGI_OK; #ifdef UWSGI_ROUTING // special case here, we could need to set transformations before if (!wsgi_req->headers_sent) { // apply response routes if (wsgi_req->is_response_routing == 0) { if (uwsgi_apply_response_routes(wsgi_req) == UWSGI_ROUTE_BREAK) { // from now on ignore write body requests... wsgi_req->ignore_body = 1; return -1; } wsgi_req->is_response_routing = 0; } } #endif size_t i; int buffering = 0; // transformations apply to every vector for(i=0;itransformed_chunk_len == 0 && wsgi_req->transformations) { int t_ret = uwsgi_apply_transformations(wsgi_req, iov[i].iov_base, iov[i].iov_len); if (t_ret == 0) { iov[i].iov_base = wsgi_req->transformed_chunk; iov[i].iov_len = wsgi_req->transformed_chunk_len; // reset transformation wsgi_req->transformed_chunk = NULL; wsgi_req->transformed_chunk_len = 0; goto write; } if (t_ret == 1) { buffering = 1; continue; } wsgi_req->write_errors++; return -1; } } if (buffering) return UWSGI_OK; write: // send headers if not already sent if (!wsgi_req->headers_sent) { int ret = uwsgi_response_write_headers_do(wsgi_req); if (ret == UWSGI_OK) goto sendbody; if (ret == UWSGI_AGAIN) return UWSGI_AGAIN; wsgi_req->write_errors++; return -1; } sendbody: if (len == 0) return UWSGI_OK; // unfortunately vector based I/O cannot be accomplished on all protocols if (!wsgi_req->socket->proto_writev) goto fallback; // we use a copy to avoid mess size_t iov_len = len; for(;;) { errno = 0; int ret = wsgi_req->socket->proto_writev(wsgi_req, iov, &iov_len); if (ret < 0) { if (!uwsgi.ignore_write_errors) { uwsgi_req_error("uwsgi_response_writev_body_do()"); } wsgi_req->write_errors++; return -1; } if (ret == UWSGI_OK) { break; } if (!uwsgi_is_again()) continue; ret = uwsgi_wait_write_req(wsgi_req); if (ret < 0) { wsgi_req->write_errors++; return -1;} if (ret == 0) { uwsgi_log("uwsgi_response_writev_body_do() TIMEOUT !!!\n"); wsgi_req->write_errors++; return -1; } } goto done; fallback: for(i=0;isocket->proto_write(wsgi_req, iov[i].iov_base, iov[i].iov_len); if (ret < 0) { if (!uwsgi.ignore_write_errors) { uwsgi_req_error("uwsgi_response_writev_body_do()"); } wsgi_req->write_errors++; return -1; } if (ret == UWSGI_OK) { break; } if (!uwsgi_is_again()) continue; ret = uwsgi_wait_write_req(wsgi_req); if (ret < 0) { wsgi_req->write_errors++; return -1;} if (ret == 0) { uwsgi_log("uwsgi_response_writev_body_do() TIMEOUT !!!\n"); wsgi_req->write_errors++; return -1; } } } done: wsgi_req->response_size += wsgi_req->write_pos; // reset for the next write wsgi_req->write_pos = 0; return UWSGI_OK; } int uwsgi_response_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) { return uwsgi_response_sendfile_do_can_close(wsgi_req, fd, pos, len, 1); } int uwsgi_response_sendfile_do_can_close(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len, int can_close) { if (fd == wsgi_req->sendfile_fd) can_close = 0; if (wsgi_req->write_errors) { if (can_close) close(fd); return -1; } if (wsgi_req->ignore_body) { if (can_close) close(fd); return UWSGI_OK; } if (!wsgi_req->headers_sent) { int ret = uwsgi_response_write_headers_do(wsgi_req); if (ret == UWSGI_OK) goto sendfile; if (ret == UWSGI_AGAIN) return UWSGI_AGAIN; wsgi_req->write_errors++; if (can_close) close(fd); return -1; } sendfile: if (len == 0) { struct stat st; if (fstat(fd, &st)) { uwsgi_req_error("uwsgi_response_sendfile_do()/fstat()"); wsgi_req->write_errors++; if (can_close) close(fd); return -1; } if (pos >= (size_t)st.st_size) { if (can_close) close(fd); return UWSGI_OK; } len = st.st_size; } if (wsgi_req->socket->can_offload) { // of we cannot close the socket (before the app will close it later) // let's dup it if (!can_close) { int tmp_fd = dup(fd); if (tmp_fd < 0) { uwsgi_req_error("uwsgi_response_sendfile_do()/dup()"); wsgi_req->write_errors++; return -1; } fd = tmp_fd; can_close = 1; } if (!uwsgi_offload_request_sendfile_do(wsgi_req, fd, pos, len)) { wsgi_req->via = UWSGI_VIA_OFFLOAD; wsgi_req->response_size += len; return 0; } wsgi_req->write_errors++; if (can_close) close(fd); return -1; } wsgi_req->via = UWSGI_VIA_SENDFILE; for(;;) { errno = 0; int ret = wsgi_req->socket->proto_sendfile(wsgi_req, fd, pos, len); if (ret < 0) { if (!uwsgi.ignore_write_errors) { uwsgi_req_error("uwsgi_response_sendfile_do()"); } wsgi_req->write_errors++; if (can_close) close(fd); return -1; } if (ret == UWSGI_OK) { break; } if (!uwsgi_is_again()) continue; ret = uwsgi_wait_write_req(wsgi_req); if (ret < 0) { wsgi_req->write_errors++; if (can_close) close(fd); return -1; } if (ret == 0) { uwsgi_log("uwsgi_response_sendfile_do() TIMEOUT !!!\n"); wsgi_req->write_errors++; if (can_close) close(fd); return -1; } } wsgi_req->response_size += wsgi_req->write_pos; // reset for the next write wsgi_req->write_pos = 0; // close the file descriptor if (can_close) close(fd); return UWSGI_OK; } int uwsgi_simple_wait_write_hook(int fd, int timeout) { struct pollfd upoll; timeout = timeout * 1000; upoll.fd = fd; upoll.events = POLLOUT; upoll.revents = 0; int ret = poll(&upoll, 1, timeout); if (ret > 0) { if (upoll.revents & POLLOUT) { return 1; } return -1; } if (ret < 0) { uwsgi_error("uwsgi_simple_wait_write_hook()/poll()"); } return ret; } /* simplified write to client (generally used as fallback) */ int uwsgi_simple_write(struct wsgi_request *wsgi_req, char *buf, size_t len) { wsgi_req->write_pos = 0; for(;;) { errno = 0; int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len); if (ret < 0) { if (!uwsgi.ignore_write_errors) { uwsgi_req_error("uwsgi_simple_write()"); } wsgi_req->write_errors++; return -1; } if (ret == UWSGI_OK) { break; } if (!uwsgi_is_again()) continue; ret = uwsgi_wait_write_req(wsgi_req); if (ret < 0) { wsgi_req->write_errors++; return -1;} if (ret == 0) { uwsgi_log("uwsgi_simple_write() TIMEOUT !!!\n"); wsgi_req->write_errors++; return -1; } } return 0; } uwsgi-2.0.29/core/xmlconf.c000066400000000000000000000145611477626554400155370ustar00rootroot00000000000000#ifdef UWSGI_XML #include "uwsgi.h" extern struct uwsgi_server uwsgi; #ifdef UWSGI_XML_LIBXML2 #include #include void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, char *magic_table[]) { xmlDoc *doc = NULL; xmlNode *element = NULL; xmlNode *node = NULL; xmlChar *node_mode; char *colon; char *xml_id; char *xml_content; size_t xml_size = 0; LIBXML_TEST_VERSION if (uwsgi_check_scheme(filename)) { colon = uwsgi_get_last_char(filename, '/'); colon = uwsgi_get_last_char(colon, ':'); } else { colon = uwsgi_get_last_char(filename, ':'); } if (colon) { colon[0] = 0; colon++; if (*colon == 0) { uwsgi_log("invalid xml id\n"); exit(1); } uwsgi_log("[uWSGI] using xml uwsgi id: %s\n", colon); } xml_content = uwsgi_open_and_read(filename, &xml_size, 0, magic_table); doc = xmlReadMemory(xml_content, xml_size, filename, NULL, 0); if (doc == NULL) { uwsgi_log("[uWSGI] could not parse file %s.\n", filename); exit(1); } uwsgi_log_initial("[uWSGI] parsing config file %s\n", filename); element = xmlDocGetRootElement(doc); if (element == NULL) { uwsgi_log("[uWSGI] invalid xml config file.\n"); exit(1); } if (strcmp((char *) element->name, "uwsgi")) { for (node = element->children; node; node = node->next) { element = NULL; if (node->type == XML_ELEMENT_NODE) { if (!strcmp((char *) node->name, "uwsgi")) { xml_id = (char *) xmlGetProp(node, (const xmlChar *) "id"); if (colon && xml_id) { if (strcmp(colon, xml_id)) { continue; } } element = node; break; } } } if (!element) { uwsgi_log("[uWSGI] invalid xml root element, expected.\n"); exit(1); } } // first check for options for (node = element->children; node; node = node->next) { node_mode = xmlGetProp(node, (const xmlChar *) "mode"); if (uwsgi.mode && node_mode) { if (strcmp(uwsgi.mode, (char *) node_mode)) { continue; } } xml_id = (char *) xmlGetProp(node, (const xmlChar *) "id"); if (colon && xml_id) { if (strcmp(colon, xml_id)) { continue; } } if (node->type == XML_CDATA_SECTION_NODE) { if (node->content) { add_exported_option((char *) "eval", strdup((char *) node->content), 0); } } else if (node->type == XML_ELEMENT_NODE) { if (!strcmp((char *) node->name, (char *) "app")) { char *mountpoint = (char *) xmlGetProp(node, (const xmlChar *) "mountpoint"); char *domain = (char *) xmlGetProp(node, (const xmlChar *) "domain"); if (!node->children) { add_exported_option("app", strdup(""), 0); } else if (node->children && node->children->content && !node->children->next) { char *opt_value = strdup((char *) node->children->content); if (mountpoint) { opt_value = uwsgi_concat3(mountpoint, "=", opt_value); } else if (domain) { opt_value = uwsgi_concat3(domain, "|=", opt_value); } add_exported_option("mount", opt_value, 0); add_exported_option("app", strdup(""), 0); } else if (node->children && node->children->next && node->children->next->children && node->children->next->children->content) { char *opt_value = strdup((char *) node->children->next->children->content); if (mountpoint) { opt_value = uwsgi_concat3(mountpoint, "=", opt_value); } else if (domain) { opt_value = uwsgi_concat3(domain, "|=", opt_value); } add_exported_option("mount", opt_value, 0); add_exported_option("app", strdup(""), 0); } } else { if (node->children) { add_exported_option(strdup((char *) node->name), strdup((char *) node->children->content), 0); } else { add_exported_option(strdup((char *) node->name), strdup("1"), 0); } } } } /* We can safely free resources */ if (colon) colon[0] = ':'; xmlFreeDoc(doc); xmlCleanupParser(); } #endif #ifdef UWSGI_XML_EXPAT #include int uwsgi_xml_found_stanza = 0; char *uwsgi_xml_found_opt_key = NULL; static void startElement(void *xml_id, const XML_Char * name, const XML_Char ** attrs) { if (!uwsgi_xml_found_stanza) { if (xml_id) { if (!attrs[0]) return; if (!attrs[1]) return; if (strcmp("id", attrs[0])) return; if (strcmp((char *) xml_id, attrs[1])) return; } if (!strcmp("uwsgi", name)) uwsgi_xml_found_stanza = 1; } else { uwsgi_xml_found_opt_key = (char *) name; } } static void textElement(void *xml_id, const char *s, int len) { if (!uwsgi_xml_found_stanza) return; if (uwsgi_xml_found_opt_key) { add_exported_option(strdup(uwsgi_xml_found_opt_key), uwsgi_concat2n((char *) s, len, (char *) "", 0), 0); uwsgi_xml_found_opt_key = NULL; } } static void endElement(void *xml_id, const XML_Char * name) { if (!uwsgi_xml_found_stanza) return; if (!strcmp(name, "uwsgi")) { uwsgi_xml_found_stanza = 0; return; } if (!uwsgi_xml_found_opt_key) return; add_exported_option(strdup(uwsgi_xml_found_opt_key), strdup("1"), 0); uwsgi_xml_found_opt_key = NULL; } void uwsgi_xml_config(char *filename, struct wsgi_request *wsgi_req, char *magic_table[]) { char *colon; char *xml_content; size_t xml_size = 0; int done = 0; if (uwsgi_check_scheme(filename)) { colon = uwsgi_get_last_char(filename, '/'); colon = uwsgi_get_last_char(colon, ':'); } else { colon = uwsgi_get_last_char(filename, ':'); } if (colon) { colon[0] = 0; colon++; if (*colon == 0) { uwsgi_log("invalid xml id\n"); exit(1); } uwsgi_log("[uWSGI] using xml uwsgi id: %s\n", colon); } xml_content = uwsgi_open_and_read(filename, &xml_size, 0, magic_table); uwsgi_log("[uWSGI] parsing config file %s\n", filename); XML_Parser parser = XML_ParserCreate(NULL); XML_SetUserData(parser, NULL); if (colon) { XML_SetUserData(parser, colon); } XML_SetElementHandler(parser, startElement, endElement); XML_SetCharacterDataHandler(parser, textElement); do { if (!XML_Parse(parser, xml_content, xml_size, done)) { if (XML_GetErrorCode(parser) != XML_ERROR_JUNK_AFTER_DOC_ELEMENT) { uwsgi_log("unable to parse xml file: %s (line %d)\n", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser)); exit(1); } else { break; } } } while (!done); if (colon) colon[0] = ':'; // we can safely free, as we have a copy of datas XML_ParserFree(parser); } #endif #else #warning "*** XML configuration support is disabled ***" #endif uwsgi-2.0.29/core/yaml.c000066400000000000000000000120711477626554400150250ustar00rootroot00000000000000#ifdef UWSGI_YAML #include "uwsgi.h" extern struct uwsgi_server uwsgi; #ifndef UWSGI_LIBYAML /* yaml file must be read ALL into memory. This memory must not be freed for all the server lifecycle */ void yaml_rstrip(char *line) { off_t i; for (i = strlen(line) - 1; i >= 0; i--) { if (line[i] == ' ' || line[i] == '\t') { line[i] = 0; continue; } break; } } char *yaml_lstrip(char *line) { off_t i; char *ptr = line; for (i = 0; i < (int) strlen(line); i++) { if (line[i] == ' ' || line[i] == '\t' || line[i] == '\r') { ptr++; continue; } break; } return ptr; } int yaml_get_depth(char *line) { off_t i; int depth = 0; for (i = 0; i < (int) strlen(line); i++) { if (line[i] == ' ') { depth++; continue; } else if (line[i] == '\t' || line[i] == '\r') { depth += 8; continue; } break; } return depth; } char *yaml_get_line(char *yaml, size_t size) { size_t i; char *ptr = yaml; int comment = 0; for (i = 0; i < size; i++) { ptr++; if (yaml[i] == '#') { yaml[i] = 0; comment = 1; } else if (yaml[i] == '\n') { yaml[i] = 0; return ptr; } else if (comment) { yaml[i] = 0; } } // check if it is a stupid file without \n at the end if (ptr > yaml) { return ptr; } return NULL; } #else #include #endif void uwsgi_yaml_config(char *file, char *magic_table[]) { size_t len = 0; char *yaml; int in_uwsgi_section = 0; char *key = NULL; char *val = NULL; char *section_asked = "uwsgi"; char *colon; if (uwsgi_check_scheme(file)) { colon = uwsgi_get_last_char(file, '/'); colon = uwsgi_get_last_char(colon, ':'); } else { colon = uwsgi_get_last_char(file, ':'); } if (colon) { colon[0] = 0; if (colon[1] != 0) { section_asked = colon + 1; } } uwsgi_log_initial("[uWSGI] getting YAML configuration from %s\n", file); yaml = uwsgi_open_and_read(file, &len, 1, magic_table); #ifdef UWSGI_LIBYAML yaml_parser_t parser; yaml_token_t token; int status = 0; int parsing = 1; if (!yaml_parser_initialize(&parser)) { uwsgi_log("unable to initialize YAML parser (libyaml)\n"); exit(1); } yaml_parser_set_input_string(&parser, (unsigned char *) yaml, (size_t) len - 1); while (parsing) { if (!yaml_parser_scan(&parser, &token)) { uwsgi_log("error parsing YAML file: %s (%c)\n", parser.problem, yaml[parser.problem_offset]); exit(1); } switch (token.type) { case YAML_STREAM_END_TOKEN: parsing = 0; break; case YAML_KEY_TOKEN: status = 1; break; case YAML_VALUE_TOKEN: status = 2; break; case YAML_FLOW_SEQUENCE_START_TOKEN: case YAML_BLOCK_SEQUENCE_START_TOKEN: if (in_uwsgi_section) in_uwsgi_section++; // fallthrough case YAML_FLOW_ENTRY_TOKEN: case YAML_BLOCK_ENTRY_TOKEN: status = 3; // inside a sequence break; case YAML_BLOCK_MAPPING_START_TOKEN: if (in_uwsgi_section) { in_uwsgi_section++; break; } if (key) { if (!strcmp(section_asked, key)) { in_uwsgi_section = 1; } } break; case YAML_BLOCK_END_TOKEN: case YAML_FLOW_SEQUENCE_END_TOKEN: if (in_uwsgi_section) parsing = !!(--in_uwsgi_section); key = NULL; status = 0; break; case YAML_SCALAR_TOKEN: if (status == 1) { key = (char *) token.data.scalar.value; } else if (status == 2 || status == 3) { val = (char *) token.data.scalar.value; if (key && val && in_uwsgi_section) { add_exported_option(key, val, 0); } // If this was the scalar of a value token, forget the state. if (status == 2) { key = NULL; status = 0; } } else { uwsgi_log("unsupported YAML token %d in %s block\n", token.type, section_asked); parsing = 0; break; } break; default: status = 0; } } #else int depth; int current_depth = 0; char *yaml_line; char *section = ""; while (len) { yaml_line = yaml_get_line(yaml, len); if (yaml_line == NULL) { break; } // skip empty line if (yaml[0] == 0) goto next; depth = yaml_get_depth(yaml); if (depth <= current_depth) { current_depth = depth; // end the parsing cycle if (in_uwsgi_section) return; } else if (depth > current_depth && !in_uwsgi_section) { goto next; } key = yaml_lstrip(yaml); // skip empty line if (key[0] == 0) goto next; // skip list and {} defined dict if (key[0] == '-' || key[0] == '[' || key[0] == '{') { if (in_uwsgi_section) return; goto next; } if (!in_uwsgi_section) { section = strchr(key, ':'); if (!section) goto next; section[0] = 0; if (!strcmp(key, section_asked)) { in_uwsgi_section = 1; } } else { // get dict value val = strstr(key, ": "); if (!val) { val = strstr(key, ":\t"); } if (!val) return; // get the right key val[0] = 0; // yeah overengeneering.... yaml_rstrip(key); val = yaml_lstrip(val + 2); yaml_rstrip(val); //uwsgi_log("YAML: %s = %s\n", key, val); add_exported_option((char *) key, val, 0); } next: len -= (yaml_line - yaml); yaml += (yaml_line - yaml); } #endif if (colon) colon[0] = ':'; } #endif uwsgi-2.0.29/core/zeus.c000066400000000000000000000037731477626554400150620ustar00rootroot00000000000000/* *** WORK IN PROGRESS *** Zeus mode A Zeus instance can load all of the available imperial monitor plugins, but instead of spawning vassals it delegates actions to Emperors connected to it. The Zeus instance try to distribute vassals evenly between Emperors. Emperors register to one (ore more, maybe...) Zeus instance, passing various informations (like the maximum number of vassals it can manage) to spawn a Zeus: # unencrypted mode uwsgi --zeus "192.168.173.17:4040 /etc/uwsgi/vassals" # crypted mode uwsgi --zeus "192.168.173.17:4040,foobar.crt,foobar.key /etc/uwsgi/vassals" # crypted + authentication mode uwsgi --zeus "192.168.173.17:4040,foobar.crt,foobar.key,clients.pem /etc/uwsgi/vassals" to connect an Emperor to Zeus # unencrypted mode uwsgi --emperor zeus:192.168.173.17:4040 # crypted mode uwsgi --emperor zeus-ssl:192.168.173.17:4040 # crypted + authentication mode uwsgi --emperor zeus-ssl:192.168.173.17:4040,myself.key Protocol (each message is a basic uwsgi packet: modifier1 pktsize modifier2 payload) modifier2 identifies the type of the message 0 -> I_AM_ALIVE {node: 'node001', max_vassals: '100', running_vassals: '17'} [ emperor -> zeus ] 1 -> NEW_VASSAL {name: 'foobar.ini'} [ zeus -> the choosen emperor ] 2 -> ACCEPTED_VASSAL {name: 'foobar.ini'} [ emperor -> zeus ] 3 -> CONFIG_CHUNK {name: 'foobar.ini', body: '[uwsgi].....'} [ zeus -> the choosen emperor ] 4 -> CONFIG_END {name: 'foobar.ini'} [ zeus -> the choosen emperor ] 5 -> VASSAL_SPAWNED {name: 'foobar.ini'} [the choosen emperor -> zeus] 6 -> VASSAL_REJECTED {name: 'foobar.ini'} [the choosen emperor -> zeus] 7 -> VASSAL_RELOAD {name: 'foobar.ini'} [ zeus -> the choosen emperor ] 8 -> VASSAL_UPDATE {name: 'foobar.ini'} [ zeus -> the choosen emperor ] 9 -> VASSAL_DESTROY {name: 'foobar.ini'} [ zeus -> the choosen emperor ] 10 -> VASSAL_RELOADED {name: 'foobar.ini'} [the choosen emperor -> zeus] 11 -> VASSAL_DESTROYED {name: 'foobar.ini'} [the choosen emperor -> zeus] */ uwsgi-2.0.29/core/zlib.c000066400000000000000000000105041477626554400150220ustar00rootroot00000000000000#include "uwsgi.h" char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 }; extern struct uwsgi_server uwsgi; char *uwsgi_gzip_chunk(z_stream *z, uint32_t *crc32, char *buf, size_t len, size_t *dlen) { uwsgi_crc32(crc32, buf, len); return uwsgi_deflate(z, buf, len, dlen); } struct uwsgi_buffer *uwsgi_gzip(char *buf, size_t len) { z_stream z; struct uwsgi_buffer *ub = NULL; uint32_t gzip_crc32 = 0; char *gzipped = NULL; char *gzipped0 = NULL; size_t dlen = 0; size_t dlen0 = 0; uwsgi_crc32(&gzip_crc32, NULL, 0); if (uwsgi_deflate_init(&z, NULL, 0)) return NULL; uwsgi_crc32(&gzip_crc32, buf, len); gzipped = uwsgi_deflate(&z, buf, len, &dlen); if (!gzipped) goto end; gzipped0 = uwsgi_deflate(&z, NULL, 0, &dlen0); if (!gzipped0) goto end; ub = uwsgi_buffer_new(10 + dlen + dlen0 + 8); if (uwsgi_buffer_append(ub, gzheader, 10)) goto end; if (uwsgi_buffer_append(ub, gzipped, dlen)) goto end; if (uwsgi_buffer_append(ub, gzipped0, dlen0)) goto end; if (uwsgi_buffer_u32le(ub, gzip_crc32)) goto end; if (uwsgi_buffer_u32le(ub, len)) goto end; end: if (gzipped) free(gzipped); if (gzipped0) free(gzipped0); deflateEnd(&z); return ub; } struct uwsgi_buffer *uwsgi_zlib_decompress(char *buf, size_t len) { z_stream z; z.zalloc = Z_NULL; z.zfree = Z_NULL; z.opaque = Z_NULL; if (inflateInit(&z) != Z_OK) { return NULL; } struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); unsigned char out[8192]; z.next_in = (unsigned char *)buf; z.avail_in = len; z.next_out = out; do { z.avail_out = 8192; z.next_out = out; int ret = inflate(&z, Z_NO_FLUSH); if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) { uwsgi_buffer_destroy(ub); ub = NULL; goto end; } if (uwsgi_buffer_append(ub, (char *)out, 8192 - z.avail_out)) { uwsgi_buffer_destroy(ub); ub = NULL; goto end; } } while (z.avail_out == 0); end: inflateEnd(&z); return ub; } int uwsgi_deflate_init(z_stream *z, char *dict, size_t dict_len) { z->zalloc = Z_NULL; z->zfree = Z_NULL; z->opaque = Z_NULL; if (deflateInit2(z, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 9, Z_DEFAULT_STRATEGY) != Z_OK) { //if (deflateInit(z, Z_DEFAULT_COMPRESSION)) { return -1; } if (dict && dict_len) { if (deflateSetDictionary(z, (Bytef *) dict, dict_len) != Z_OK) { return -1; } } return 0; } int uwsgi_inflate_init(z_stream *z, char *dict, size_t dict_len) { z->zalloc = Z_NULL; z->zfree = Z_NULL; z->opaque = Z_NULL; if (inflateInit2(z, 16+MAX_WBITS) != Z_OK) { return -1; } if (dict && dict_len) { if (inflateSetDictionary(z, (Bytef *) dict, dict_len) != Z_OK) { return -1; } } return 0; } int uwsgi_gzip_prepare(z_stream *z, char *dict, size_t dict_len, uint32_t *crc32) { uwsgi_crc32(crc32, NULL, 0); if (uwsgi_deflate_init(z, NULL, 0)) return -1; return 0; } // fix and free a gzip stream int uwsgi_gzip_fix(z_stream *z, uint32_t crc32, struct uwsgi_buffer *ub, size_t len) { size_t dlen0 = 0; char *gzipped0 = uwsgi_deflate(z, NULL, 0, &dlen0); if (!gzipped0) goto end; if (uwsgi_buffer_append(ub, gzipped0, dlen0)) goto end; free(gzipped0); if (uwsgi_buffer_u32le(ub, crc32)) goto end2; if (uwsgi_buffer_u32le(ub, len)) goto end2; deflateEnd(z); return 0; end: if (gzipped0) free(gzipped0); end2: deflateEnd(z); return -1; } char *uwsgi_deflate(z_stream *z, char *buf, size_t len, size_t *dlen) { // calculate the amount of bytes needed for output (+30 should be enough) Bytef *dbuf = uwsgi_malloc(len+30); z->avail_in = len; z->next_in = (Bytef *) buf; z->avail_out = len+30; z->next_out = dbuf; if (len > 0) { if (deflate(z, Z_SYNC_FLUSH) != Z_OK) { free(dbuf); return NULL; } } else { if (deflate(z, Z_FINISH) != Z_STREAM_END) { free(dbuf); return NULL; } deflateEnd(z); } *dlen = (z->next_out - dbuf); return (char *) dbuf; } void uwsgi_crc32(uint32_t *ctx, char *buf, size_t len) { if (!buf) { *ctx = crc32(*ctx, Z_NULL, 0); } else { *ctx = crc32(*ctx, (const Bytef *) buf, len); } } uwsgi-2.0.29/examples/000077500000000000000000000000001477626554400146045ustar00rootroot00000000000000uwsgi-2.0.29/examples/bootstrap.py000066400000000000000000000002001477626554400171630ustar00rootroot00000000000000import sys import uwsgi print("i am the bootstrap for uwsgi.SymbolsImporter") sys.meta_path.insert(0, uwsgi.SymbolsImporter()) uwsgi-2.0.29/examples/bootstrap2.py000066400000000000000000000001331477626554400172520ustar00rootroot00000000000000import sys import uwsgi sys.meta_path.insert(0, uwsgi.SymbolsZipImporter("pygments_zip")) uwsgi-2.0.29/examples/bootstrap3.py000066400000000000000000000002721477626554400172570ustar00rootroot00000000000000import sys import uwsgi sys.meta_path.insert(0, uwsgi.SymbolsZipImporter("django_zip:djenv/lib/python2.6/site-packages")) sys.meta_path.insert(0, uwsgi.SymbolsZipImporter("djapp_zip")) uwsgi-2.0.29/examples/bootstrap4.py000066400000000000000000000001201477626554400172500ustar00rootroot00000000000000import sys import uwsgi sys.meta_path.insert(0, uwsgi.ZipImporter("data://0")) uwsgi-2.0.29/examples/bootstrap5.py000066400000000000000000000000571477626554400172620ustar00rootroot00000000000000import uwsgi print(uwsgi.extract("data://0")) uwsgi-2.0.29/examples/config.lua000066400000000000000000000003431477626554400165540ustar00rootroot00000000000000config = {} config['immediate-uid'] = 'roberto' config['immediate-gid'] = 'roberto' config['http-socket'] = ':9090' config['env'] = { 'FOO=bar', 'TEST=topogigio' } config['module'] = 'werkzeug.testapp:test_app' return config uwsgi-2.0.29/examples/config.ru000066400000000000000000000003031477626554400164150ustar00rootroot00000000000000require 'fiber' require 'sinatra' get '/hi' do class Response def each for i in 1..10 yield "ciao
" Fiber.yield end end end Response.new end run Sinatra::Application uwsgi-2.0.29/examples/config17.ru000066400000000000000000000010221477626554400165640ustar00rootroot00000000000000require 'stringio' hello = proc do |signum| puts "Hello i am signal #{signum}" end file_changed = proc do |signum| puts "/tmp has been modified" end UWSGI.register_signal(17, '', hello) UWSGI.register_signal(30, '', file_changed) UWSGI.add_rb_timer(17 , 2) UWSGI.add_timer(17 , 1) UWSGI.add_file_monitor(30 , '/tmp') puts UWSGI.signal_registered(1) puts UWSGI.signal_registered(17) run lambda { |env| puts env.inspect UWSGI.signal(17) [200, {'Content-Type'=>'text/plain'}, StringIO.new("Hello World!\n")] } uwsgi-2.0.29/examples/config2.lua000066400000000000000000000003061477626554400166350ustar00rootroot00000000000000config = {} config[1] = { ['http-socket']=':9090' } config[2] = { ['env']='FOO=bar' } config[3] = { ['env']='TEST=topogigio' } config[4] = { ['module']='werkzeug.testapp:test_app' } return config uwsgi-2.0.29/examples/config2.ru000066400000000000000000000001151477626554400165000ustar00rootroot00000000000000require 'sinatra' get '/hi' do "Hello World" end run Sinatra::Application uwsgi-2.0.29/examples/config30.ru000066400000000000000000000021401477626554400165610ustar00rootroot00000000000000require 'stringio' require 'uwsgidsl' signal 17,'mule5' do |signum| end puts UWSGI::VERSION puts UWSGI::NUMPROC puts UWSGI::HOSTNAME puts UWSGI::OPT.inspect timer 2 do |signum| puts "ciao sono un dsl ruby: #{signum} #{UWSGI::OPT.inspect}" end timer 1,'mule1' do |signum| puts "1 second elapsed (signum #{signum})" end filemon '/tmp' do |signum| puts "/tmp has been modified" end cron 5,-1,-1,-1,-1 do |signum| puts "cron ready #{signum}" end cron 58,-1,-1,-1,-1 do |signum| puts "cron ready #{signum}" end postfork do puts "fork() called" end rpc 'pippo' do "i am an rpc function" end rpc 'pluto' do |x,y| "i am another rpc function #{x} #{y}" end begin foo_func rescue end puts UWSGI.cache_exists('nilkey') puts UWSGI.cache_exists?('nilkey') UWSGI.cache_set!('foobar_key?a=1', UWSGI::OPT.inspect) begin puts UWSGI.cache_get(nil) rescue end puts UWSGI.cache_get('foobar_key?a=1') run lambda { |env| puts env.inspect UWSGI.setprocname("i am the uWSGI rack plugin") UWSGI.signal(17) [200, {'Content-Type'=>'text/plain'}, StringIO.new("Hello World! #{UWSGI.mem.inspect}\n")] } uwsgi-2.0.29/examples/corostream.pl000066400000000000000000000034131477626554400173200ustar00rootroot00000000000000# to run the server # uwsgi --plugin psgi,coroae --http-socket :9090 --http-socket-modifier1 5 --coroae 8 --psgi examples/corostream.pl --master # to test it # curl -D /dev/stdout -N --raw http://localhost:9090/ use Coro::AnyEvent; use AnyEvent::HTTP; my $signal_handler = sub { my $signum = shift; print "i am the signal ".$signum."\n" ; }; my $signal_timer = sub { my $signum = shift; print "2 seconds elapsed\n"; }; uwsgi::register_signal(17, '', $signal_handler); uwsgi::register_signal(30, '', $signal_timer); # raise the signal 30 every 2 seconds uwsgi::add_timer(30, 2); sub streamer { $responder = shift; # generate the headers and start streaming the response my $writer = $responder->( [200, ['Content-Type' => 'text/plain']]); $writer->write("Hello, the streaming is starting...\n"); for(my $i=0;$i<5;$i++) { Coro::AnyEvent::sleep 1; $writer->write("[".$i."] one seconds elapsed...\n"); } $writer->write("let me show you the coroae plugin source taken from github\n\n"); # this condvar will allow us to wait for the github response my $w = AnyEvent->condvar; my $uwsgi_coroae_src = ''; http_get 'https://raw.github.com/unbit/uwsgi/master/plugins/coroae/coroae.c', sub { $uwsgi_coroae_src = $_[0] ; $w->send;}; $w->recv; $writer->write($uwsgi_coroae_src); Coro::AnyEvent::sleep 1; $writer->write("now let's raise a uwsgi signal...\n"); uwsgi::signal(17); Coro::AnyEvent::sleep 1; $writer->write("another one second elapsed, time to finish.\n"); Coro::AnyEvent::sleep 1; $writer->write("Goodbye\n"); $writer->close; print "the request ended, but we are still here\n"; Coro::AnyEvent::sleep 1; print "another second elapsed, time to end (really)\n"; } # our PSGI app my $app = sub { my $env = shift; return \&streamer; } uwsgi-2.0.29/examples/debug.ini000066400000000000000000000000331477626554400163670ustar00rootroot00000000000000[uwsgi] show-config = true uwsgi-2.0.29/examples/fibers.ru000066400000000000000000000013431477626554400164270ustar00rootroot00000000000000require 'fiber' class SuspendingBody def each for i in 1..3 yield "number: #{i}\n" UWSGI.async_sleep(1) puts "sleep..." Fiber.yield end fd = UWSGI.async_connect("81.174.68.52:80") UWSGI.wait_fd_write(fd, 3) Fiber.yield io = IO.new(fd) puts "connected" io.syswrite("GET /uwsgi/export/1081%3A362d695b2f25/plugins/fiber/fiber.c HTTP/1.0\r\n") io.syswrite("Host: projects.unbit.it\r\n") io.syswrite("\r\n") UWSGI.wait_fd_read(fd, 3) Fiber.yield puts "data available" begin while body = io.sysread(fd) yield body Fiber.yield end rescue end io.close end end class RackFoo def call(env) [200, { 'Content-Type' => 'text/plain'}, SuspendingBody.new] end end run RackFoo.new uwsgi-2.0.29/examples/fibers.yml000066400000000000000000000001751477626554400166040ustar00rootroot00000000000000uwsgi: plugins: rack socket: 127.0.0.1:3031 rack: fibers.ru post-buffering: 4096 async: 10 loop: fiber uwsgi-2.0.29/examples/flaskpost.py000066400000000000000000000007631477626554400171720ustar00rootroot00000000000000from flask import Flask, request app = Flask(__name__) app.debug = True @app.route('/') def hello_world(): return "
" @app.route('/upload', methods=['GET', 'POST']) def upload_file(): return str(len(request.form.get('pippo', 'boh'))) + request.form.get('pippo', 'boh') return request.files['ufile'].read() uwsgi-2.0.29/examples/heavytest.ini000066400000000000000000000006421477626554400173230ustar00rootroot00000000000000[uwsgi] master = true processes = 4 threads = 8 ; initialize 4 sockets with 4 different protocols socket = :3031 socket = :3032 socket = :3033 socket = :3034 socket-protocol = 0,uwsgi socket-protocol = 1,http socket-protocol = 2,fastcgi socket-protocol = 3,uwsgidump ; add a cache with 1000 items of 96k cache = 1000 cache-blocksize = 98304 log-micros = true module = heavytest mount = /cc=uwsgicc/__init__.py uwsgi-2.0.29/examples/heavytest.py000066400000000000000000000010431477626554400171700ustar00rootroot00000000000000import uwsgi import werkzeug.testapp uwsgi.cache_set("/cache/get", "HTTP 1.1 200 OK\r\nContent-Type: text/html\r\n\r\n

I am the uWSGI cache

") def app001(env, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return "PATH_INFO=%s" % env['PATH_INFO'] def app002(env, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return "requests: %d" % uwsgi.total_requests() uwsgi.applications = { '': werkzeug.testapp.test_app, '/app001': app001, '/app002': app002 } uwsgi-2.0.29/examples/info_uwsgi.php000066400000000000000000000013621477626554400174700ustar00rootroot00000000000000uWSGI version
worker id:
master pid:
uri:
docroot:
PATH_INFO:
rpc result:
cache value:
uwsgi-2.0.29/examples/logic.ini000066400000000000000000000012461477626554400164050ustar00rootroot00000000000000[uwsgi] for = 4031 14032 4033 14034 24035 socket = /tmp/%(_)/uwsgi.sock socket = 192.*:%(_) print = ciao %(_) hello %(_) bye %(_) endfor = socket = :4045 socket = :4046 socket = :4047 socket = :4048 socket = :4049 socket = :4050 socket = :4051 show-config = if-env = PIPPO print = print = PIPPO e' definita e il suo valore e' %(_) boh endif = socket = :5051 socket = :5052 socket = :5053 socket = :5054 if-exists = /etc/services print = il file %(_) esiste $(PATH) endif = if-exists = /etc/foobar print = il file %(_) esiste $(PATH) endif = socket = :6060 if-file = /etc/fstab socket = :7171 endif = ifdir = /tmp print = %(_) is a directory endif= uwsgi-2.0.29/examples/mega.xml000066400000000000000000000006051477626554400162400ustar00rootroot00000000000000 ciao ciao :3333 trac.web.main:dispatch_request ciao TRAC_ENV=/root/uwsgi/utrac :4444 trac.web.main:dispatch_request :3031 uwsgi-2.0.29/examples/mjpeg_stream.py000066400000000000000000000013161477626554400176340ustar00rootroot00000000000000import os import subprocess def application(env, start_response): boundary = 'uwsgi_mjpeg_frame' start_response('200 Ok', [ ('Cache-Control', 'no-cache'), ('Cache-Control', 'private'), ('Pragma', 'no-cache'), ('Content-Type', 'multipart/x-mixed-replace; boundary=' + boundary), ]) yield "--%s\r\n" % boundary while 1: yield "Content-Type: image/jpeg\r\n\r\n" print(subprocess.call('screencapture -t jpg -m -T 1 screenshot.jpg', shell=True)) f = open('screenshot.jpg') yield env['wsgi.file_wrapper'](f) yield "\r\n--%s\r\n" % boundary # subprocess.call('./isightcapture -w 640 -h 480 screenshot.jpg', shell=True) uwsgi-2.0.29/examples/mojoapp.pl000066400000000000000000000005651477626554400166140ustar00rootroot00000000000000use Mojolicious::Lite; # / get '/' => 'index'; # /* get '/:groovy' => sub { my $self = shift; $self->render_text($self->param('groovy'), layout => 'funky'); }; app->start('psgi'); __DATA__ @@ index.html.ep % layout 'funky'; Yea baby! @@ layouts/funky.html.ep Funky! <%= content %> uwsgi-2.0.29/examples/multi.ini000066400000000000000000000007151477626554400164420ustar00rootroot00000000000000[uwsgi] ; socket 0 socket = :3033 ; socket 1 socket = :3034 ; socket 2 socket = pippo1.sock ; socket 3 socket = pippo2.sock ; socket 4 socket = 127.0.0.1:1717 map-socket = 0:1,2,3,4 map-socket = 1:4 map-socket = 2:10 map-socket = 3:5,6,9 map-socket = 4:7,8,9 vacuum = true memory-report = true master = true processes = 10 ;mount = /app1=werkzeug.testapp:test_app ;mount = /app2=config:/Users/roberta/uwsgi/my.ini ;mount = /app3=pinaxsite/deploy/pinax.wsgi uwsgi-2.0.29/examples/multi.xml000066400000000000000000000020631477626554400164610ustar00rootroot00000000000000 psgi rack :9090 :3031 127.0.0.1:3032 8 TRAC_ENV=utrac werkzeug.testapp:test_app werkzeug.testapp:test_app trac.web.main:dispatch_request werkzeug.testapp:test_app from bzrlib.transport.http import wsgi application = wsgi.make_app("mybzr", "/bzr", readonly=False) trac.web.main:dispatch_request config2.ru test.psgi uwsgi-2.0.29/examples/multiapp.py000066400000000000000000000011241477626554400170070ustar00rootroot00000000000000import werkzeug import uwsgi def zero_app(e, s): s('200 OK', [('Content-Type', 'text/plain')]) return "0" def not_found(e, s): s('404 Not Found', [('Content-Type', 'text/plain')]) return "" def wsgi_app(e, s): s('200 OK', [('Content-Type', 'text/plain')]) yield "I am a WSGI app\n" def internal_server_error(e, s): s('500 Internal Server Error', [('Content-Type', 'text/plain')]) return "" uwsgi.applications = { '/wsgi': wsgi_app, '/test': werkzeug.test_app, '/zero': zero_app, '/notfound': not_found, '/ise': internal_server_error } uwsgi-2.0.29/examples/protected.ini000066400000000000000000000006501477626554400172770ustar00rootroot00000000000000[uwsgi] http-socket = :9090 route = ^/foo basicauth:foobar,kratos: ; a simple user:passowrd mapping route = .* basicauth:nether realm 3,serena:alessandro ; htpasswd-like real-time parsing route = .* basicauth:nether realm 2,.htpasswd ; user-only auth route = .* basicauth:nether realm 4,roberta: route = .* basicauth:nether realm 4, route = ^/bar basicauth:foobar,kratos: module = welcome processes = 4 master = true uwsgi-2.0.29/examples/router.lua000066400000000000000000000011061477626554400166250ustar00rootroot00000000000000print("uWSGI Lua router") uwsgi.log("i am ready") function route(env) print(env.REQUEST_URI) html = uwsgi.cache_get(env.REQUEST_URI) local function send_cache() coroutine.yield(html) end local function body() page = "" parts = { uwsgi.send_message("127.0.0.1:3033", 0, 0, env, 30, uwsgi.req_fd(), uwsgi.cl()) } for i, part in pairs(parts) do page = page .. part coroutine.yield(part) end uwsgi.cache_set(env.REQUEST_URI, page) end if html then return nil,{}, coroutine.wrap(send_cache) end return nil,{}, coroutine.wrap(body) end return route uwsgi-2.0.29/examples/simple_app.py000066400000000000000000000014641477626554400173140ustar00rootroot00000000000000import uwsgi import os print("!!! uWSGI version:", uwsgi.version) def ciao(): print("modifica su /tmp") def ciao2(): print("nuovo uwsgi_server") print(os.getpid()) counter = 0 #if uwsgi.load_plugin(0, 'plugins/example/example_plugin.so', 'ciao'): # print("example plugin loaded") #else: # print("unable to load example plugin") #uwsgi.event_add(uwsgi.EVENT_FILE, "/tmp", ciao) #uwsgi.event_add(uwsgi.EVENT_DNSSD, "_uwsgi._tcp", ciao2) #uwsgi.event_add(uwsgi.EVENT_TIMER, 1000, ciao2) uwsgi.post_fork_hook = ciao2 def application(env, start_response): global counter start_response('200 Ok', [('Content-type', 'text/plain')]) yield "hello world" yield "hello world2" for i in range(1, 1000): yield str(i) yield "\n" yield str(counter) counter += 1 uwsgi-2.0.29/examples/simple_app_wsgi2.py000066400000000000000000000005321477626554400204220ustar00rootroot00000000000000from six.moves import range def mygen(uri): for i in range(1, 100): yield "ciao %s
" % uri def application(env, start_response=None): return '200 OK', [('Content-Type', 'text/html')], "

This is the fastest homepage of the world !!!

" # return '200 OK', [('Content-Type', 'text/html')], mygen(env['PATH_INFO']) uwsgi-2.0.29/examples/simple_logger.py000066400000000000000000000001601477626554400200030ustar00rootroot00000000000000import uwsgi def print_logs(ip, port, message): print(ip, port, message) uwsgi.udp_callable = print_logs uwsgi-2.0.29/examples/sites.xml000066400000000000000000000007031477626554400164550ustar00rootroot00000000000000 :3031 4 TRAC_ENV=/Users/roberto/uapps/utrac /Users/roberto/uwsgi/config.ru uwsgi-2.0.29/examples/sputnik.ws000066400000000000000000000003311477626554400166510ustar00rootroot00000000000000require('sputnik') return sputnik.wsapi_app.new{ VERSIUM_STORAGE_MODULE = "versium.sqlite3", VERSIUM_PARAMS = {'/tmp/sputnik.db'}, SHOW_STACK_TRACE = true, TOKEN_SALT = 'xxx', BASE_URL = '/', } uwsgi-2.0.29/examples/staticfilesnmp.py000066400000000000000000000007261477626554400202100ustar00rootroot00000000000000import uwsgi from os import path uwsgi.snmp_set_counter64(1, 0) # Number of requests uwsgi.snmp_set_counter64(2, 0) # Number of bytes def application(environ, start_response): size = path.getsize('logo_uWSGI.png') start_response('200 OK', [('Content-Type', 'image/png'), ('Content-Length', str(size))]) fd = open('logo_uWSGI.png') uwsgi.snmp_incr_counter64(1) uwsgi.snmp_incr_counter64(2, size) return environ['wsgi.file_wrapper'](fd, 4096) uwsgi-2.0.29/examples/taskqueue.py000066400000000000000000000014011477626554400171610ustar00rootroot00000000000000from threading import Thread import uwsgi from six.moves import queue CONSUMERS = 4 def consumer(q): while True: item = q.get() print(item) # ... DO A HEAVY TASK HERE ... q.task_done() def spawn_consumers(): global q q = queue.Queue() for i in range(CONSUMERS): t = Thread(target=consumer, args=(q,)) t.daemon = True t.start() print("consumer %d on worker %d started" % (i, uwsgi.worker_id())) uwsgi.post_fork_hook = spawn_consumers def application(env, start_response): global q # we pass a copy of the env dictionary as it gets cleared after yield/return q.put(env.copy()) start_response('200 OK', [('Content-Type', 'text/html')]) yield "Task enqueued" uwsgi-2.0.29/examples/uwsgi.xml000066400000000000000000000011201477626554400164560ustar00rootroot00000000000000 rtmpt :3031 :3031 homepage view1 amfapp rtmpt_open rtmpt_idle rtmpt_send index uwsgi-2.0.29/examples/uwsgirouter.py000066400000000000000000000042551477626554400175630ustar00rootroot00000000000000import uwsgi def application(env, start_response): # open the socket fd = uwsgi.async_connect("192.168.173.100:3032") # wait for connection ready (3s timeout) yield uwsgi.wait_fd_write(fd, 3) # has timed out ? if env['x-wsgiorg.fdevent.timeout']: print("connection timed out !!!") uwsgi.close(fd) raise StopIteration # connection refused ? if not uwsgi.is_connected(fd): print("unable to connect") uwsgi.close(fd) raise StopIteration # send request # env can contains python objects, but send_message will discard them. # In this way we will automagically have a congruent and valid uwsgi packet uwsgi.async_send_message(fd, 0, 0, env) # send the http body # ready body in async mode and resend to fd # uwsgi.recv will use always an internal buffer of 4096, but can be limited in the number of bytes to read # does this request has a body ? cl = uwsgi.cl() if cl > 0: # get the input fd input = env['wsgi.input'].fileno() # read (in async mode) up to 'cl' data and send to uwsgi peer while cl > 0: bufsize = min(cl, 4096) yield uwsgi.wait_fd_read(input, 30) if env['x-wsgiorg.fdevent.timeout']: print("connection timed out !!!") uwsgi.close(fd) raise StopIteration body = uwsgi.recv(input, bufsize) if body: uwsgi.send(fd, body) cl = cl - len(body) else: break # wait for response (30s timeout) yield uwsgi.wait_fd_read(fd, 30) # has timed out ? if env['x-wsgiorg.fdevent.timeout']: print("connection timed out !!!") uwsgi.close(fd) raise StopIteration data = uwsgi.recv(fd) # recv the data, if it returns None the callable will end while data: yield data # wait for response yield uwsgi.wait_fd_read(fd, 30) if env['x-wsgiorg.fdevent.timeout']: print("connection timed out !!!") uwsgi.close(fd) raise StopIteration data = uwsgi.recv(fd) uwsgi.close(fd) uwsgi-2.0.29/examples/uwsgirouter2.py000066400000000000000000000002511477626554400176350ustar00rootroot00000000000000 import uwsgi def application(e, s): for part in uwsgi.send_message("192.168.173.100:3032", 0, 0, e, 0, e['wsgi.input'].fileno(), uwsgi.cl()): yield part uwsgi-2.0.29/examples/uwsgirouter3.py000066400000000000000000000007121477626554400176400ustar00rootroot00000000000000 import uwsgi current_node = 0 def application(e, s): global current_node nodes = uwsgi.cluster_nodes() print(nodes) if len(nodes) == 0: print("no cluster node available") raise StopIteration if current_node >= len(nodes): current_node = 0 node = nodes[current_node] for part in uwsgi.send_message(node, 0, 0, e, 0, e['wsgi.input'].fileno(), uwsgi.cl()): yield part current_node += 1 uwsgi-2.0.29/examples/uwsgirouter4.py000066400000000000000000000004431477626554400176420ustar00rootroot00000000000000 import uwsgi def application(e, s): node = uwsgi.cluster_best_node() print(node) if not node: print("sorry node unavailable") raise StopIteration for part in uwsgi.send_message(node, 0, 0, e, 0, e['wsgi.input'].fileno(), uwsgi.cl()): yield part uwsgi-2.0.29/examples/uwsgirouter5.py000066400000000000000000000002741477626554400176450ustar00rootroot00000000000000 import uwsgi fd = uwsgi.connect("127.0.0.1:3033") def application(e, s): for part in uwsgi.send_message(fd, 0, 4, e, 30, e['wsgi.input'].fileno(), uwsgi.cl()): yield part uwsgi-2.0.29/examples/uwsgistatus.py000066400000000000000000000034351477626554400175650ustar00rootroot00000000000000import uwsgi import time import sys import os def application(env, start_response): print(env) start_response('200 OK', [('Content-Type', 'text/html')]) yield '

uWSGI %s status

' % uwsgi.version yield 'masterpid: ' + str(uwsgi.masterpid()) + '
' yield 'started on: ' + time.ctime(uwsgi.started_on) + '
' yield 'buffer size: ' + str(uwsgi.buffer_size) + '
' yield 'total_requests: ' + str(uwsgi.total_requests()) + '
' yield 'log size: ' + str(uwsgi.logsize()) + '
' yield 'workers: ' + str(uwsgi.numproc) + '
' yield "cwd: %s
" % os.getcwd() try: yield "mode: %s
" % uwsgi.mode except Exception: pass try: yield "pidfile: %s
" % uwsgi.pidfile except Exception: pass yield "

Hooks

" for h in range(0, 255): if uwsgi.has_hook(h): yield "%d
" % h yield '

dynamic options

' yield '' yield '' workers = uwsgi.workers() yield '

workers

' for w in workers: # print(w) # print(w['running_time']) if w is not None: yield '' print(w) yield '
worker idpidin requestrequestsrunning timeaddress spacerss
' + str(w['id']) + '' + str(w['pid']) + '' + str(w['pid']) + '' + str(w['requests']) + '' + str(w['running_time']) + '' + str(w['vsz']) + '' + str(w['rss']) + '
' yield "

PYTHONPATH

" yield "
    " for p in sys.path: yield "
  • %s
  • " % p yield "
" yield "%s" % str(os.uname()) uwsgi-2.0.29/examples/welcome.ini000066400000000000000000000003451477626554400167420ustar00rootroot00000000000000[uwsgi] socket = :$(PORT) socket = /tmp/uwsgi_welcome.socket vacuum = true appname = welcome module = %(appname) numproc = 4 master = %(vacuum) processes = %(numproc) mount = /werkzeug=tests/werkzeug.py manage-script-name = true uwsgi-2.0.29/examples/welcome.py000066400000000000000000000072651477626554400166230ustar00rootroot00000000000000import uwsgi import os import gc import sys from uwsgidecorators import rpc, signal, postfork from os.path import abspath, dirname, join logo_png = abspath(join(dirname(__file__), "../logo_uWSGI.png")) print(sys.version) print(sys.version_info) if "set_debug" in gc.__dict__: gc.set_debug(gc.DEBUG_SAVEALL) print(os.environ) print(sys.modules) print(sys.argv) try: DEBUG = sys.argv[1] == "debug" except IndexError: DEBUG = False def after_request_hook(): print("request finished") uwsgi.after_req_hook = after_request_hook @rpc(b"hello") def hello_rpc(one, two, three): arg0 = one[::-1] arg1 = two[::-1] arg2 = three[::-1] return "!%s-%s-%s!" % (arg1, arg2, arg0) @signal(17) def ciao_mondo(signum): print("Hello World") def xsendfile(e, sr): sr( "200 OK", [("Content-Type", "image/png"), ("X-Sendfile", logo_png),], ) return [] def serve_logo(e, sr): # use raw facilities (status will not be set...) uwsgi.send( b"%s 200 OK\r\nContent-Type: image/png\r\n\r\n" % e["SERVER_PROTOCOL"].encode("latin1") ) uwsgi.sendfile(logo_png) return [] def serve_config(e, sr): sr("200 OK", [("Content-Type", "text/html")]) for key in uwsgi.opt.keys(): opt = uwsgi.opt[key] if not isinstance(opt, bytes): opt = str(opt).encode("utf-8") yield b"%s = %s
" % (key, opt) routes = {} routes["/xsendfile"] = xsendfile routes["/logo"] = serve_logo routes["/config"] = serve_config @postfork def setprocname(): if uwsgi.worker_id() > 0: uwsgi.setprocname(b"i am the worker %d" % uwsgi.worker_id()) def application(env, start_response): try: uwsgi.mule_msg(env["REQUEST_URI"], 1) except Exception: pass req = uwsgi.workers()[uwsgi.worker_id() - 1]["requests"] uwsgi.setprocname(b"worker %d managed %d requests" % (uwsgi.worker_id(), req)) try: gc.collect(2) except Exception: pass if DEBUG: print(env["wsgi.input"].fileno()) if env["PATH_INFO"] in routes: return routes[env["PATH_INFO"]](env, start_response) if DEBUG: print(env["wsgi.input"].fileno()) try: gc.collect(2) except Exception: pass if DEBUG: print(len(gc.get_objects())) workers = "" for w in uwsgi.workers(): apps = '' for app in w["apps"]: apps += "" % ( app["id"], app["mountpoint"], app["startup_time"], app["requests"], ) apps += "
idmountpointstartup timerequests
%d%s%d%d
" workers += """ %d%d%s%d%d%d%s """ % ( w["id"], w["pid"], w["status"], w["running_time"] / 1000, w["avg_rt"] / 1000, w["tx"], apps, ) output = """ version %s running on %s (remote user: %s)

Configuration


Workers and applications
%s
widpidstatusrunning timeaveragetxapps
""" % ( uwsgi.version, uwsgi.hostname, env.get("REMOTE_USER", "None"), workers, ) start_response( "200 OK", [("Content-Type", "text/html"), ("Content-Length", str(len(output)))] ) return [output.format(script_name=env["SCRIPT_NAME"]).encode("utf-8")] uwsgi-2.0.29/examples/welcome3.py000066400000000000000000000025021477626554400166730ustar00rootroot00000000000000import uwsgi import os from os.path import abspath, dirname, join logo_png = abspath(join(dirname(__file__), "../logo_uWSGI.png")) def xsendfile(e, sr): sr( "200 OK", [("Content-Type", "image/png"), ("X-Sendfile", logo_png),], ) return b"" def serve_logo(e, sr): sr("200 OK", [("Content-Type", "image/png")]) return uwsgi.sendfile(logo_png) def serve_config(e, sr): sr("200 OK", [("Content-Type", "text/html")]) for opt in uwsgi.opt.keys(): def decode_if_bytes(val): if isinstance(val, bytes): return val.decode("ascii") return val body = "{opt} = {optvalue}
".format( opt=opt.decode("ascii"), optvalue=decode_if_bytes(uwsgi.opt[opt]) ) yield bytes(body.encode("ascii")) routes = {} routes["/xsendfile"] = xsendfile routes["/logo"] = serve_logo routes["/config"] = serve_config def application(env, start_response): if env["PATH_INFO"] in routes: return routes[env["PATH_INFO"]](env, start_response) start_response("200 OK", [("Content-Type", "text/html")]) body = """ version {version}

Configuration


""".format( version=uwsgi.version ) return [bytes(body.encode("ascii"))] uwsgi-2.0.29/examples/werkzeug.js000066400000000000000000000003531477626554400170060ustar00rootroot00000000000000{ "uwsgi": { "http": ":8080", "workers": 8, "module": "werkzeug.testapp:test_app", "master": true, "socket": [ "/tmp/uwsgi.sock", "127.0.0.1:3031", "@foobar" ], "pythonpath": [ "/foo", "/bar" ], "show-config": true } } uwsgi-2.0.29/examples/werkzeug.yml000066400000000000000000000010251477626554400171700ustar00rootroot00000000000000# werkzeug test module via YAML uwsgi: module: werkzeug.testapp:test_app # a comment socket: :3032 # another comment # a line comment # another line comment # adding a tab as separator (discouraged) master: 1 processes: 8 # the number of processes memory-report: 1 show-config: true # now a psgi app via plugin app2: plugins: psgi socket: :3032 # another comment # adding a tab as separator (discouraged) master: 1 processes: 8 # the number of processes memory-report: 1 psgi: test.psgi show-config: true uwsgi-2.0.29/examples/werkzeug_strict.yml000066400000000000000000000003011477626554400205540ustar00rootroot00000000000000# werkzeug test module via YAML uwsgi: module: werkzeug.testapp:test_app # a comment socket: :3032 # another comment master: 1 processes: 8 # the number of processes memory-report: 1 uwsgi-2.0.29/examples/xmlindex-html.xsl000066400000000000000000000070201477626554400201250ustar00rootroot00000000000000 Index of <xsl:value-of select="@path" />

Index of

Name Last Modified Size
Parent directory
/ / /
uwsgi-2.0.29/examples/xmlindex.ini000066400000000000000000000010221477626554400171300ustar00rootroot00000000000000[uwsgi] plugin = 0:notfound, router_xmldir, xslt http-socket = :8080 docroot = . check-static = %(docroot) route-if = isdir:%(docroot)/${PATH_INFO} goto:index route-run = last: route-label = index ; uncomment to link CSS stylesheet /css/default.css ;route-run = toxslt:stylesheet=examples/xmlindex-html.xsl,params=stylesheet=/css/default.css,content_type=text/html ; use embedded CSS route-run = toxslt:stylesheet=examples/xmlindex-html.xsl,params=stylesheet=,content_type=text/html route-run = xmldir:%(docroot)/${PATH_INFO} uwsgi-2.0.29/examples/zmqgevent.ini000066400000000000000000000003241477626554400173240ustar00rootroot00000000000000[uwsgi] ;master = true gevent = 1000 zmq-socket = tcp://192.168.173.2:9999,tcp://192.168.173.2:9998 zmq-socket = tcp://192.168.173.19:9999,tcp://192.168.173.19:9998 http-socket = :8080 ;module = tests.ugevent uwsgi-2.0.29/ext/000077500000000000000000000000001477626554400135665ustar00rootroot00000000000000uwsgi-2.0.29/ext/uwsgi/000077500000000000000000000000001477626554400147245ustar00rootroot00000000000000uwsgi-2.0.29/ext/uwsgi/extconf.rb000066400000000000000000000012011477626554400167110ustar00rootroot00000000000000require 'net/http' Net::HTTP.start("uwsgi.it") do |http| resp = http.get("/install") open("install.sh", "wb") do |file| file.write(resp.body) end end major,minor = RUBY_VERSION.split('.') if major.to_i >= 2 or (major.to_i == 1 and minor.to_i >= 9) # a trick for installations with messy PATH ENV['UWSGICONFIG_RUBYPATH'] = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name']).sub(/.*\s.*/m, '"\&"') system("bash install.sh ruby2 #{Dir.pwd}/uwsgi.ruby") else system("bash install.sh rack #{Dir.pwd}/uwsgi.ruby") end open("Makefile", "w") do |file| file.write("all:\n") file.write("\t\n") end uwsgi-2.0.29/install.sh000066400000000000000000000010471477626554400147720ustar00rootroot00000000000000echo "*** uWSGI installer ***" if [ $# -ne 2 ] then echo "Usage: install.sh " exit 1 fi if [ ${2:0:1} != "/" ] then echo "uWSGI binary path must be absolute !!!" exit 1 fi echo "downloading latest uWSGI tarball..." curl -o uwsgi_latest_from_installer.tar.gz http://projects.unbit.it/downloads/uwsgi-latest.tar.gz mkdir uwsgi_latest_from_installer tar zvxC uwsgi_latest_from_installer --strip-components=1 -f uwsgi_latest_from_installer.tar.gz cd uwsgi_latest_from_installer UWSGI_PROFILE="$1" UWSGI_BIN_NAME="$2" make uwsgi-2.0.29/lib/000077500000000000000000000000001477626554400135345ustar00rootroot00000000000000uwsgi-2.0.29/lib/linux_ns.c000066400000000000000000000143051477626554400155420ustar00rootroot00000000000000#include "../uwsgi.h" extern struct uwsgi_server uwsgi; #ifndef CLONE_NEWUTS #define CLONE_NEWUTS 0x04000000 #endif #ifndef CLONE_NEWPID #define CLONE_NEWPID 0x20000000 #endif #ifndef CLONE_NEWIPC #define CLONE_NEWIPC 0x08000000 #endif #ifndef CLONE_NEWNET #define CLONE_NEWNET 0x40000000 #endif int uwsgi_is_a_keep_mount(char *mp) { struct uwsgi_string_list *usl = uwsgi.ns_keep_mount; while(usl) { char *colon = strchr(usl->value, ':'); if (colon) { if (!strcmp(colon+1, mp)) { return 1; } } else { // slip first part if (!uwsgi_startswith(usl->value, uwsgi.ns, strlen(uwsgi.ns))) { char *skipped = usl->value + strlen(uwsgi.ns); if (uwsgi.ns[strlen(uwsgi.ns)-1] == '/') { skipped--; } if (!strcmp(skipped, mp)) { return 1; } } else { if (!strcmp(usl->value, mp)) { return 1; } } } usl = usl->next; } return 0; } static int uwsgi_ns_start(void *v_argv) { uwsgi_start(v_argv); return uwsgi_run(); } void linux_namespace_start(void *argv) { for (;;) { char stack[PTHREAD_STACK_MIN]; int waitpid_status; char *pid_str = NULL; uwsgi_log("*** jailing uWSGI in %s ***\n", uwsgi.ns); int clone_flags = SIGCHLD | CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWNS; if (uwsgi.ns_net) { clone_flags |= CLONE_NEWNET; } pid_t pid = clone(uwsgi_ns_start, stack + PTHREAD_STACK_MIN, clone_flags, (void *) argv); if (pid == -1) { uwsgi_error("clone()"); exit(1); } #if defined(MS_REC) && defined(MS_PRIVATE) if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL)) { uwsgi_error("mount()"); exit(1); } #endif pid_str = uwsgi_num2str((int) pid); // run the post-jail scripts if (setenv("UWSGI_JAIL_PID", pid_str, 1)) { uwsgi_error("setenv()"); } free(pid_str); uwsgi_hooks_run(uwsgi.hook_post_jail, "post-jail", 1); struct uwsgi_string_list *usl = uwsgi.exec_post_jail; while(usl) { uwsgi_log("running \"%s\" (post-jail)...\n", usl->value); int ret = uwsgi_run_command_and_wait(NULL, usl->value); if (ret != 0) { uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret); exit(1); } usl = usl->next; } uwsgi_foreach(usl, uwsgi.call_post_jail) { if (uwsgi_call_symbol(usl->value)) { uwsgi_log("unable to call function \"%s\"\n", usl->value); exit(1); } } uwsgi_log("waiting for jailed master (pid: %d) death...\n", (int) pid); pid = waitpid(pid, &waitpid_status, 0); if (pid < 0) { uwsgi_error("waitpid()"); exit(1); } // in Linux this is reliable if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == 1) { exit(1); } else if (uwsgi.exit_on_reload && WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == 0) { uwsgi_log("jailed master process exited and exit-on-reload is enabled, shutting down\n"); exit(0); } uwsgi_log("pid %d ended. Respawning...\n", (int) pid); } // never here } void linux_namespace_jail() { char *ns_tmp_mountpoint = NULL, *ns_tmp_mountpoint2 = NULL; if (getpid() != 1) { uwsgi_log("your kernel does not support linux pid namespace\n"); exit(1); } char *ns_hostname = strchr(uwsgi.ns, ':'); if (ns_hostname) { ns_hostname[0] = 0; ns_hostname++; if (sethostname(ns_hostname, strlen(ns_hostname))) { uwsgi_error("sethostname()"); } } FILE *procmounts; char line[1024]; int unmounted = 1; char *delim0, *delim1; if (chdir(uwsgi.ns)) { uwsgi_error("chdir()"); exit(1); } if (strcmp(uwsgi.ns, "/")) { ns_tmp_mountpoint = uwsgi_concat2(uwsgi.ns, "/.uwsgi_ns_tmp_mountpoint"); if (mkdir(ns_tmp_mountpoint, S_IRWXU) < 0) { uwsgi_error("mkdir() ns_tmp_mountpoint"); exit(1); } ns_tmp_mountpoint2 = uwsgi_concat2(ns_tmp_mountpoint, "/.uwsgi_ns_tmp_mountpoint"); if (mkdir(ns_tmp_mountpoint2, S_IRWXU) < 0) { uwsgi_error("mkdir() ns_tmp_mountpoint2"); exit(1); } if (mount(uwsgi.ns, ns_tmp_mountpoint, "none", MS_BIND, NULL)) { uwsgi_error("mount()"); } if (chdir(ns_tmp_mountpoint)) { uwsgi_error("chdir()"); } if (pivot_root(".", ns_tmp_mountpoint2)) { uwsgi_error("pivot_root()"); exit(1); } if (chdir("/")) { uwsgi_error("chdir()"); exit(1); } } uwsgi_log("remounting /proc\n"); if (mount("proc", "/proc", "proc", 0, NULL)) { uwsgi_error("mount()"); exit(1); } struct uwsgi_string_list *usl = uwsgi.ns_keep_mount; while(usl) { // bind mounting keep-mount items char *keep_mountpoint = usl->value; char *destination = strchr(usl->value, ':'); if (destination) { keep_mountpoint = uwsgi_concat2n(usl->value, destination - usl->value, "", 0); } char *ks = uwsgi_concat2("/.uwsgi_ns_tmp_mountpoint", keep_mountpoint); if (!destination) { destination = usl->value; // skip first part of the name if under the jail if (!uwsgi_startswith(destination, uwsgi.ns, strlen(uwsgi.ns))) { if (uwsgi.ns[strlen(uwsgi.ns)-1] == '/') { destination += strlen(uwsgi.ns)-1; } else { destination += strlen(uwsgi.ns); } } } else { free(keep_mountpoint); destination++; } uwsgi_log("remounting %s to %s\n", ks+25, destination); if (mount(ks, destination, "none", MS_BIND, NULL)) { uwsgi_error("mount()"); } free(ks); usl = usl->next; } while (unmounted) { unmounted = 0; procmounts = fopen("/proc/self/mounts", "r"); if (!procmounts) break; while (fgets(line, 1024, procmounts) != NULL) { delim0 = strchr(line, ' '); if (!delim0) continue; delim0++; delim1 = strchr(delim0, ' '); if (!delim1) continue; *delim1 = 0; // and now check for keep-mounts if (uwsgi_is_a_keep_mount(delim0)) continue; if (!strcmp(delim0, "/") || !strcmp(delim0, "/proc")) continue; if (!umount(delim0)) { unmounted++; } } fclose(procmounts); } if (rmdir("/.uwsgi_ns_tmp_mountpoint/.uwsgi_ns_tmp_mountpoint")) { uwsgi_error("rmdir()"); } if (rmdir("/.uwsgi_ns_tmp_mountpoint")) { uwsgi_error("rmdir()"); } if (strcmp(uwsgi.ns, "/")) { free(ns_tmp_mountpoint2); free(ns_tmp_mountpoint); } } uwsgi-2.0.29/lib/netlink.c000066400000000000000000000246111477626554400153500ustar00rootroot00000000000000#include "../uwsgi.h" #ifdef OBSOLETE_LINUX_KERNEL #ifndef __u16 #define __u16 u_int16_t #endif #ifndef __u32 #define __u32 u_int32_t #endif #ifndef __s32 #define __s32 int32_t #endif #ifndef __u8 #define __u8 u_int8_t #endif #endif #include #include #include #ifdef CLONE_NEWNET #define NLMSG_TAIL(nmsg) \ ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) #ifndef VETH_INFO_PEER # define VETH_INFO_PEER 1 #endif struct uwsgi_nl_req { struct nlmsghdr nlmsg; struct ifinfomsg ifinfomsg; }; struct uwsgi_nl_ipreq { struct nlmsghdr nlmsg; struct ifaddrmsg ifaddrmsg; }; struct uwsgi_nl_rtreq { struct nlmsghdr nlmsg; struct rtmsg rtmsg; }; int uwsgi_nl_send(struct nlmsghdr *); struct nlmsghdr *uwsgi_netlink_alloc() { size_t len = NLMSG_ALIGN(8192) + NLMSG_ALIGN(sizeof(struct nlmsghdr *)); struct nlmsghdr *nlmsg = (struct nlmsghdr *) uwsgi_malloc(len); memset(nlmsg, 0, len); struct uwsgi_nl_req *unr = (struct uwsgi_nl_req *)nlmsg; unr->ifinfomsg.ifi_family = AF_UNSPEC; nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); nlmsg->nlmsg_type = RTM_NEWLINK; nlmsg->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; return nlmsg; } struct nlmsghdr *uwsgi_netlink_ip_alloc() { size_t len = NLMSG_ALIGN(8192) + NLMSG_ALIGN(sizeof(struct nlmsghdr *)); struct nlmsghdr *nlmsg = (struct nlmsghdr *) uwsgi_malloc(len); memset(nlmsg, 0, len); struct uwsgi_nl_ipreq *uni = (struct uwsgi_nl_ipreq *)nlmsg; uni->ifaddrmsg.ifa_family = AF_INET; uni->ifaddrmsg.ifa_scope = 0; nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); nlmsg->nlmsg_type = RTM_NEWADDR; nlmsg->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_CREATE|NLM_F_EXCL; return nlmsg; } struct nlmsghdr *uwsgi_netlink_rt_alloc() { size_t len = NLMSG_ALIGN(8192) + NLMSG_ALIGN(sizeof(struct nlmsghdr *)); struct nlmsghdr *nlmsg = (struct nlmsghdr *) uwsgi_malloc(len); memset(nlmsg, 0, len); struct uwsgi_nl_rtreq *unr = (struct uwsgi_nl_rtreq *)nlmsg; unr->rtmsg.rtm_family = AF_INET; unr->rtmsg.rtm_table = RT_TABLE_MAIN; unr->rtmsg.rtm_protocol = RTPROT_STATIC; unr->rtmsg.rtm_scope = RT_SCOPE_UNIVERSE; unr->rtmsg.rtm_type = RTN_UNICAST; nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); nlmsg->nlmsg_type = RTM_NEWROUTE; nlmsg->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_CREATE|NLM_F_EXCL; return nlmsg; } int uwsgi_netlink_rt(char *src, char *dst, int dst_prefix, char *gw) { struct nlmsghdr *nlmsg = uwsgi_netlink_rt_alloc(); struct rtattr *rta; struct in_addr ia; struct in_addr oa; struct in_addr ga; struct uwsgi_nl_rtreq *unr = (struct uwsgi_nl_rtreq *)nlmsg; if (inet_pton(AF_INET, src, &ia) <= 0) { uwsgi_error("inet_pton()"); free(nlmsg); return -1; } if (inet_pton(AF_INET, dst, &oa) <= 0) { uwsgi_error("inet_pton()"); free(nlmsg); return -1; } if (inet_pton(AF_INET, gw, &ga) <= 0) { uwsgi_error("inet_pton()"); free(nlmsg); return -1; } rta = NLMSG_TAIL(nlmsg); rta->rta_type = RTA_PREFSRC; rta->rta_len = RTA_LENGTH(4); memcpy(RTA_DATA(rta), &ia.s_addr, 4); nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len); rta = NLMSG_TAIL(nlmsg); rta->rta_type = RTA_DST; rta->rta_len = RTA_LENGTH(4); memcpy(RTA_DATA(rta), &oa.s_addr, 4); nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len); rta = NLMSG_TAIL(nlmsg); rta->rta_type = RTA_GATEWAY; rta->rta_len = RTA_LENGTH(4); memcpy(RTA_DATA(rta), &ga.s_addr, 4); nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len); unr->rtmsg.rtm_src_len = 0; unr->rtmsg.rtm_dst_len = dst_prefix; return uwsgi_nl_send(nlmsg); } int uwsgi_netlink_gw(char *iface, char *ip) { struct nlmsghdr *nlmsg = uwsgi_netlink_rt_alloc(); struct rtattr *rta; struct in_addr ia; uint32_t zero = 0; int index = if_nametoindex(iface); if (!index) return -1; if (inet_pton(AF_INET, ip, &ia) <= 0) { uwsgi_error("inet_pton()"); free(nlmsg); return -1; } rta = NLMSG_TAIL(nlmsg); rta->rta_type = RTA_GATEWAY; rta->rta_len = RTA_LENGTH(4); memcpy(RTA_DATA(rta), &ia.s_addr, 4); nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len); rta = NLMSG_TAIL(nlmsg); rta->rta_type = RTA_DST; rta->rta_len = RTA_LENGTH(4); memcpy(RTA_DATA(rta), &zero, 4); nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len); rta = NLMSG_TAIL(nlmsg); rta->rta_type = RTA_OIF; rta->rta_len = RTA_LENGTH(sizeof(int)); memcpy(RTA_DATA(rta), &index, sizeof(int)); nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len); return uwsgi_nl_send(nlmsg); } int uwsgi_netlink_ip(char *iface, char *ip, int prefix) { struct nlmsghdr *nlmsg = uwsgi_netlink_ip_alloc(); struct uwsgi_nl_ipreq *uni = (struct uwsgi_nl_ipreq *)nlmsg; struct rtattr *rta; struct in_addr ia; int index = if_nametoindex(iface); if (!index) return -1; uni->ifaddrmsg.ifa_index = index; uni->ifaddrmsg.ifa_prefixlen = prefix; if (inet_pton(AF_INET, ip, &ia) <= 0) { uwsgi_error("inet_pton()"); free(nlmsg); return -1; } rta = NLMSG_TAIL(nlmsg); rta->rta_type = IFA_LOCAL; rta->rta_len = RTA_LENGTH(sizeof(struct in_addr)); memcpy(RTA_DATA(rta), &ia, sizeof(struct in_addr)); nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len); rta = NLMSG_TAIL(nlmsg); rta->rta_type = IFA_ADDRESS; rta->rta_len = RTA_LENGTH(sizeof(struct in_addr)); memcpy(RTA_DATA(rta), &ia, sizeof(struct in_addr)); nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len); return uwsgi_nl_send(nlmsg); } int uwsgi_netlink_veth_attach(char *veth1, pid_t pid) { struct nlmsghdr *nlmsg = uwsgi_netlink_alloc(); struct uwsgi_nl_req *unr = (struct uwsgi_nl_req *)nlmsg; struct rtattr *rta; int index = if_nametoindex(veth1); if (!index) return -1; unr->ifinfomsg.ifi_index = index; rta = NLMSG_TAIL(nlmsg); rta->rta_type = IFLA_NET_NS_PID; rta->rta_len = RTA_LENGTH(sizeof(pid_t)); memcpy(RTA_DATA(rta), &pid, sizeof(pid_t)); nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len); return uwsgi_nl_send(nlmsg); } int uwsgi_netlink_ifup(char *iface) { struct nlmsghdr *nlmsg = uwsgi_netlink_alloc(); struct uwsgi_nl_req *unr = (struct uwsgi_nl_req *)nlmsg; int index = if_nametoindex(iface); if (!index) return -1; unr->ifinfomsg.ifi_index = index; unr->ifinfomsg.ifi_change |= IFF_UP; unr->ifinfomsg.ifi_flags |= IFF_UP; return uwsgi_nl_send(nlmsg); } int uwsgi_netlink_del(char *iface) { struct nlmsghdr *nlmsg = uwsgi_netlink_alloc(); struct uwsgi_nl_req *unr = (struct uwsgi_nl_req *)nlmsg; int index = if_nametoindex(iface); if (!index) return -1; nlmsg->nlmsg_type = RTM_DELLINK; unr->ifinfomsg.ifi_index = index; return uwsgi_nl_send(nlmsg); } int uwsgi_netlink_veth(char *veth0, char *veth1) { struct rtattr *rta, *rta0, *rta1, *rta2; struct nlmsghdr *nlmsg = uwsgi_netlink_alloc(); nlmsg->nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL; // IFLA_LINKINFO rta0 = NLMSG_TAIL(nlmsg); rta0->rta_type = IFLA_LINKINFO; rta0->rta_len = RTA_LENGTH(0); nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta0->rta_len); // IFLA_INFO_KIND rta = NLMSG_TAIL(nlmsg); rta->rta_type = IFLA_INFO_KIND; rta->rta_len = RTA_LENGTH(4); memcpy(RTA_DATA(rta), "veth", 4); nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len); // IFLA_INFO_DATA rta1 = NLMSG_TAIL(nlmsg); rta1->rta_type = IFLA_INFO_DATA; rta1->rta_len = RTA_LENGTH(0); nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta1->rta_len); // VETH_INFO_PEER rta2 = NLMSG_TAIL(nlmsg); rta2->rta_type = VETH_INFO_PEER; rta2->rta_len = RTA_LENGTH(0); nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta2->rta_len); nlmsg->nlmsg_len += sizeof(struct ifinfomsg); // IFLA_IFNAME rta = NLMSG_TAIL(nlmsg); rta->rta_type = IFLA_IFNAME; rta->rta_len = RTA_LENGTH(strlen(veth1)); memcpy(RTA_DATA(rta), veth1, strlen(veth1)); nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len); rta2->rta_len = (void *)NLMSG_TAIL(nlmsg) - (void *)rta2; rta1->rta_len = (void *)NLMSG_TAIL(nlmsg) - (void *)rta1; rta0->rta_len = (void *)NLMSG_TAIL(nlmsg) - (void *)rta0; // IFLA_IFNAME rta = NLMSG_TAIL(nlmsg); rta->rta_type = IFLA_IFNAME; rta->rta_len = RTA_LENGTH(strlen(veth0)); memcpy(RTA_DATA(rta), veth0, strlen(veth0)); nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + RTA_ALIGN(rta->rta_len); return uwsgi_nl_send(nlmsg); } int uwsgi_nl_send(struct nlmsghdr *nlmsg) { struct sockaddr_nl nladdr; struct iovec iov = { .iov_base = (void*)nlmsg, .iov_len = nlmsg->nlmsg_len, }; struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; int ret; int nlfd; memset(&nladdr, 0, sizeof(struct sockaddr_nl)); nladdr.nl_family = AF_NETLINK; nladdr.nl_pid = 0; nladdr.nl_groups = 0; nlfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (nlfd < 0) { uwsgi_error("socket()"); free(nlmsg); return -1; } ret = sendmsg(nlfd, &msg, 0); if (ret < 0) { uwsgi_error("sendmsg()"); free(nlmsg); close(nlfd); return -1; } ret = recvmsg(nlfd, &msg, 0); if (ret < 0) { uwsgi_error("recvmsg()"); free(nlmsg); close(nlfd); return -1; } if (nlmsg->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(nlmsg); ret = err->error; } free(nlmsg); close(nlfd); return ret; } #endif uwsgi-2.0.29/lib/sun_fixes.c000066400000000000000000000012041477626554400157000ustar00rootroot00000000000000/* function written by Ben Taylor (found in the qemu-devel list) */ #include "../uwsgi.h" time_t timegm(struct tm *t) { time_t tl, tb; struct tm *tg; tl = mktime (t); if (tl == -1) { t->tm_hour--; tl = mktime (t); if (tl == -1) return -1; /* can't deal with output from strptime */ tl += 3600; } tg = gmtime (&tl); tg->tm_isdst = 0; tb = mktime (tg); if (tb == -1) { tg->tm_hour--; tb = mktime (tg); if (tb == -1) return -1; /* can't deal with output from gmtime */ tb += 3600; } return (tl - (tb - tl)); } uwsgi-2.0.29/logo_uWSGI.png000066400000000000000000000135231477626554400154560ustar00rootroot00000000000000PNG  IHDRI>ItEXtSoftwareAdobe ImageReadyqe<IDATx] pTu@la(PQicB~\@fi:Mʴ8q(+&VucŢD8^!]~Wjyᄃiw{ww=>KP?id`2+! cԓm TK*/~?Z~i:=ݩlө^yUdw5$R?z}Y-_{x N;5]n}=ۻ}=_վqtl靛mIKKMHk(((m7n9ϟo}{bsNlWydߛ%s-]ޮUUjڂqڀmx`'Lnjk8@#-JMǒ;n+ONInp2k =S-ccY29##DA_yHY/w|u3UE zEmkWo|TEß`z ϯ~r(5ϝ=bE oQэO \i722jmXeD:naf?sFFPt]Z q:;*^CV@tG6'*t 7 m@]C\|n 4=s118`{zzIt4[^ݷdEƕ G$CR<ʸB~Ԭ>t:- X扛\(9VyD+:S'_;&O%?[^?C/hA=L2PZNkyy$+Ғ𴘪t$Dpje@ T`ZVH\y3ݛ.5ڐ;*S [n` eAy :Xf+UdQ|?ICY# ifV;(0"׼pE5XBR/Rj`;Q ǿ4^vm[F܃_>l)EwúrVjOqdi)A3Ϭ t|_{w~Y'[1P"z{r~#rȟ7vܼ`4~bd Wuuy7GS wߟ7vnQ`z@Hpx[`9ޞZqh;c4a;؜XL UkFNHP72}PxsJ7&g~%"0!v>`s_)ݧndnނ>j?WFCQʳx}7ߠ&eF9-;.n_G/5R|Q/5jEðߦ:*]WO> T+zI<HI$JچD5@18;Qg$Xcg6!ґ2ͭQA slB RNHiE6{h /?V -uεoӒ> KؘQsPvN/)=[VJCҲZS~^,\0^`O6Uk|\+XsT늶lܰW/=XZ fVlN4E$ɛe :!38 ЩcɸysoFpպBYZw_EQ}+fvˊU)$- !u +ZhYWJ QO+n^!=1A`Ď%Xu_#uD Fّ; P2 [PUÏ豒%n*f'R.7#qUc)FGG*:.o`} z"YŎk)u"-P,ŲeK/m2k;Cc)R"zOT~( S*862mh@ߡ5oסnu8>V :)F[D FxİȚ1,*2ko][id;Tځi#܈(>7A6aŇ ЎbI9Xbt`S$LVRi ވv(:u<~'1?X6q.m)LiP*[-d)P\~XUjiw8oK]nR꡶ZO"YDSZTjk>dǕPZ!Ѥ Sm|:.dwE*)-~B:QN)n7؀9S{&RISTKHBsڷ#lhV:/lbN 5q0aw~̽!x݁8THWx[4m-+WW';:?n;u-Еjb#OyنT:J6mATn͕0龱/р:^DN׮UJy|{jZ٥JIͱԜtD53PG3);Nd}$f3w_c@`Mh k?N6\mU97ܰ8s]Y?X}|р꾧. R&ҫWqulsS:dyդ)LV|Ԝx9ՠysG\P᎒3Y ;l/˗t|^MtYq+;IK`q~1eScgǧ_')bSp+wXdDl36##+Jt֨Ο?+LY*}!r!jsrXݝwm|DLDT2s$ iW啑U^W靱崸xJ]N0VR#[.]Lu@ X@P'Nk,df,PXNXh %Rx@9)44+,75Bc5 ue p]ϲk ta!X:<ڜƒI܇LaN'KNNUU(&;SFEE6kdP'S=F|`@wonok}`aB; RhI%HQ<Իpp&)v;s:#5UW;NmZ *,!e\ʥQ`Gfş1ɷQYkzDR+EA}XVhiL#a|je K>Vɐ8A#Rs#-IeEcIǵT' ѯ UltQ[^lu>n?VGD>O+1ͭYF/|mc!9h1ҷGMH; "v7+ʟTvAPi(IӤ5D}ZaWD\\Xremq?y Ul:pDyI3֫:yY,J^l +wz?GaDոY`lk`ںD ޝ!@W%q!˫o?W@;m1U|{?9/#gPIXC9lB-- n%ST ~P!g^\VˀMJPACpj:u8/>x%YlNQɮj:Qx^?hurxX]YHXWⰐ/"Sa@5 b`yDEbHLl`b'C5EMg#jg6Fgz?zD#*-VFKhoA/;,͖̒rYFb6'Sr^g׷!%[$GaO ^79eҖwӂn:D'e/P~Rkz#sAnP'v:bV%v^eLWiPg4`aҒԛRxi4Mk`∤coEB}zo33˭X3/hٜ,fౝ'A[F U* z9Y hsBOb"N~j/+E,Z\A!DZ|b>쌢vW͖PH-5iSl?&AǕH#`WX6(.% %5 N#*tKy~%MɋZ&/3H ="QYH)/fqM(.9᳀ ˢ3J[Hyݝ&j<&},`#H`txE۱8,z,cWHX(jU*@-c0@4gM6a~^+VI4H.Hs!  V> W4Swv{r 儏Vo#FPc~Gz״EUF5&ҚͶC>#a2(T=pb r)rN M^hp{bazhm_OУc#ˏijU6T9#v~Q[ vKN K}Ik=bF cj*ym6bK/؞i عY/POly25GkMlK%3_KɭN+{,Nad( LCmigݕaw@;66jz T=ˮ;peO5:4yyeI".ωW%ͱDd6DLr:SAu=QRԅ,BX283o4XwtC1 DJRZZq;n<"f\ 0HZx˭j P/X[ܰhWqHؼUǯt/5-m1(ڎ0'l]㕑LJbQبgVhv 띣-9/f 68h9ZX ^СbVZX.?3{Yv{.a ~<ɕv8>Z1ʠEkYD qXt$Gjl`Po`xف|rK¢ݥe 3c7KBgѓUI5&AJcP@kq{ڞ] @ /PڑI_z\epUUkVcG6B[5)$J{<38-/^6ٙe*b(>dTA3h 5L6ԈGP2pa;cK`NiyуdTČX#QCe>'Uͺ1cf@6 n+=8s~oۋ%f1I*&gX\{KXa6iaOȮ\O@ӵq5x}an!=o\bkUw?xaLW®' (SZ|zzˠ:ڃ6l)pIw8}ⳗa Q-"vp )ev#.gRFK3{!7Y $ANxfe%J &]OvpGʽ+Q_9gSZIENDB`uwsgi-2.0.29/logo_uWSGI.svg000066400000000000000000000100561477626554400154670ustar00rootroot00000000000000 uwsgi-2.0.29/mongrel2-uwsgi.conf000066400000000000000000000012311477626554400165130ustar00rootroot00000000000000main = Server( uuid="f400bf85-4538-4f7a-8908-67e313d515c2", access_log="/logs/access.log", error_log="/logs/error.log", chroot="./", default_host="192.168.173.18", name="test", pid_file="/run/mongrel2.pid", port=6767, hosts = [ Host(name="192.168.173.18", routes={ '/': Handler(send_spec='tcp://192.168.173.18:9999', send_ident='54c6755b-9628-40a4-9a2d-cc82a816345e', recv_spec='tcp://192.168.173.18:9998', recv_ident='') }) ] ) settings = {'upload.temp_store':'tmp/mongrel2.upload.XXXXXX'} servers = [main] uwsgi = { 'socket':':3031', 'master':'true'} uwsgi-2.0.29/plugins/000077500000000000000000000000001477626554400144475ustar00rootroot00000000000000uwsgi-2.0.29/plugins/airbrake/000077500000000000000000000000001477626554400162275ustar00rootroot00000000000000uwsgi-2.0.29/plugins/airbrake/airbrake_plugin.c000066400000000000000000000207241477626554400215360ustar00rootroot00000000000000#include #include #include extern struct uwsgi_server uwsgi; struct uwsgi_airbrake_config { int first; char *arg; char *apikey; char *env; }; struct uwsgi_airbrake_opt { char *name; CURLoption option; void (*func)(CURL *, CURLoption, char *, struct uwsgi_airbrake_config*); }; static void uwsgi_airbrake_ssl(CURL *curl, CURLoption option, char *arg, struct uwsgi_airbrake_config *uacc) { curl_easy_setopt(curl, option, (long)CURLUSESSL_ALL); } static void uwsgi_airbrake_int(CURL *curl, CURLoption option, char *arg, struct uwsgi_airbrake_config *uacc) { curl_easy_setopt(curl, option, atoi(arg)); } static void uwsgi_airbrake_set_apikey(CURL *curl, CURLoption option, char *arg, struct uwsgi_airbrake_config *uacc) { uacc->apikey = arg; } static void uwsgi_airbrake_set_env(CURL *curl, CURLoption option, char *arg, struct uwsgi_airbrake_config *uacc) { uacc->env = arg; } static struct uwsgi_airbrake_opt uaco[] = { {"url", CURLOPT_URL, NULL}, {"apikey", 0, uwsgi_airbrake_set_apikey}, {"env", 0, uwsgi_airbrake_set_env}, {"ssl", CURLOPT_USE_SSL, uwsgi_airbrake_ssl}, {"timeout", CURLOPT_TIMEOUT, uwsgi_airbrake_int}, {"conn_timeout", CURLOPT_CONNECTTIMEOUT, uwsgi_airbrake_int}, {NULL, 0, NULL}, }; static void uwsgi_airbrake_setopt(CURL *curl, char *opt, struct uwsgi_airbrake_config *uacc) { struct uwsgi_airbrake_opt *o = uaco; char *equal = strchr(opt,'='); if (!equal) { if (!uacc->first) { curl_easy_setopt(curl, CURLOPT_URL, opt); uacc->first = 1; } return; } uacc->first = 1; *equal = 0; while(o->name) { if (!strcmp(o->name, opt)) { if (o->func) { o->func(curl, o->option, equal+1, uacc); } else { curl_easy_setopt(curl, o->option, equal+1); } goto end; } o++; } end: *equal = '='; } char *uwsgi_format_airbrake_backtrace(struct uwsgi_thread *ut) { struct uwsgi_airbrake_config *uacc = (struct uwsgi_airbrake_config *) ut->data; xmlChar *xmlbuff; int buffersize; xmlDocPtr doc = NULL; xmlNodePtr notice_node = NULL, node = NULL, line_node = NULL, errnode = NULL; char *msg = NULL; doc = xmlNewDoc(BAD_CAST "1.0"); notice_node = xmlNewNode(NULL, BAD_CAST "notice"); xmlNewProp(notice_node, BAD_CAST "version", BAD_CAST "2.3"); xmlDocSetRootElement(doc, notice_node); xmlNewChild(notice_node, NULL, BAD_CAST "api-key", BAD_CAST uacc->apikey); node = xmlNewChild(notice_node, NULL, BAD_CAST "notifier", NULL); xmlNewChild(node, NULL, BAD_CAST "name", BAD_CAST "uWSGI"); xmlNewChild(node, NULL, BAD_CAST "version", BAD_CAST UWSGI_VERSION); xmlNewChild(node, NULL, BAD_CAST "url", BAD_CAST "https://github.com/unbit/uwsgi"); // request env node = xmlNewChild(notice_node, NULL, BAD_CAST "request", NULL); node = xmlNewChild(node, NULL, BAD_CAST "cgi-data", NULL); line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST UWSGI_VERSION); xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "uwsgi_version"); line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST __VERSION__); xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "compiled_with_version"); struct utsname uuts; #ifdef __sun__ if (uname(&uuts) < 0) { #else if (uname(&uuts)) { #endif uwsgi_error("uname()"); } else { line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.sysname); xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "os_sysname"); char *os_version = uwsgi_concat3(uuts.release, "-", uuts.version); line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST os_version); xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "os_version"); free(os_version); line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.machine); xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "machine"); line_node = xmlNewChild(node, NULL, BAD_CAST "var", BAD_CAST uuts.nodename); xmlNewProp(line_node, BAD_CAST "key", BAD_CAST "nodename"); } // end request env node = xmlNewChild(notice_node, NULL, BAD_CAST "server-environment", NULL); xmlNewChild(node, NULL, BAD_CAST "app-version", BAD_CAST UWSGI_VERSION); if (uacc->env) { xmlNewChild(node, NULL, BAD_CAST "environment-name", BAD_CAST uacc->env); } else { xmlNewChild(node, NULL, BAD_CAST "environment-name", BAD_CAST UWSGI_VERSION); } errnode = xmlNewChild(notice_node, NULL, BAD_CAST "error", NULL); xmlNewChild(errnode, NULL, BAD_CAST "class", BAD_CAST "RuntimeError"); node = xmlNewChild(errnode, NULL, BAD_CAST "backtrace", NULL); char *ctx = NULL; char *text = uwsgi_str(ut->buf); char *p = strtok_r(text, "\n", &ctx); while (p) { // skip log messages if (!uwsgi_startswith(p, "***", 3)) goto next; // backtrace line looks like this: uwsgi(simple_loop_run+0xc5) [0x451555] // we take binary/lib as filename // and extract method name from remaining string char *n = strchr(p, '('); if (n) { *n = 0; char *pls = strchr(n+1, '+'); if (pls) { *pls = 0; } if (!strcmp("uwsgi_backtrace", n+1) || !strcmp("what_i_am_doing", n+1)) { goto next; } else if (!strcmp("uwsgi_fpe", n+1)) { msg = uwsgi_concat4("uWSGI FPE at ", n+1, " in ", p); goto next; } if (!msg) { if (strlen(n+1)) { msg = uwsgi_concat4("uWSGI segfault at ", n+1, " in ", p); } else { // method name might be missing msg = uwsgi_concat2("uWSGI segfault in ", p); } } // skip empty lines if (!p) goto next; line_node = xmlNewChild(node, NULL, BAD_CAST "line", NULL); if ((n+1)[0] == ')') { xmlNewProp(line_node, BAD_CAST "method", BAD_CAST "()"); } else { xmlNewProp(line_node, BAD_CAST "method", BAD_CAST n+1); } xmlNewProp(line_node, BAD_CAST "file", BAD_CAST p); //xmlNewProp(line_node, BAD_CAST "number", BAD_CAST "0"); } next: p = strtok_r(NULL, "\n", &ctx); } xmlNewChild(errnode, NULL, BAD_CAST "message", BAD_CAST msg); xmlDocDumpFormatMemory(doc, &xmlbuff, &buffersize, 1); xmlFreeDoc(doc); xmlCleanupParser(); xmlMemoryDump(); free(msg); free(text); return (char *) xmlbuff; } static void uwsgi_airbrake_loop(struct uwsgi_thread *ut) { int interesting_fd; ut->buf = uwsgi_malloc(uwsgi.log_master_bufsize); CURL *curl = curl_easy_init(); // ARGH !!! if (!curl) return; curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, uwsgi.socket_timeout); curl_easy_setopt(curl, CURLOPT_TIMEOUT, uwsgi.socket_timeout); curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); curl_easy_setopt(curl, CURLOPT_READDATA, ut); curl_easy_setopt(curl, CURLOPT_POST, 1L); struct curl_slist *expect = NULL; expect = curl_slist_append(expect, "Expect:"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, expect); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); struct uwsgi_airbrake_config *uacc = (struct uwsgi_airbrake_config *) ut->data; char *opts = uwsgi_str(uacc->arg); // fill curl options char *ctx = NULL; char *p = strtok_r(opts, ";", &ctx); while(p) { uwsgi_airbrake_setopt(curl, uwsgi_str(p), uacc); p = strtok_r(NULL, ";", &ctx); } for(;;) { int ret = event_queue_wait(ut->queue, -1, &interesting_fd); if (ret < 0) return; if (ret == 0) continue; if (interesting_fd != ut->pipe[1]) continue; ssize_t rlen = read(ut->pipe[1], ut->buf, uwsgi.log_master_bufsize); if (rlen <= 0) continue; ut->pos = 0; ut->len = (size_t) rlen; ut->custom0 = 0; char *notice = uwsgi_format_airbrake_backtrace(ut); curl_slist_append(expect, "Accept: */*"); curl_slist_append(expect, "Content-Type: text/xml; charset=utf-8"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, expect); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, notice); curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(notice)); curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t) ut->len); CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { uwsgi_log_alarm("-curl] curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } free(notice); } } static void uwsgi_airbrake_init(struct uwsgi_alarm_instance *uai) { struct uwsgi_airbrake_config *uacc = uwsgi_calloc(sizeof(struct uwsgi_airbrake_config)); uacc->arg = uai->arg; struct uwsgi_thread *ut = uwsgi_thread_new_with_data(uwsgi_airbrake_loop, uacc); if (!ut) return; uai->data_ptr = ut; } static void uwsgi_airbrake_func(struct uwsgi_alarm_instance *uai, char *msg, size_t len) { struct uwsgi_thread *ut = (struct uwsgi_thread *) uai->data_ptr; ut->rlen = write(ut->pipe[0], msg, len); } static void uwsgi_airbrake_load(void) { uwsgi_register_alarm("airbrake", uwsgi_airbrake_init, uwsgi_airbrake_func); } struct uwsgi_plugin airbrake_plugin = { .name = "airbrake", .on_load = uwsgi_airbrake_load, }; uwsgi-2.0.29/plugins/airbrake/uwsgiplugin.py000066400000000000000000000002701477626554400211550ustar00rootroot00000000000000from uwsgiconfig import spcall NAME='airbrake' CFLAGS = [spcall('xml2-config --cflags')] LDFLAGS = [] LIBS = ['-lcurl', spcall('xml2-config --libs')] GCC_LIST = ['airbrake_plugin'] uwsgi-2.0.29/plugins/alarm_curl/000077500000000000000000000000001477626554400165705ustar00rootroot00000000000000uwsgi-2.0.29/plugins/alarm_curl/alarm_curl_plugin.c000066400000000000000000000170061477626554400224370ustar00rootroot00000000000000#include #include extern struct uwsgi_server uwsgi; struct uwsgi_alarm_curl { CURL *curl; struct uwsgi_thread *ut; int pos; int blen; char *body; int hlen; char hdr[]; }; struct uwsgi_alarm_curl_config { char *url; char *subject; char *to; }; struct uwsgi_alarm_curl_opt { char *name; CURLoption option; void (*func)(CURL *, CURLoption, char *, struct uwsgi_alarm_curl_config*); }; #ifdef CURLPROTO_SMTP static void uwsgi_alarm_curl_to(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc) { uacc->to = arg; struct curl_slist *list = NULL; char *items = uwsgi_str(arg); char *ctx = NULL; char *p = strtok_r(items, ",", &ctx); while(p) { list = curl_slist_append(list, p); p = strtok_r(NULL, ",", &ctx); } curl_easy_setopt(curl, option, list); free(items); } #endif static void uwsgi_alarm_curl_ssl(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc) { curl_easy_setopt(curl, option, (long)CURLUSESSL_ALL); } static void uwsgi_alarm_curl_int(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc) { curl_easy_setopt(curl, option, atoi(arg)); } static void uwsgi_alarm_curl_set_subject(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc) { uacc->subject = arg; } static void uwsgi_alarm_curl_url(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc) { #ifndef CURLPROTO_SMTP if (!uwsgi_strnicmp(arg, 4, "smtp", 4)) { uwsgi_error("Please update libcurl to use SMTP protocol.\n"); exit(1); } #endif uacc->url = arg; curl_easy_setopt(curl, option, arg); } static void uwsgi_alarm_curl_ssl_insecure(CURL *curl, CURLoption option, char *arg, struct uwsgi_alarm_curl_config *uacc) { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); } static struct uwsgi_alarm_curl_opt uaco[] = { {"url", CURLOPT_URL, uwsgi_alarm_curl_url}, #ifdef CURLPROTO_SMTP {"mail_to", CURLOPT_MAIL_RCPT, uwsgi_alarm_curl_to}, {"mail_from", CURLOPT_MAIL_FROM, NULL}, #endif {"subject", 0, uwsgi_alarm_curl_set_subject}, {"ssl", CURLOPT_USE_SSL, uwsgi_alarm_curl_ssl}, {"ssl_insecure", 0, uwsgi_alarm_curl_ssl_insecure}, {"auth_user", CURLOPT_USERNAME, NULL}, {"auth_pass", CURLOPT_PASSWORD, NULL}, {"method", CURLOPT_CUSTOMREQUEST, NULL}, {"timeout", CURLOPT_TIMEOUT, uwsgi_alarm_curl_int}, {"conn_timeout", CURLOPT_CONNECTTIMEOUT, uwsgi_alarm_curl_int}, {NULL, 0, NULL}, }; static void uwsgi_alarm_curl_setopt(CURL *curl, char *opt, struct uwsgi_alarm_curl_config *uacc) { struct uwsgi_alarm_curl_opt *o = uaco; char *equal = strchr(opt,'='); if (!equal || !uacc->url) { uwsgi_alarm_curl_url(curl, CURLOPT_URL, opt, uacc); return; } *equal = 0; while(o->name) { if (!strcmp(o->name, opt)) { if (o->func) { o->func(curl, o->option, equal+1, uacc); } else { curl_easy_setopt(curl, o->option, equal+1); } break; } o++; } } static size_t uwsgi_alarm_curl_read_callback(void *ptr, size_t size, size_t nmemb, void *userp) { struct uwsgi_alarm_curl *uac = userp; size_t full_size = size * nmemb; int remains = full_size; if (uac->pos < uac->hlen) { if (remains > uac->hlen - uac->pos) { memcpy(ptr, uac->hdr + uac->pos, uac->hlen - uac->pos); ptr += uac->hlen - uac->pos; remains -= uac->hlen - uac->pos; uac->pos = uac->hlen; } else { memcpy(ptr, uac->hdr + uac->pos, remains); uac->pos += remains; return full_size; } } if (remains > uac->blen + uac->hlen - uac->pos) { memcpy(ptr, uac->body + uac->pos - uac->hlen, uac->blen + uac->hlen - uac->pos); remains -= uac->blen + uac->hlen - uac->pos; uac->pos = uac->blen + uac->hlen; return full_size - remains; } memcpy(ptr, uac->body + uac->pos - uac->hlen, remains); uac->pos += remains; return full_size; } static struct uwsgi_alarm_curl *uwsgi_alarm_curl_alloc(struct uwsgi_alarm_curl_config *uacc) { char *addr; struct uwsgi_alarm_curl *uac; size_t required = 0; if (uacc->to) required += 4 + strlen(uacc->to) + 2; if (uacc->subject) required += 9 + strlen(uacc->subject) + 2; if (required) required += 2; /* newline between MIME header and body */ uac = uwsgi_malloc(sizeof(*uac) + required); uac->hlen = required; addr = uac->hdr; if (uacc->to) { memcpy(addr, "To: ", 4); addr += 4; memcpy(addr, uacc->to, strlen(uacc->to)); addr += strlen(uacc->to); *addr++ = '\r'; *addr++ = '\n'; } if (uacc->subject) { memcpy(addr, "Subject: ", 9); addr += 9; memcpy(addr, uacc->subject, strlen(uacc->subject)); addr += strlen(uacc->subject); *addr++ = '\r'; *addr++ = '\n'; } if (required) { *addr++ = '\r'; *addr = '\n'; } return uac; } static struct uwsgi_alarm_curl *uwsgi_alarm_curl_init_curl(struct uwsgi_alarm_instance *uai) { CURL *curl = curl_easy_init(); if (!curl) { uwsgi_error("Failed to initialize libcurl.\n"); exit(1); } curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, uwsgi.socket_timeout); curl_easy_setopt(curl, CURLOPT_TIMEOUT, uwsgi.socket_timeout); curl_easy_setopt(curl, CURLOPT_READFUNCTION, uwsgi_alarm_curl_read_callback); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); curl_easy_setopt(curl, CURLOPT_POST, 1L); struct curl_slist *expect = NULL; expect = curl_slist_append(expect, "Expect:"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, expect); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); struct uwsgi_alarm_curl_config uacc; memset(&uacc, 0, sizeof(uacc)); char *opts = uwsgi_str(uai->arg); // fill curl options char *ctx = NULL; char *p = strtok_r(opts, ";", &ctx); while(p) { uwsgi_alarm_curl_setopt(curl, p, &uacc); p = strtok_r(NULL, ";", &ctx); } if (!uacc.url) { uwsgi_error("An URL is required to trigger curl-based alarm.\n"); exit(1); } struct uwsgi_alarm_curl *uac = uwsgi_alarm_curl_alloc(&uacc); curl_easy_setopt(curl, CURLOPT_READDATA, uac); free(opts); uac->curl = curl; uai->data_ptr = uac; return uac; } static void uwsgi_alarm_curl_call_curl(struct uwsgi_alarm_curl *uac, char *msg, int len) { uac->pos = 0; uac->body = msg; uac->blen = len; curl_easy_setopt(uac->curl, CURLOPT_INFILESIZE, uac->hlen + uac->blen); CURLcode res = curl_easy_perform(uac->curl); if (res != CURLE_OK) uwsgi_log_alarm("-curl] curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } static void uwsgi_alarm_curl_loop(struct uwsgi_thread *ut) { int interesting_fd; struct uwsgi_alarm_curl *uac = uwsgi_alarm_curl_init_curl(ut->data); uac->ut = ut; ut->buf = uwsgi_malloc(uwsgi.log_master_bufsize); for(;;) { int ret = event_queue_wait(ut->queue, -1, &interesting_fd); if (ret < 0) return; if (ret == 0) continue; if (interesting_fd != ut->pipe[1]) continue; ssize_t rlen = read(ut->pipe[1], ut->buf, uwsgi.log_master_bufsize); if (rlen <= 0) continue; uwsgi_alarm_curl_call_curl(uac, ut->buf, rlen); } } static void uwsgi_alarm_curl_init(struct uwsgi_alarm_instance *uai) { if (uwsgi.alarm_cheap) uwsgi_alarm_curl_init_curl(uai); else uwsgi_thread_new_with_data(uwsgi_alarm_curl_loop, uai); } // pipe the message into the thread; static void uwsgi_alarm_curl_func(struct uwsgi_alarm_instance *uai, char *msg, size_t len) { struct uwsgi_alarm_curl *uac = uai->data_ptr; if (uwsgi.alarm_cheap) uwsgi_alarm_curl_call_curl(uac, msg, len); else { struct uwsgi_thread *ut = uac->ut; ut->rlen = write(ut->pipe[0], msg, len); } } static void uwsgi_alarm_curl_load(void) { uwsgi_register_alarm("curl", uwsgi_alarm_curl_init, uwsgi_alarm_curl_func); } struct uwsgi_plugin alarm_curl_plugin = { .name = "alarm_curl", .on_load = uwsgi_alarm_curl_load, }; uwsgi-2.0.29/plugins/alarm_curl/uwsgiplugin.py000066400000000000000000000001371477626554400215200ustar00rootroot00000000000000NAME='alarm_curl' CFLAGS = [] LDFLAGS = [] LIBS = ['-lcurl'] GCC_LIST = ['alarm_curl_plugin'] uwsgi-2.0.29/plugins/alarm_speech/000077500000000000000000000000001477626554400170725ustar00rootroot00000000000000uwsgi-2.0.29/plugins/alarm_speech/alarm_speech.m000066400000000000000000000024411477626554400216740ustar00rootroot00000000000000#include "../../uwsgi.h" #import "Foundation/NSString.h" #import "AppKit/NSSpeechSynthesizer.h" @interface uWSGIAlarmSpeaker : NSObject { NSSpeechSynthesizer *synth; } -(void)speak: (NSString *)phrase; @end @implementation uWSGIAlarmSpeaker - (uWSGIAlarmSpeaker *) init { self = [super init]; synth = [[NSSpeechSynthesizer alloc] initWithVoice:nil]; return self; } - (void)speak:(NSString *)phrase { [synth startSpeakingString:phrase]; } @end // generate a uwsgi signal on alarm void uwsgi_alarm_speech_init(struct uwsgi_alarm_instance *uai) { uai->data_ptr = [[uWSGIAlarmSpeaker alloc] init]; } void uwsgi_alarm_speech_func(struct uwsgi_alarm_instance *uai, char *msg, size_t len) { uWSGIAlarmSpeaker *say = (uWSGIAlarmSpeaker *) uai->data_ptr; NSString *phrase = [[NSString alloc] initWithBytes:msg length:len encoding:NSUTF8StringEncoding]; [say speak:phrase]; [phrase release]; } static void uwsgi_alarm_speech_load(void) { uwsgi_register_alarm("speech", uwsgi_alarm_speech_init, uwsgi_alarm_speech_func); } struct uwsgi_plugin alarm_speech_plugin = { .name = "alarm_speech", .on_load = uwsgi_alarm_speech_load, }; uwsgi-2.0.29/plugins/alarm_speech/uwsgiplugin.py000066400000000000000000000003551477626554400220240ustar00rootroot00000000000000import os NAME='alarm_speech' uwsgi_os = os.uname()[0] LDFLAGS = [] if uwsgi_os == "Darwin": CFLAGS = [] LIBS = ['-framework AppKit'] else: CFLAGS = ['-I /usr/include/GNUstep'] LIBS = [] GCC_LIST = ['alarm_speech.m'] uwsgi-2.0.29/plugins/alarm_xmpp/000077500000000000000000000000001477626554400166075ustar00rootroot00000000000000uwsgi-2.0.29/plugins/alarm_xmpp/alarm_xmpp_plugin.c000066400000000000000000000013511477626554400224710ustar00rootroot00000000000000#include "../../uwsgi.h" void uwsgi_alarm_xmpp_loop(struct uwsgi_thread *); static void uwsgi_alarm_xmpp_init(struct uwsgi_alarm_instance *uai) { struct uwsgi_thread *ut = uwsgi_thread_new_with_data(uwsgi_alarm_xmpp_loop, uai->arg); if (!ut) return; uai->data_ptr = ut; } // pipe the message into the thread; static void uwsgi_alarm_xmpp_func(struct uwsgi_alarm_instance *uai, char *msg, size_t len) { struct uwsgi_thread *ut = (struct uwsgi_thread *) uai->data_ptr; ut->rlen = write(ut->pipe[0], msg, len); } static void uwsgi_alarm_xmpp_load(void) { uwsgi_register_alarm("xmpp", uwsgi_alarm_xmpp_init, uwsgi_alarm_xmpp_func); } struct uwsgi_plugin alarm_xmpp_plugin = { .name = "alarm_xmpp", .on_load = uwsgi_alarm_xmpp_load, }; uwsgi-2.0.29/plugins/alarm_xmpp/gloox.cc000066400000000000000000000106301477626554400202460ustar00rootroot00000000000000#include "../../uwsgi.h" #include #include #include #include #include extern struct uwsgi_server uwsgi; using namespace gloox; class Jabbo : public ConnectionListener{ public: Jabbo(struct uwsgi_thread *ut, char *jab_username, char *jab_password, char *dests) { u_thread = ut; dest = NULL; char *ctx = NULL; char *p = strtok_r(dests, ",", &ctx); while(p) { uwsgi_string_new_list(&dest, p); p = strtok_r(NULL, ",", &ctx); } full_jid = jab_username; JID jid(jab_username); client = new Client( jid, jab_password ); client->registerConnectionListener(this); u_connected = 0; client->connect(false); fd = static_cast( client->connectionImpl() )->socket(); } ~Jabbo() { delete client; } void send(char *buf, size_t len) { struct uwsgi_string_list *usl = dest; while(usl) { JID jid(usl->value); std::string text(buf, len); Message msg(Message::Chat, jid, text); client->send(msg); usl = usl->next; } } virtual void onConnect() { event_queue_add_fd_read(u_thread->queue, fd); event_queue_add_fd_read(u_thread->queue, u_thread->pipe[1]); u_connected = 1; uwsgi_log_alarm("-xmpp] (%s) connected to the XMPP server\n", full_jid); } virtual void onDisconnect(ConnectionError e) { uwsgi_log_alarm("-xmpp] (%s) trying reconnect to the XMPP server...\n", full_jid); if (u_connected) { // no need to remove it as it is already closed... //event_queue_del_fd(u_thread->queue, fd, event_queue_read()); event_queue_del_fd(u_thread->queue, u_thread->pipe[1], event_queue_read()); } sleep(1); u_connected = 0; client->connect(false); fd = static_cast( client->connectionImpl() )->socket(); } virtual void onResourceBindError(const Error *error) { uwsgi_log_alarm("-xmpp] (%s) onResourceBindError(): %s\n", full_jid, error->text().c_str()); client->disconnect(); } virtual void onSessionCreateError(const Error *error) { uwsgi_log_alarm("-xmpp] (%s) onSessionCreateError(): %s\n", full_jid, error->text().c_str()); client->disconnect(); } virtual bool onTLSConnect(const CertInfo& info) { return true; } Client* client; char *full_jid; int fd; int u_connected; struct uwsgi_thread *u_thread; struct uwsgi_string_list *dest; }; extern "C" void uwsgi_alarm_xmpp_loop(struct uwsgi_thread *ut) { int interesting_fd; ut->buf = (char *) uwsgi_malloc(uwsgi.log_master_bufsize); char *xmpp_username = (char *) ""; char *xmpp_password = (char *) ""; char *xmpp_dests = (char *) ""; // 0 -> username, 1 -> password, 2-> dest list int opt_state = 0; // fill xmpp options char *ctx = NULL; char *opts = uwsgi_str((char *)ut->data); char *p = strtok_r(opts, ";", &ctx); while(p) { switch(opt_state) { case 0: xmpp_username = p; opt_state = 1; break; case 1: xmpp_password = p; opt_state = 2; break; case 2: xmpp_dests = p; opt_state = 3; break; default: break; } p = strtok_r(NULL, ";", &ctx); } // do not process loglines til the jabber account is connected event_queue_del_fd(ut->queue, ut->pipe[1], event_queue_read()); Jabbo j(ut, xmpp_username, xmpp_password, xmpp_dests); int timeout = 0; for(;;) { if (j.u_connected) { timeout = -1; } else { timeout = 0; } int ret = event_queue_wait(ut->queue, timeout, &interesting_fd); if (ret < 0) continue; if (ret > 0 && interesting_fd == ut->pipe[1]) { ssize_t rlen = read(ut->pipe[1], ut->buf, uwsgi.log_master_bufsize); if (rlen <= 0) continue; if (j.u_connected) { j.send(ut->buf, rlen); } } else if (ret == 0 || (ret > 0 && j.fd > -1 && interesting_fd == j.fd)) { j.client->recv(); } } } uwsgi-2.0.29/plugins/alarm_xmpp/uwsgiplugin.py000066400000000000000000000001541477626554400215360ustar00rootroot00000000000000NAME='alarm_xmpp' CFLAGS = [] LDFLAGS = [] LIBS = ['-lgloox'] GCC_LIST = ['alarm_xmpp_plugin', 'gloox.cc'] uwsgi-2.0.29/plugins/asyncio/000077500000000000000000000000001477626554400161145ustar00rootroot00000000000000uwsgi-2.0.29/plugins/asyncio/asyncio.c000066400000000000000000000272451477626554400177370ustar00rootroot00000000000000#include "../python/uwsgi_python.h" /* python >= 3.4 asyncio (PEP 3156) loop engine EXPERIMENTAL !!! Author: Roberto De Ioris */ extern struct uwsgi_server uwsgi; extern struct uwsgi_python up; static struct uwsgi_asyncio { PyObject *mod; PyObject *loop; PyObject *request; PyObject *hook_fd; PyObject *hook_timeout; PyObject *hook_fix; } uasyncio; #define free_req_queue uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = wsgi_req static void uwsgi_opt_setup_asyncio(char *opt, char *value, void *null) { // set async mode uwsgi_opt_set_int(opt, value, &uwsgi.async); if (uwsgi.socket_timeout < 30) { uwsgi.socket_timeout = 30; } // set loop engine uwsgi.loop = "asyncio"; } static struct uwsgi_option asyncio_options[] = { {"asyncio", required_argument, 0, "a shortcut enabling asyncio loop engine with the specified number of async cores and optimal parameters", uwsgi_opt_setup_asyncio, NULL, UWSGI_OPT_THREADS}, {0, 0, 0, 0, 0, 0, 0}, }; static void gil_asyncio_get() { pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure()); } static void gil_asyncio_release() { PyGILState_Release((PyGILState_STATE) pthread_getspecific(up.upt_gil_key)); } static int uwsgi_asyncio_wait_read_hook(int fd, int timeout) { struct wsgi_request *wsgi_req = current_wsgi_req(); if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOl", fd, uasyncio.hook_fd,(long) wsgi_req) == NULL) { goto error; } PyObject *ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOl", timeout, uasyncio.hook_timeout, (long)wsgi_req); if (!ob_timeout) { if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", fd) == NULL) PyErr_Print(); goto error; } // back to loop if (uwsgi.schedule_to_main) uwsgi.schedule_to_main(wsgi_req); // back from loop if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", fd) == NULL) PyErr_Print(); if (PyObject_CallMethod(ob_timeout, "cancel", NULL) == NULL) PyErr_Print(); Py_DECREF(ob_timeout); if (wsgi_req->async_timed_out) return 0; return 1; error: PyErr_Print(); return -1; } static int uwsgi_asyncio_wait_write_hook(int fd, int timeout) { struct wsgi_request *wsgi_req = current_wsgi_req(); if (PyObject_CallMethod(uasyncio.loop, "add_writer", "iOl", fd, uasyncio.hook_fd,(long) wsgi_req) == NULL) { goto error; } PyObject *ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOl", timeout, uasyncio.hook_timeout, (long)wsgi_req); if (!ob_timeout) { if (PyObject_CallMethod(uasyncio.loop, "remove_writer", "i", fd) == NULL) PyErr_Print(); goto error; } // back to loop if (uwsgi.schedule_to_main) { uwsgi.schedule_to_main(wsgi_req); } // back from loop if (PyObject_CallMethod(uasyncio.loop, "remove_writer", "i", fd) == NULL) PyErr_Print(); if (PyObject_CallMethod(ob_timeout, "cancel", NULL) == NULL) PyErr_Print(); Py_DECREF(ob_timeout); if (wsgi_req->async_timed_out) return 0; return 1; error: PyErr_Print(); return -1; } static PyObject *py_uwsgi_asyncio_request(PyObject *self, PyObject *args) { long wsgi_req_ptr = 0; int timed_out = 0; if (!PyArg_ParseTuple(args, "l|i:uwsgi_asyncio_request", &wsgi_req_ptr, &timed_out)) { uwsgi_log_verbose("[BUG] invalid arguments for asyncio callback !!!\n"); exit(1); } struct wsgi_request *wsgi_req = (struct wsgi_request *) wsgi_req_ptr; uwsgi.wsgi_req = wsgi_req; PyObject *ob_timeout = (PyObject *) wsgi_req->async_timeout; if (PyObject_CallMethod(ob_timeout, "cancel", NULL) == NULL) PyErr_Print(); Py_DECREF(ob_timeout); // avoid mess when closing the request wsgi_req->async_timeout = NULL; if (timed_out > 0) { if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) PyErr_Print(); goto end; } int status = wsgi_req->socket->proto(wsgi_req); if (status > 0) { ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOli", uwsgi.socket_timeout, uasyncio.request, wsgi_req_ptr, 1); if (!ob_timeout) { if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) PyErr_Print(); goto end; } // trick for reference counting wsgi_req->async_timeout = (struct uwsgi_rb_timer *) ob_timeout; goto again; } if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) { PyErr_Print(); goto end; } if (status == 0) { // we call this two time... overengineering :( uwsgi.async_proto_fd_table[wsgi_req->fd] = NULL; uwsgi.schedule_to_req(); goto again; } end: uwsgi.async_proto_fd_table[wsgi_req->fd] = NULL; uwsgi_close_request(uwsgi.wsgi_req); free_req_queue; again: Py_INCREF(Py_None); return Py_None; } static PyObject *py_uwsgi_asyncio_accept(PyObject *self, PyObject *args) { long uwsgi_sock_ptr = 0; if (!PyArg_ParseTuple(args, "l:uwsgi_asyncio_accept", &uwsgi_sock_ptr)) { return NULL; } struct wsgi_request *wsgi_req = find_first_available_wsgi_req(); if (wsgi_req == NULL) { uwsgi_async_queue_is_full(uwsgi_now()); goto end; } uwsgi.wsgi_req = wsgi_req; struct uwsgi_socket *uwsgi_sock = (struct uwsgi_socket *) uwsgi_sock_ptr; // fill wsgi_request structure wsgi_req_setup(wsgi_req, wsgi_req->async_id, uwsgi_sock ); // mark core as used uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 1; // accept the connection (since uWSGI 1.5 all of the sockets are non-blocking) if (wsgi_req_simple_accept(wsgi_req, uwsgi_sock->fd)) { // in case of errors (or thundering herd, just reset it) uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 0; free_req_queue; goto end; } wsgi_req->start_of_request = uwsgi_micros(); wsgi_req->start_of_request_in_sec = wsgi_req->start_of_request/1000000; // enter harakiri mode if (uwsgi.harakiri_options.workers > 0) { set_harakiri(uwsgi.harakiri_options.workers); } uwsgi.async_proto_fd_table[wsgi_req->fd] = wsgi_req; // add callback for protocol if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOl", wsgi_req->fd, uasyncio.request, (long) wsgi_req) == NULL) { free_req_queue; PyErr_Print(); } // add timeout PyObject *ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOli", uwsgi.socket_timeout, uasyncio.request, (long)wsgi_req, 1); if (!ob_timeout) { if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) PyErr_Print(); free_req_queue; } else { // trick for reference counting wsgi_req->async_timeout = (struct uwsgi_rb_timer *) ob_timeout; } end: Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_asyncio_hook_fd(PyObject *self, PyObject *args) { long wsgi_req_ptr = 0; if (!PyArg_ParseTuple(args, "l:uwsgi_asyncio_hook_fd", &wsgi_req_ptr)) { return NULL; } uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr; uwsgi.schedule_to_req(); Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_asyncio_hook_timeout(PyObject *self, PyObject *args) { long wsgi_req_ptr = 0; if (!PyArg_ParseTuple(args, "l", &wsgi_req_ptr)) { return NULL; } uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr; uwsgi.wsgi_req->async_timed_out = 1; uwsgi.schedule_to_req(); Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_asyncio_hook_fix(PyObject *self, PyObject *args) { long wsgi_req_ptr = 0; if (!PyArg_ParseTuple(args, "l", &wsgi_req_ptr)) { return NULL; } uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr; uwsgi.schedule_to_req(); Py_INCREF(Py_None); return Py_None; } PyMethodDef uwsgi_asyncio_accept_def[] = { {"uwsgi_asyncio_accept", py_uwsgi_asyncio_accept, METH_VARARGS, ""} }; PyMethodDef uwsgi_asyncio_request_def[] = { {"uwsgi_asyncio_request", py_uwsgi_asyncio_request, METH_VARARGS, ""} }; PyMethodDef uwsgi_asyncio_hook_fd_def[] = { {"uwsgi_asyncio_hook_fd", py_uwsgi_asyncio_hook_fd, METH_VARARGS, ""} }; PyMethodDef uwsgi_asyncio_hook_timeout_def[] = { {"uwsgi_asyncio_hook_timeout", py_uwsgi_asyncio_hook_timeout, METH_VARARGS, ""} }; PyMethodDef uwsgi_asyncio_hook_fix_def[] = { {"uwsgi_asyncio_hook_fix", py_uwsgi_asyncio_hook_fix, METH_VARARGS, ""} }; static void uwsgi_asyncio_schedule_fix(struct wsgi_request *wsgi_req) { PyObject *cb = PyObject_CallMethod(uasyncio.loop, "call_soon", "Ol", uasyncio.hook_fix, (long) wsgi_req); if (!cb) goto error; Py_DECREF(cb); return; error: PyErr_Print(); } static void asyncio_loop() { if (!uwsgi.has_threads && uwsgi.mywid == 1) { uwsgi_log("!!! Running asyncio without threads IS NOT recommended, enable them with --enable-threads !!!\n"); } if (uwsgi.socket_timeout < 30) { uwsgi_log("!!! Running asyncio with a socket-timeout lower than 30 seconds is not recommended, tune it with --socket-timeout !!!\n"); } if (!uwsgi.async_waiting_fd_table) uwsgi.async_waiting_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd); if (!uwsgi.async_proto_fd_table) uwsgi.async_proto_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd); // get the GIL UWSGI_GET_GIL up.gil_get = gil_asyncio_get; up.gil_release = gil_asyncio_release; uwsgi.wait_write_hook = uwsgi_asyncio_wait_write_hook; uwsgi.wait_read_hook = uwsgi_asyncio_wait_read_hook; if (uwsgi.async < 2) { uwsgi_log("the asyncio loop engine requires async mode (--async )\n"); exit(1); } if (!uwsgi.schedule_to_main) { uwsgi_log("*** DANGER *** asyncio mode without coroutine/greenthread engine loaded !!!\n"); } if (!uwsgi.schedule_to_req) { uwsgi.schedule_to_req = async_schedule_to_req_green; } else { uwsgi.schedule_fix = uwsgi_asyncio_schedule_fix; } #ifndef PYTHREE PyObject *asyncio = PyImport_ImportModule("trollius"); #else PyObject *asyncio = PyImport_ImportModule("asyncio"); #endif if (!asyncio) uwsgi_pyexit; uasyncio.mod = asyncio; uasyncio.loop = PyObject_CallMethod(asyncio, "get_event_loop", NULL); if (!uasyncio.loop) uwsgi_pyexit; // main greenlet waiting for connection (one greenlet per-socket) PyObject *asyncio_accept = PyCFunction_New(uwsgi_asyncio_accept_def, NULL); Py_INCREF(asyncio_accept); uasyncio.request = PyCFunction_New(uwsgi_asyncio_request_def, NULL); if (!uasyncio.request) uwsgi_pyexit; uasyncio.hook_fd = PyCFunction_New(uwsgi_asyncio_hook_fd_def, NULL); if (!uasyncio.hook_fd) uwsgi_pyexit; uasyncio.hook_timeout = PyCFunction_New(uwsgi_asyncio_hook_timeout_def, NULL); if (!uasyncio.hook_timeout) uwsgi_pyexit; uasyncio.hook_fix = PyCFunction_New(uwsgi_asyncio_hook_fix_def, NULL); if (!uasyncio.hook_fix) uwsgi_pyexit; Py_INCREF(uasyncio.request); Py_INCREF(uasyncio.hook_fd); Py_INCREF(uasyncio.hook_timeout); Py_INCREF(uasyncio.hook_fix); // call add_handler on each socket struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while(uwsgi_sock) { if (PyObject_CallMethod(uasyncio.loop, "add_reader", "iOl", uwsgi_sock->fd, asyncio_accept, (long) uwsgi_sock) == NULL) { uwsgi_pyexit; } uwsgi_sock = uwsgi_sock->next; } if (PyObject_CallMethod(uasyncio.loop, "run_forever", NULL) == NULL) { uwsgi_pyexit; } // never here ? } static void asyncio_init() { uwsgi_register_loop( (char *) "asyncio", asyncio_loop); } struct uwsgi_plugin asyncio_plugin = { .name = "asyncio", .options = asyncio_options, .on_load = asyncio_init, }; uwsgi-2.0.29/plugins/asyncio/uwsgiplugin.py000066400000000000000000000006211477626554400210420ustar00rootroot00000000000000try: from distutils import sysconfig paths = [ sysconfig.get_python_inc(), sysconfig.get_python_inc(plat_specific=True), ] except ImportError: import sysconfig paths = [ sysconfig.get_path('include'), sysconfig.get_path('platinclude'), ] NAME = 'asyncio' CFLAGS = ['-I' + path for path in paths] LDFLAGS = [] LIBS = [] GCC_LIST = ['asyncio'] uwsgi-2.0.29/plugins/cache/000077500000000000000000000000001477626554400155125ustar00rootroot00000000000000uwsgi-2.0.29/plugins/cache/cache.c000066400000000000000000000267321477626554400167330ustar00rootroot00000000000000#include /* Plugin for remote access to the uWSGI cache For request generating a response containing cache data, we need to make a copy to avoid holding the lock too much in case of blocking/slow writes we use 1.9 cache magic functions to be DRY the modifier2 is the command to run. Some command is extremely raw, and generally it is mean for internal uWSGI usage. commands: 0 -> simple cache get for values not bigger than 64k, the request is [111, keysize, 0] + key / response is [111, vallen, 0] + value 1 -> simple cache set for values not bigger than 64k, the request is [111, pktsize, 1] + (key, value) / response is connection closed 2 -> simple cache del, the request is [111, keysize, 2] + key / response is connection closed 3/4 -> simple dict based get command -> [111, pktsize ,3/4] + (key|get) / response is value for "key and get", but if "get" and no key is found an HTTP 404 is returned 5 -> get and stream -> [111, keysize, 5] + key response is a stream of the value til the whole object is transferred 6 -> dump the whole cache 17 -> magic interface for plugins remote access { "cmd": "get|set|update|del|exists", "key": "cache key", "expires": "seconds", "cache": "the cache name"} returns: {"status":"ok|notfound|error", "size": "size of the following body, if present"} + stream */ extern struct uwsgi_server uwsgi; static void cache_simple_command(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) { struct wsgi_request *wsgi_req = (struct wsgi_request *) data; if (vallen > 0) { if (!uwsgi_strncmp(key, keylen, "key", 3)) { uint64_t vallen = 0; char *value = uwsgi_cache_magic_get(val, vallen, &vallen, NULL, NULL); if (value) { uwsgi_response_write_body_do(wsgi_req, value, vallen); free(value); } } else if (!uwsgi_strncmp(key, keylen, "get", 3)) { uint64_t vallen = 0; char *value = uwsgi_cache_magic_get(val, vallen, &vallen, NULL, NULL); if (value) { uwsgi_response_write_body_do(wsgi_req, value, vallen); free(value); } else { uwsgi_404(wsgi_req); } } } } // this function does not use the magic api internally to avoid too much copy static void manage_magic_context(struct wsgi_request *wsgi_req, struct uwsgi_cache_magic_context *ucmc) { struct uwsgi_buffer *ub = NULL; struct uwsgi_cache *uc = uwsgi.caches; if (ucmc->cache_len > 0) { uc = uwsgi_cache_by_namelen(ucmc->cache, ucmc->cache_len); if (!uc) return; } if (!uc) return; // cache get if (!uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "get", 3)) { uint64_t vallen = 0; uint64_t expires = 0; uwsgi_rlock(uc->lock); char *value = uwsgi_cache_get3(uc, ucmc->key, ucmc->key_len, &vallen, &expires); if (!value) { uwsgi_rwunlock(uc->lock); return; } // we are still locked !!! ub = uwsgi_buffer_new(uwsgi.page_size); ub->pos = 4; if (uwsgi_buffer_append_keyval(ub, "status", 6, "ok", 2)) goto error; if (uwsgi_buffer_append_keynum(ub, "size", 4, vallen)) goto error; if (expires) { if (uwsgi_buffer_append_keynum(ub, "expires", 7, expires)) goto error; } if (uwsgi_buffer_set_uh(ub, 111, 17)) goto error; if (uwsgi_buffer_append(ub, value, vallen)) goto error; // unlock !!! uwsgi_rwunlock(uc->lock); uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return; } // cache exists if (!uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "exists", 6)) { uwsgi_rlock(uc->lock); if (!uwsgi_cache_exists2(uc, ucmc->key, ucmc->key_len)) { uwsgi_rwunlock(uc->lock); return; } // we are still locked !!! ub = uwsgi_buffer_new(uwsgi.page_size); ub->pos = 4; if (uwsgi_buffer_append_keyval(ub, "status", 6, "ok", 2)) goto error; if (uwsgi_buffer_set_uh(ub, 111, 17)) goto error; // unlock !!! uwsgi_rwunlock(uc->lock); uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return; } // cache del if (!uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "del", 3)) { uwsgi_wlock(uc->lock); if (uwsgi_cache_del2(uc, ucmc->key, ucmc->key_len, 0, 0)) { uwsgi_rwunlock(uc->lock); return; } // we are still locked !!! ub = uwsgi_buffer_new(uwsgi.page_size); ub->pos = 4; if (uwsgi_buffer_append_keyval(ub, "status", 6, "ok", 2)) goto error; if (uwsgi_buffer_set_uh(ub, 111, 17)) goto error; // unlock !!! uwsgi_rwunlock(uc->lock); uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return; } // cache clear if (!uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "clear", 5)) { uint64_t i; uwsgi_wlock(uc->lock); for (i = 1; i < uwsgi.caches->max_items; i++) { if (uwsgi_cache_del2(uc, NULL, 0, i, 0)) { uwsgi_rwunlock(uc->lock); return; } } // we are still locked !!! ub = uwsgi_buffer_new(uwsgi.page_size); ub->pos = 4; if (uwsgi_buffer_append_keyval(ub, "status", 6, "ok", 2)) goto error; if (uwsgi_buffer_set_uh(ub, 111, 17)) goto error; // unlock !!! uwsgi_rwunlock(uc->lock); uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return; } // cache set if (!uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "set", 3) || !uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "update", 6)) { if (ucmc->size == 0 || ucmc->size > uc->max_item_size) return; wsgi_req->post_cl = ucmc->size; // read the value ssize_t rlen = 0; char *value = uwsgi_request_body_read(wsgi_req, ucmc->size, &rlen); if (rlen != (ssize_t) ucmc->size) return; // ok let's lock uwsgi_wlock(uc->lock); if (uwsgi_cache_set2(uc, ucmc->key, ucmc->key_len, value, ucmc->size, ucmc->expires, ucmc->cmd_len > 3 ? UWSGI_CACHE_FLAG_UPDATE : 0)) { uwsgi_rwunlock(uc->lock); return; } // we are still locked !!! ub = uwsgi_buffer_new(uwsgi.page_size); ub->pos = 4; if (uwsgi_buffer_append_keyval(ub, "status", 6, "ok", 2)) goto error; if (uwsgi_buffer_set_uh(ub, 111, 17)) goto error; // unlock !!! uwsgi_rwunlock(uc->lock); uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return; } return; error: uwsgi_rwunlock(uc->lock); uwsgi_buffer_destroy(ub); } static int uwsgi_cache_request(struct wsgi_request *wsgi_req) { uint64_t vallen = 0; char *value; char *argv[3]; uint16_t argvs[3]; uint8_t argc = 0; // used for modifier2 17 struct uwsgi_cache_magic_context ucmc; struct uwsgi_cache *uc = NULL; switch(wsgi_req->uh->modifier2) { case 0: // get if (wsgi_req->uh->pktsize > 0) { value = uwsgi_cache_magic_get(wsgi_req->buffer, wsgi_req->uh->pktsize, &vallen, NULL, NULL); if (value) { wsgi_req->uh->pktsize = vallen; if (uwsgi_response_write_body_do(wsgi_req, (char *)&wsgi_req->uh, 4)) { free(value) ; return -1;} uwsgi_response_write_body_do(wsgi_req, value, vallen); free(value); } } break; case 1: // set if (wsgi_req->uh->pktsize > 0) { // max 3 items argc = 3; if (!uwsgi_parse_array(wsgi_req->buffer, wsgi_req->uh->pktsize, argv, argvs, &argc)) { if (argc > 1) { uwsgi_cache_magic_set(argv[0], argvs[0], argv[1], argvs[1], 0, 0, NULL); } } } break; case 2: // del if (wsgi_req->uh->pktsize > 0) { uwsgi_cache_magic_del(wsgi_req->buffer, wsgi_req->uh->pktsize, NULL); } break; case 3: case 4: // dict if (wsgi_req->uh->pktsize > 0) { uwsgi_hooked_parse(wsgi_req->buffer, wsgi_req->uh->pktsize, cache_simple_command, (void *) wsgi_req); } break; case 5: // get (uwsgi + stream) if (wsgi_req->uh->pktsize > 0) { value = uwsgi_cache_magic_get(wsgi_req->buffer, wsgi_req->uh->pktsize, &vallen, NULL, NULL); if (value) { wsgi_req->uh->pktsize = 0; wsgi_req->uh->modifier2 = 1; if (uwsgi_response_write_body_do(wsgi_req, (char *)&wsgi_req->uh, 4)) { free(value) ;return -1;} uwsgi_response_write_body_do(wsgi_req, value, vallen); free(value); } else { wsgi_req->uh->pktsize = 0; wsgi_req->uh->modifier2 = 0; uwsgi_response_write_body_do(wsgi_req, (char *)&wsgi_req->uh, 4); free(value); } } break; case 6: // dump uc = uwsgi.caches; if (wsgi_req->uh->pktsize > 0) { uc = uwsgi_cache_by_namelen(wsgi_req->buffer, wsgi_req->uh->pktsize); } if (!uc) break; uwsgi_wlock(uc->lock); struct uwsgi_buffer *cache_dump = uwsgi_buffer_new(uwsgi.page_size + uc->filesize); cache_dump->pos = 4; if (uwsgi_buffer_append_keynum(cache_dump, "items", 5, uc->max_items)) { uwsgi_buffer_destroy(cache_dump); break; } if (uwsgi_buffer_append_keynum(cache_dump, "blocksize", 9, uc->blocksize)) { uwsgi_buffer_destroy(cache_dump); break; } if (uwsgi_buffer_set_uh(cache_dump, 111, 7)) { uwsgi_buffer_destroy(cache_dump); break; } if (uwsgi_buffer_append(cache_dump, (char *)uc->items, uc->filesize)) { uwsgi_buffer_destroy(cache_dump); break; } uwsgi_rwunlock(uc->lock); uwsgi_response_write_body_do(wsgi_req, cache_dump->buf, cache_dump->pos); uwsgi_buffer_destroy(cache_dump); break; case 17: if (wsgi_req->uh->pktsize == 0) break; memset(&ucmc, 0, sizeof(struct uwsgi_cache_magic_context)); if (uwsgi_hooked_parse(wsgi_req->buffer, wsgi_req->uh->pktsize, uwsgi_cache_magic_context_hook, &ucmc)) { break; } manage_magic_context(wsgi_req, &ucmc); break; default: break; } return UWSGI_OK; } struct uwsgi_plugin cache_plugin = { .name = "cache", .modifier1 = 111, .request = uwsgi_cache_request, }; uwsgi-2.0.29/plugins/cache/uwsgiplugin.py000066400000000000000000000001071477626554400204370ustar00rootroot00000000000000 NAME='cache' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['cache'] uwsgi-2.0.29/plugins/carbon/000077500000000000000000000000001477626554400157135ustar00rootroot00000000000000uwsgi-2.0.29/plugins/carbon/carbon.c000066400000000000000000000357331477626554400173360ustar00rootroot00000000000000#include /* Author: Łukasz Mierzwa */ extern struct uwsgi_server uwsgi; struct carbon_server_list { int healthy; int errors; char *hostname; char *port; struct carbon_server_list *next; }; struct uwsgi_carbon { struct uwsgi_string_list *servers; struct carbon_server_list *servers_data; int freq; int timeout; char *id; int no_workers; unsigned long long *last_busyness_values; unsigned long long *current_busyness_values; int *was_busy; int max_retries; int retry_delay; char *root_node; char *hostname_dot_replacement; char *hostname; int resolve_hostname; char *idle_avg; int push_avg; int zero_avg; uint64_t last_requests; struct uwsgi_stats_pusher *pusher; int use_metrics; } u_carbon; static struct uwsgi_option carbon_options[] = { {"carbon", required_argument, 0, "push statistics to the specified carbon server", uwsgi_opt_add_string_list, &u_carbon.servers, UWSGI_OPT_MASTER}, {"carbon-timeout", required_argument, 0, "set carbon connection timeout in seconds (default 3)", uwsgi_opt_set_int, &u_carbon.timeout, 0}, {"carbon-freq", required_argument, 0, "set carbon push frequency in seconds (default 60)", uwsgi_opt_set_int, &u_carbon.freq, 0}, {"carbon-id", required_argument, 0, "set carbon id", uwsgi_opt_set_str, &u_carbon.id, 0}, {"carbon-no-workers", no_argument, 0, "disable generation of single worker metrics", uwsgi_opt_true, &u_carbon.no_workers, 0}, {"carbon-max-retry", required_argument, 0, "set maximum number of retries in case of connection errors (default 1)", uwsgi_opt_set_int, &u_carbon.max_retries, 0}, {"carbon-retry-delay", required_argument, 0, "set connection retry delay in seconds (default 7)", uwsgi_opt_set_int, &u_carbon.retry_delay, 0}, {"carbon-root", required_argument, 0, "set carbon metrics root node (default 'uwsgi')", uwsgi_opt_set_str, &u_carbon.root_node, 0}, {"carbon-hostname-dots", required_argument, 0, "set char to use as a replacement for dots in hostname (dots are not replaced by default)", uwsgi_opt_set_str, &u_carbon.hostname_dot_replacement, 0}, {"carbon-name-resolve", no_argument, 0, "allow using hostname as carbon server address (default disabled)", uwsgi_opt_true, &u_carbon.resolve_hostname, 0}, {"carbon-resolve-names", no_argument, 0, "allow using hostname as carbon server address (default disabled)", uwsgi_opt_true, &u_carbon.resolve_hostname, 0}, {"carbon-idle-avg", required_argument, 0, "average values source during idle period (no requests), can be \"last\", \"zero\", \"none\" (default is last)", uwsgi_opt_set_str, &u_carbon.idle_avg, 0}, {"carbon-use-metrics", no_argument, 0, "don't compute all statistics, use metrics subsystem data instead (warning! key names will be different)", uwsgi_opt_true, &u_carbon.use_metrics, 0}, {0, 0, 0, 0, 0, 0, 0}, }; static void carbon_post_init() { int i; struct uwsgi_string_list *usl = u_carbon.servers; if (!uwsgi.sockets) return; if (!u_carbon.servers) return; while(usl) { struct carbon_server_list *u_server = uwsgi_calloc(sizeof(struct carbon_server_list)); u_server->healthy = 1; u_server->errors = 0; char *p, *ctx = NULL; // make a copy to not clobber argv char *tmp = uwsgi_str(usl->value); uwsgi_foreach_token(tmp, ":", p, ctx) { if (!u_server->hostname) { u_server->hostname = uwsgi_str(p); } else if (!u_server->port) { u_server->port = uwsgi_str(p); } else break; } free(tmp); if (!u_server->hostname || !u_server->port) { uwsgi_log("[carbon] invalid carbon server address (%s)\n", usl->value); usl = usl->next; if (u_server->hostname) free(u_server->hostname); if (u_server->port) free(u_server->port); free(u_server); continue; } if (u_carbon.servers_data) { u_server->next = u_carbon.servers_data; } u_carbon.servers_data = u_server; uwsgi_log("[carbon] added server %s:%s\n", u_server->hostname, u_server->port); usl = usl->next; } if (!u_carbon.root_node) u_carbon.root_node = "uwsgi."; if (strlen(u_carbon.root_node) && !uwsgi_endswith(u_carbon.root_node, ".")) { u_carbon.root_node = uwsgi_concat2(u_carbon.root_node, "."); } if (u_carbon.freq < 1) u_carbon.freq = 60; if (u_carbon.timeout < 1) u_carbon.timeout = 3; if (u_carbon.max_retries < 0) u_carbon.max_retries = 0; if (u_carbon.retry_delay <= 0) u_carbon.retry_delay = 7; if (!u_carbon.id) { u_carbon.id = uwsgi_str(uwsgi.sockets->name); for(i=0;i<(int)strlen(u_carbon.id);i++) { if (u_carbon.id[i] == '.') u_carbon.id[i] = '_'; } } u_carbon.hostname = uwsgi_str(uwsgi.hostname); if (u_carbon.hostname_dot_replacement) { for(i=0;i<(int)strlen(u_carbon.hostname);i++) { if (u_carbon.hostname[i] == '.') u_carbon.hostname[i] = u_carbon.hostname_dot_replacement[0]; } } u_carbon.push_avg = 1; u_carbon.zero_avg = 0; if (!u_carbon.idle_avg) { u_carbon.idle_avg = "last"; } else if (!strcmp(u_carbon.idle_avg, "zero")) { u_carbon.zero_avg = 1; } else if (!strcmp(u_carbon.idle_avg, "none")) { u_carbon.push_avg = 0; } else if (strcmp(u_carbon.idle_avg, "last")) { uwsgi_log("[carbon] invalid value for carbon-idle-avg: \"%s\"\n", u_carbon.idle_avg); exit(1); } if (!u_carbon.last_busyness_values) { u_carbon.last_busyness_values = uwsgi_calloc(sizeof(unsigned long long) * uwsgi.numproc); } if (!u_carbon.current_busyness_values) { u_carbon.current_busyness_values = uwsgi_calloc(sizeof(unsigned long long) * uwsgi.numproc); } if (!u_carbon.was_busy) { u_carbon.was_busy = uwsgi_calloc(sizeof(int) * uwsgi.numproc); } uwsgi_log("[carbon] carbon plugin started, %is frequency, %is timeout, max retries %i, retry delay %is\n", u_carbon.freq, u_carbon.timeout, u_carbon.max_retries, u_carbon.retry_delay); struct uwsgi_stats_pusher_instance *uspi = uwsgi_stats_pusher_add(u_carbon.pusher, NULL); uspi->freq = u_carbon.freq; uspi->retry_delay = u_carbon.retry_delay; uspi->max_retries = u_carbon.max_retries; // no need to generate the json uspi->raw=1; } static int carbon_write(int fd, char *fmt,...) { va_list ap; va_start(ap, fmt); char ptr[4096]; int rlen; rlen = vsnprintf(ptr, 4096, fmt, ap); va_end(ap); if (rlen < 1) return 0; if (uwsgi_write_nb(fd, ptr, rlen, u_carbon.timeout)) { uwsgi_error("carbon_write()"); return 0; } return 1; } static int carbon_push_stats(int retry_cycle, time_t now) { struct carbon_server_list *usl = u_carbon.servers_data; if (!u_carbon.servers_data) return 0; int i; int fd; int wok; char *ip; char *carbon_address = NULL; int needs_retry; for (i = 0; i < uwsgi.numproc; i++) { u_carbon.current_busyness_values[i] = uwsgi.workers[i+1].running_time - u_carbon.last_busyness_values[i]; u_carbon.last_busyness_values[i] = uwsgi.workers[i+1].running_time; u_carbon.was_busy[i] += uwsgi_worker_is_busy(i+1); } needs_retry = 0; while(usl) { if (retry_cycle && usl->healthy) // skip healthy servers during retry cycle goto nxt; if (retry_cycle && usl->healthy == 0) uwsgi_log("[carbon] Retrying failed server at %s (%d)\n", usl->hostname, usl->errors); if (!retry_cycle) { usl->healthy = 1; usl->errors = 0; } if (u_carbon.resolve_hostname) { ip = uwsgi_resolve_ip(usl->hostname); if (!ip) { uwsgi_log("[carbon] Could not resolve hostname %s\n", usl->hostname); goto nxt; } carbon_address = uwsgi_concat3(ip, ":", usl->port); } else { carbon_address = uwsgi_concat3(usl->hostname, ":", usl->port); } fd = uwsgi_connect(carbon_address, u_carbon.timeout, 0); if (fd < 0) { uwsgi_log("[carbon] Could not connect to carbon server at %s\n", carbon_address); needs_retry = 1; usl->healthy = 0; usl->errors++; free(carbon_address); goto nxt; } free(carbon_address); // put the socket in non-blocking mode uwsgi_socket_nb(fd); if (u_carbon.use_metrics) goto metrics_loop; unsigned long long total_rss = 0; unsigned long long total_vsz = 0; unsigned long long total_tx = 0; unsigned long long total_avg_rt = 0; // total avg_rt unsigned long long avg_rt = 0; // per worker avg_rt reported to carbon unsigned long long active_workers = 0; // number of workers used to calculate total avg_rt unsigned long long total_busyness = 0; unsigned long long total_avg_busyness = 0; unsigned long long worker_busyness = 0; unsigned long long total_harakiri = 0; int do_avg_push; wok = carbon_write(fd, "%s%s.%s.requests %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) uwsgi.workers[0].requests, (unsigned long long) now); if (!wok) goto clear; for(i=1;i<=uwsgi.numproc;i++) { total_tx += uwsgi.workers[i].tx; total_harakiri += uwsgi.workers[i].harakiri_count; if (uwsgi.workers[i].cheaped) { // also if worker is cheaped than we report its average response time as zero, sending last value might be confusing avg_rt = 0; worker_busyness = 0; } else { // global average response time is calculated from active/idle workers, cheaped workers are excluded, otherwise it is not accurate avg_rt = uwsgi.workers[i].avg_response_time; active_workers++; total_avg_rt += uwsgi.workers[i].avg_response_time; // calculate worker busyness if (u_carbon.current_busyness_values[i-1] == 0 && u_carbon.was_busy[i-1]) { worker_busyness = 100; } else { worker_busyness = ((u_carbon.current_busyness_values[i-1]*100) / (u_carbon.freq*1000000)); if (worker_busyness > 100) worker_busyness = 100; } total_busyness += worker_busyness; u_carbon.was_busy[i-1] = 0; if (uwsgi.logging_options.memory_report == 1 || uwsgi.force_get_memusage) { // only running workers are counted in total memory stats and if memory-report option is enabled total_rss += uwsgi.workers[i].rss_size; total_vsz += uwsgi.workers[i].vsz_size; } } //skip per worker metrics when disabled if (u_carbon.no_workers) continue; wok = carbon_write(fd, "%s%s.%s.worker%d.requests %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].requests, (unsigned long long) now); if (!wok) goto clear; if (uwsgi.logging_options.memory_report == 1 || uwsgi.force_get_memusage) { wok = carbon_write(fd, "%s%s.%s.worker%d.rss_size %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].rss_size, (unsigned long long) now); if (!wok) goto clear; wok = carbon_write(fd, "%s%s.%s.worker%d.vsz_size %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].vsz_size, (unsigned long long) now); if (!wok) goto clear; } do_avg_push = 1; if (!u_carbon.last_requests || u_carbon.last_requests == uwsgi.workers[0].requests) { if (!u_carbon.push_avg) { do_avg_push = 0; } else if (u_carbon.zero_avg) { avg_rt = 0; } } if (do_avg_push) { wok = carbon_write(fd, "%s%s.%s.worker%d.avg_rt %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, i, (unsigned long long) avg_rt, (unsigned long long) now); if (!wok) goto clear; } wok = carbon_write(fd, "%s%s.%s.worker%d.tx %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].tx, (unsigned long long) now); if (!wok) goto clear; wok = carbon_write(fd, "%s%s.%s.worker%d.busyness %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, i, (unsigned long long) worker_busyness, (unsigned long long) now); if (!wok) goto clear; wok = carbon_write(fd, "%s%s.%s.worker%d.harakiri %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, i, (unsigned long long) uwsgi.workers[i].harakiri_count, (unsigned long long) now); if (!wok) goto clear; } if (uwsgi.logging_options.memory_report == 1 || uwsgi.force_get_memusage) { wok = carbon_write(fd, "%s%s.%s.rss_size %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) total_rss, (unsigned long long) now); if (!wok) goto clear; wok = carbon_write(fd, "%s%s.%s.vsz_size %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) total_vsz, (unsigned long long) now); if (!wok) goto clear; } do_avg_push = 1; uint64_t c_total_avg_rt = (active_workers ? total_avg_rt / active_workers : 0); if (!u_carbon.last_requests || u_carbon.last_requests == uwsgi.workers[0].requests) { if (!u_carbon.push_avg) { do_avg_push = 0; } else if (u_carbon.zero_avg) { c_total_avg_rt = 0; } } if (do_avg_push) { wok = carbon_write(fd, "%s%s.%s.avg_rt %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) c_total_avg_rt, (unsigned long long) now); if (!wok) goto clear; } wok = carbon_write(fd, "%s%s.%s.tx %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) total_tx, (unsigned long long) now); if (!wok) goto clear; if (active_workers > 0) { total_avg_busyness = total_busyness / active_workers; if (total_avg_busyness > 100) total_avg_busyness = 100; } else { total_avg_busyness = 0; } wok = carbon_write(fd, "%s%s.%s.busyness %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) total_avg_busyness, (unsigned long long) now); if (!wok) goto clear; wok = carbon_write(fd, "%s%s.%s.active_workers %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) active_workers, (unsigned long long) now); if (!wok) goto clear; if (uwsgi.cheaper) { wok = carbon_write(fd, "%s%s.%s.cheaped_workers %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) uwsgi.numproc - active_workers, (unsigned long long) now); if (!wok) goto clear; } wok = carbon_write(fd, "%s%s.%s.harakiri %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, (unsigned long long) total_harakiri, (unsigned long long) now); if (!wok) goto clear; metrics_loop: if (u_carbon.use_metrics) { struct uwsgi_metric *um = uwsgi.metrics; while(um) { uwsgi_rlock(uwsgi.metrics_lock); wok = carbon_write(fd, "%s%s.%s.%.*s %llu %llu\n", u_carbon.root_node, u_carbon.hostname, u_carbon.id, um->name_len, um->name, (unsigned long long) *um->value, (unsigned long long) now); uwsgi_rwunlock(uwsgi.metrics_lock); if (um->reset_after_push){ uwsgi_wlock(uwsgi.metrics_lock); *um->value = um->initial_value; uwsgi_rwunlock(uwsgi.metrics_lock); } if (!wok) goto clear; um = um->next; } } usl->healthy = 1; usl->errors = 0; u_carbon.last_requests = uwsgi.workers[0].requests; clear: close(fd); nxt: usl = usl->next; } return needs_retry; } static void carbon_push(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) { uspi->needs_retry = carbon_push_stats(uspi->retries, now); } static void carbon_cleanup() { carbon_push_stats(0, uwsgi_now()); } static void carbon_register() { u_carbon.pusher = uwsgi_register_stats_pusher("carbon", carbon_push); } struct uwsgi_plugin carbon_plugin = { .name = "carbon", .master_cleanup = carbon_cleanup, .options = carbon_options, .on_load = carbon_register, .post_init = carbon_post_init, }; uwsgi-2.0.29/plugins/carbon/uwsgiplugin.py000066400000000000000000000001111477626554400206330ustar00rootroot00000000000000 NAME='carbon' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['carbon'] uwsgi-2.0.29/plugins/cgi/000077500000000000000000000000001477626554400152115ustar00rootroot00000000000000uwsgi-2.0.29/plugins/cgi/cgi_plugin.c000066400000000000000000000675341477626554400175140ustar00rootroot00000000000000#include extern struct uwsgi_server uwsgi; #define kill_on_error if (!uc.do_not_kill_on_error) { if (kill(cgi_pid, SIGKILL)) uwsgi_error("kill()");} struct uwsgi_cgi { struct uwsgi_dyn_dict *mountpoint; struct uwsgi_dyn_dict *helpers; size_t buffer_size; int timeout; struct uwsgi_string_list *index; struct uwsgi_string_list *allowed_ext; struct uwsgi_string_list *unset; struct uwsgi_string_list *loadlib; struct uwsgi_string_list *cgi_safe; int optimize; int from_docroot; int has_mountpoints; struct uwsgi_dyn_dict *default_cgi; int path_info; int do_not_kill_on_error; int async_max_attempts; int close_stdin_on_eof; } uc ; static void uwsgi_opt_add_cgi(char *opt, char *value, void *foobar) { char *val = strchr(value, '='); if (!val) { uwsgi_dyn_dict_new(&uc.mountpoint, value, strlen(value), NULL, 0); } else { uwsgi_dyn_dict_new(&uc.mountpoint, value, val-value, val+1, strlen(val+1)); } } static void uwsgi_opt_add_cgi_maphelper(char *opt, char *value, void *foobar) { char *val = strchr(value, '='); if (!val) { uwsgi_log("invalid CGI helper syntax, must be ext=command\n"); exit(1); } uwsgi_dyn_dict_new(&uc.helpers, value, val-value, val+1, strlen(val+1)); } struct uwsgi_option uwsgi_cgi_options[] = { {"cgi", required_argument, 0, "add a cgi mountpoint/directory/script", uwsgi_opt_add_cgi, NULL, 0}, {"cgi-map-helper", required_argument, 0, "add a cgi map-helper", uwsgi_opt_add_cgi_maphelper, NULL, 0}, {"cgi-helper", required_argument, 0, "add a cgi map-helper", uwsgi_opt_add_cgi_maphelper, NULL, 0}, {"cgi-from-docroot", no_argument, 0, "blindly enable cgi in DOCUMENT_ROOT", uwsgi_opt_true, &uc.from_docroot, 0}, {"cgi-buffer-size", required_argument, 0, "set cgi buffer size", uwsgi_opt_set_64bit, &uc.buffer_size, 0}, {"cgi-timeout", required_argument, 0, "set cgi script timeout", uwsgi_opt_set_int, &uc.timeout, 0}, {"cgi-index", required_argument, 0, "add a cgi index file", uwsgi_opt_add_string_list, &uc.index, 0}, {"cgi-allowed-ext", required_argument, 0, "cgi allowed extension", uwsgi_opt_add_string_list, &uc.allowed_ext, 0}, {"cgi-unset", required_argument, 0, "unset specified environment variables", uwsgi_opt_add_string_list, &uc.unset, 0}, {"cgi-loadlib", required_argument, 0, "load a cgi shared library/optimizer", uwsgi_opt_add_string_list, &uc.loadlib, 0}, {"cgi-optimize", no_argument, 0, "enable cgi realpath() optimizer", uwsgi_opt_true, &uc.optimize, 0}, {"cgi-optimized", no_argument, 0, "enable cgi realpath() optimizer", uwsgi_opt_true, &uc.optimize, 0}, {"cgi-path-info", no_argument, 0, "disable PATH_INFO management in cgi scripts", uwsgi_opt_true, &uc.path_info, 0}, {"cgi-do-not-kill-on-error", no_argument, 0, "do not send SIGKILL to cgi script on errors", uwsgi_opt_true, &uc.do_not_kill_on_error, 0}, {"cgi-async-max-attempts", no_argument, 0, "max waitpid() attempts in cgi async mode (default 10)", uwsgi_opt_set_int, &uc.async_max_attempts, 0}, {"cgi-close-stdin-on-eof", no_argument, 0, "close STDIN on input EOF", uwsgi_opt_true, &uc.close_stdin_on_eof, 0}, {"cgi-safe", required_argument, 0, "skip security checks if the cgi file is under the specified path", uwsgi_opt_add_string_list, &uc.cgi_safe, 0}, {0, 0, 0, 0, 0, 0, 0}, }; static void uwsgi_cgi_apps() { struct uwsgi_dyn_dict *udd = uc.mountpoint; struct stat st; while(udd) { if (udd->vallen) { if (uc.optimize) { udd->value = realpath(udd->value, NULL); if (!udd->value) { uwsgi_log("unable to find CGI path %.*s\n", udd->vallen, udd->value); exit(1); } udd->vallen = strlen(udd->value); udd->status = 1; if (stat(udd->value, &st)) { uwsgi_error("stat()"); uwsgi_log("something horrible happened during CGI initialization\n"); exit(1); } if (!S_ISDIR(st.st_mode)) { udd->status = 2; } } uc.has_mountpoints = 1; uwsgi_log("initialized CGI mountpoint: %.*s = %.*s\n", udd->keylen, udd->key, udd->vallen, udd->value); } else { if (uc.optimize) { udd->key = realpath(udd->key, NULL); if (!udd->key) { uwsgi_log("unable to find CGI path %.*s\n", udd->keylen, udd->key); exit(1); } udd->keylen = strlen(udd->key); udd->status = 1; if (stat(udd->key, &st)) { uwsgi_error("stat()"); uwsgi_log("something horrible happened during CGI initialization\n"); exit(1); } if (!S_ISDIR(st.st_mode)) { udd->status = 2; } } uwsgi_log("initialized CGI path: %.*s\n", udd->keylen, udd->key); uc.default_cgi = udd; } udd = udd->next; } } static int uwsgi_cgi_init(){ void (*cgi_sym)(void); if (!uc.buffer_size) uc.buffer_size = 65536; if (!uc.timeout) uc.timeout = 60; struct uwsgi_string_list *ll = uc.loadlib; while(ll) { char *colon = strchr(ll->value, ':'); if (!colon) { uwsgi_log("invalid cgi-loadlib syntax, must be in the form lib:func\n"); exit(1); } *colon = 0; void *cgi_lib = dlopen(ll->value, RTLD_NOW | RTLD_GLOBAL); if (!cgi_lib) { uwsgi_log( "cgi-loadlib: %s\n", dlerror()); exit(1); } cgi_sym = dlsym(cgi_lib, colon+1); if (!cgi_sym) { uwsgi_log("unknown symbol %s in lib %s\n", colon+1, ll->value); exit(1); } cgi_sym(); uwsgi_log("[cgi-loadlib] loaded symbol %s from %s\n", colon+1, ll->value); *colon = ':'; ll = ll->next; } return 0; } static char *uwsgi_cgi_get_helper(char *filename) { struct uwsgi_dyn_dict *helpers = uc.helpers; size_t len = strlen(filename); while(helpers) { if (len >= (size_t) helpers->keylen) { if (!uwsgi_strncmp((filename+len)-helpers->keylen, helpers->keylen, helpers->key, helpers->keylen)) { return helpers->value; } } helpers = helpers->next; } return NULL; } /* start reading each line until Status or Location are found -1 error 0 not found 1 found */ static int uwsgi_cgi_check_status(struct wsgi_request *wsgi_req, char *buf, size_t len) { char *key = buf, *value = NULL; size_t header_size = 0; size_t i; for(i=0;i buf) { // remove \r if ((buf[i-1]) == '\r') { header_size--; } } // enough space for Status ? if (header_size >= 11) { // "Status: NNN" if (!strncasecmp("Status: ", key, 8)) { #ifdef UWSGI_DEBUG uwsgi_log("found Status header: %.*s\n", header_size, key); #endif if (uwsgi_response_prepare_headers(wsgi_req, key+8, header_size - 8)) return -1; return 1; } // Location: X if (!strncasecmp("Location: ", key, 10)) { #ifdef UWSGI_DEBUG uwsgi_log("found Location header: %.*s\n", header_size, key); #endif if (uwsgi_response_prepare_headers(wsgi_req, "302 Found", 9)) return -1; return 1; } } key = NULL; value = NULL; } else if (buf[i] == ':') { value = buf+i; } else if (buf[i] != '\r') { if (key == NULL) key = buf + i; } } // no Status/Location found return 0; } static int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, int fd, char *buf, size_t blen) { size_t i; size_t header_size = 0; int status_sent = 0; size_t remains = blen; char *ptr = buf; size_t len = 0; while(remains > 0) { ssize_t rlen = uwsgi_read_true_nb(fd, ptr, remains, uc.timeout); if (rlen < 0) { if (!errno) return 1; return -1; } // timed out if (rlen == 0) return -1; remains -= rlen; len += rlen; ptr += rlen; // Search for Status/Location headers if (!status_sent) { status_sent = uwsgi_cgi_check_status(wsgi_req, buf, len); if (status_sent < 0) return -1; // need more data ? if (status_sent == 0) continue; } // send headers char *key = buf; char *value = NULL; for(i=0;i buf) { if ((buf[i-1]) == '\r') { header_size--; } } #ifdef UWSGI_DEBUG uwsgi_log("found CGI header: %.*s\n", header_size, key); #endif // Ignore "Status: NNN" header if (header_size >= 11) { if (!strncasecmp("Status: ", key, 8)) { key = NULL; value = NULL; continue; } } uwsgi_response_add_header(wsgi_req, NULL, 0, key, header_size); key = NULL; value = NULL; } else if (buf[i] == ':') { value = buf+i; } else if (buf[i] != '\r') { if (key == NULL) { key = buf + i; } } } } return -1; send_body: if (len-i > 0) { uwsgi_response_write_body_do(wsgi_req, buf+i, len-i); } return 0; } static char *uwsgi_cgi_get_docroot(char *path_info, uint16_t path_info_len, int *need_free, int *is_a_file, int *discard_base, char **script_name) { struct uwsgi_dyn_dict *udd = uc.mountpoint, *choosen_udd = NULL; int best_found = 0; struct stat st; char *path = NULL; if (uc.has_mountpoints) { while(udd) { if (udd->vallen) { if (!uwsgi_starts_with(path_info, path_info_len, udd->key, udd->keylen) && udd->keylen > best_found) { best_found = udd->keylen ; choosen_udd = udd; path = udd->value; *script_name = udd->key; *discard_base = udd->keylen; if (udd->key[udd->keylen-1] == '/') { *discard_base = *discard_base-1; } } } udd = udd->next; } } if (choosen_udd == NULL) { choosen_udd = uc.default_cgi; if (!choosen_udd) return NULL; path = choosen_udd->key; } if (choosen_udd->status == 0) { char *tmp_udd = uwsgi_malloc(PATH_MAX+1); if (!realpath(path, tmp_udd)) { free(tmp_udd); return NULL; } if (stat(tmp_udd, &st)) { uwsgi_error("stat()"); free(tmp_udd); return NULL; } if (!S_ISDIR(st.st_mode)) { *is_a_file = 1; } *need_free = 1; return tmp_udd; } if (choosen_udd->status == 2) *is_a_file = 1; return path; } static int uwsgi_cgi_walk(struct wsgi_request *wsgi_req, char *full_path, char *docroot, size_t docroot_len, int discard_base, char **path_info) { // and now start walking... uint16_t i; char *ptr = wsgi_req->path_info+discard_base; char *dst = full_path+docroot_len; char *part = ptr; int part_size = 0; struct stat st; if (wsgi_req->path_info_len == 0) return 0; if (ptr[0] == '/') part_size++; for(i=0;ipath_info_len-discard_base;i++) { if (ptr[i] == '/') { memcpy(dst, part, part_size-1); *(dst+part_size-1) = 0; if (stat(full_path, &st)) { uwsgi_404(wsgi_req); return -1; } // not a directory, stop walking if (!S_ISDIR(st.st_mode)) { if (i < (wsgi_req->path_info_len-discard_base)-1) { *path_info = ptr + i; } return 0; } // check for buffer overflow !!! *(dst+part_size-1) = '/'; *(dst+part_size) = 0; dst += part_size ; part_size = 0; part = ptr + i + 1; } part_size++; } if (part < wsgi_req->path_info+wsgi_req->path_info_len) { memcpy(dst, part, part_size-1); *(dst+part_size-1) = 0; } return 0; } static int uwsgi_cgi_run(struct wsgi_request *, char *, size_t, char *, char *, char *, char *, int, int); static int uwsgi_cgi_request(struct wsgi_request *wsgi_req) { char full_path[PATH_MAX]; char tmp_path[PATH_MAX]; struct stat cgi_stat; int need_free = 0; int is_a_file = 0; int discard_base = 0; size_t docroot_len = 0; size_t full_path_len = 0; char *helper = NULL; char *path_info = NULL; char *script_name = NULL; /* Standard CGI request */ if (!wsgi_req->uh->pktsize) { uwsgi_log("Empty CGI request. skip.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } char *docroot = NULL; // check for file availability (and 'runnability') if (uc.from_docroot) { docroot = wsgi_req->document_root; docroot_len = wsgi_req->document_root_len; } else { docroot = uwsgi_cgi_get_docroot(wsgi_req->path_info, wsgi_req->path_info_len, &need_free, &is_a_file, &discard_base, &script_name); if (docroot) docroot_len = strlen(docroot); } if (docroot == NULL || docroot_len == 0) { uwsgi_404(wsgi_req); return UWSGI_OK; } memcpy(full_path, docroot, docroot_len); if (!is_a_file) { *(full_path+docroot_len) = '/'; *(full_path+docroot_len+1) = 0; if (uwsgi_cgi_walk(wsgi_req, full_path, docroot, docroot_len, discard_base, &path_info)) { if (need_free) free(docroot); return UWSGI_OK; } if (realpath(full_path, tmp_path) == NULL) { if (need_free) free(docroot); uwsgi_404(wsgi_req); return UWSGI_OK; } full_path_len = strlen(tmp_path); // add +1 to copy the null byte memcpy(full_path, tmp_path, full_path_len+1); struct uwsgi_string_list *safe = uc.cgi_safe; while(safe) { if (!uwsgi_starts_with(full_path, full_path_len, safe->value, safe->len)) break; safe = safe->next; } if (!safe) { if (uwsgi_starts_with(full_path, full_path_len, docroot, docroot_len)) { uwsgi_log("CGI security error: %s is not under %s\n", full_path, docroot); if (need_free) free(docroot); return -1; } } } else { *(full_path+docroot_len) = 0; path_info = wsgi_req->path_info+discard_base; } if (stat(full_path, &cgi_stat)) { uwsgi_404(wsgi_req); if (need_free) free(docroot); return UWSGI_OK; } if (S_ISDIR(cgi_stat.st_mode)) { // add / to directories if (wsgi_req->path_info_len == 0 || (wsgi_req->path_info_len > 0 && wsgi_req->path_info[wsgi_req->path_info_len-1] != '/')) { uwsgi_redirect_to_slash(wsgi_req); if (need_free) free(docroot); return UWSGI_OK; } struct uwsgi_string_list *ci = uc.index; full_path[full_path_len] = '/'; full_path_len++; int found = 0; while(ci) { if (full_path_len + ci->len + 1 < PATH_MAX) { // add + 1 to ensure null byte memcpy(full_path+full_path_len, ci->value, ci->len + 1); if (!access(full_path, R_OK)) { found = 1; break; } } ci = ci->next; } if (!found) { uwsgi_404(wsgi_req); if (need_free) free(docroot); return UWSGI_OK; } } full_path_len = strlen(full_path); int cgi_allowed = 1; struct uwsgi_string_list *allowed = uc.allowed_ext; while(allowed) { cgi_allowed = 0; if (full_path_len >= allowed->len) { if (!uwsgi_strncmp(full_path+(full_path_len-allowed->len), allowed->len, allowed->value, allowed->len)) { cgi_allowed = 1; break; } } allowed = allowed->next; } if (!cgi_allowed) { uwsgi_403(wsgi_req); if (need_free) free(docroot); return UWSGI_OK; } // get the helper if (!is_a_file) { helper = uwsgi_cgi_get_helper(full_path); if (helper == NULL) { if (access(full_path, X_OK)) { uwsgi_error("access()"); uwsgi_403(wsgi_req); if (need_free) free(docroot); return UWSGI_OK; } } } int ret = uwsgi_cgi_run(wsgi_req, docroot, docroot_len, full_path, helper, path_info, script_name, is_a_file, discard_base); if (need_free) free(docroot); return ret; } static int uwsgi_cgi_run(struct wsgi_request *wsgi_req, char *docroot, size_t docroot_len, char *full_path, char *helper, char *path_info, char *script_name, int is_a_file, int discard_base) { int cgi_pipe[2]; int post_pipe[2]; int nargs = 0; int waitpid_status; int i; char **argv; char *command = full_path; int stdin_closed = 0; if (is_a_file) { command = docroot; } if (pipe(cgi_pipe)) { uwsgi_error("uwsgi_cgi_run()/pipe()"); return UWSGI_OK; } if (pipe(post_pipe)) { close(cgi_pipe[0]); close(cgi_pipe[1]); uwsgi_error("uwsgi_cgi_run()/pipe()"); return UWSGI_OK; } pid_t cgi_pid = fork(); if (cgi_pid < 0) { uwsgi_error("uwsgi_cgi_run()/fork()"); close(cgi_pipe[0]); close(cgi_pipe[1]); close(post_pipe[0]); close(post_pipe[1]); return UWSGI_OK; } if (cgi_pid > 0) { close(cgi_pipe[1]); close(post_pipe[0]); uwsgi_socket_nb(cgi_pipe[0]); uwsgi_socket_nb(post_pipe[1]); // ok start sending post data... size_t remains = wsgi_req->post_cl; while(remains > 0) { ssize_t rlen = 0; char *buf = uwsgi_request_body_read(wsgi_req, 8192, &rlen); if (!buf) { goto clear2; } if (buf == uwsgi.empty) break; // write data to the node if (uwsgi_write_true_nb(post_pipe[1], buf, rlen, uc.timeout)) { goto clear2; } remains -= rlen; } if (uc.close_stdin_on_eof) { close(post_pipe[1]); stdin_closed = 1; } // wait for data char *buf = uwsgi_malloc(uc.buffer_size); int completed = uwsgi_cgi_parse(wsgi_req, cgi_pipe[0], buf, uc.buffer_size); if (completed < 0) { uwsgi_log("invalid CGI response !!!\n"); kill_on_error goto clear; } while (!completed) { ssize_t rlen = uwsgi_read_true_nb(cgi_pipe[0], buf, uc.buffer_size, uc.timeout); if (rlen > 0) { if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) { kill_on_error goto clear; } } else if (rlen == 0) { uwsgi_log("CGI timeout !!!\n"); kill_on_error goto clear; } else { if (errno) { uwsgi_req_error("error reading CGI response\n"); kill_on_error } goto clear; } } clear: free(buf); clear2: close(cgi_pipe[0]); if (!stdin_closed) close(post_pipe[1]); // now wait for process exit/death // in async mode we need a trick... if (uwsgi.async > 1) { pid_t diedpid = waitpid(cgi_pid, &waitpid_status, WNOHANG); if (diedpid < 0) { uwsgi_error("waitpid()"); } else if (diedpid == 0) { // pass the pid of the cgi to async_plagued (the after request hook will clear the process) wsgi_req->async_plagued = (int) cgi_pid; } } else { if (waitpid(cgi_pid, &waitpid_status, 0) < 0) { uwsgi_error("waitpid()"); } } return UWSGI_OK; } // now map wsgi_req->poll.fd (or async_post) to 0 & cgi_pipe[1] to 1 dup2(post_pipe[0], 0); close(post_pipe[0]); dup2(cgi_pipe[1],1); close(cgi_pipe[1]); // close all the fd > 2 DIR *dirp = opendir("/proc/self/fd"); if (dirp == NULL) dirp = opendir("/dev/fd"); if (dirp != NULL) { struct dirent *dent; while ((dent = readdir(dirp)) != NULL) { int fd = atoi(dent->d_name); if ((fd > 2) && fd != dirfd(dirp)) close(fd); } closedir(dirp); } else { for(i=3;i<(int)uwsgi.max_fd;i++) { close(i); } } // fill cgi env for(i=0;ivar_cnt;i+=2) { // no need to free the putenv() memory if (putenv(uwsgi_concat3n(wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, "=", 1, wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len))) { uwsgi_error("putenv()"); } } if (setenv("GATEWAY_INTERFACE", "CGI/1.1", 0)) { uwsgi_error("setenv()"); } if (setenv("SERVER_SOFTWARE", uwsgi_concat2("uWSGI/", UWSGI_VERSION), 0)) { uwsgi_error("setenv()"); } // for newer php if (setenv("REDIRECT_STATUS", "200", 0)) { uwsgi_error("setenv()"); } if (path_info) { size_t pi_len = wsgi_req->path_info_len - (path_info - wsgi_req->path_info); if (setenv("PATH_INFO", uwsgi_concat2n(path_info, pi_len, "", 0), 1)) { uwsgi_error("setenv()"); } if (wsgi_req->document_root_len > 0) { if (setenv("PATH_TRANSLATED", uwsgi_concat3n(wsgi_req->document_root, wsgi_req->document_root_len, path_info, pi_len, "", 0) , 1)) { uwsgi_error("setenv()"); } } else { if (setenv("PATH_TRANSLATED", uwsgi_concat3n(docroot, docroot_len, path_info, pi_len, "", 0) , 1)) { uwsgi_error("setenv()"); } } } else { unsetenv("PATH_INFO"); unsetenv("PATH_TRANSLATED"); } if (is_a_file) { if (setenv("DOCUMENT_ROOT", uwsgi.cwd, 0)) { uwsgi_error("setenv()"); } if (setenv("SCRIPT_FILENAME", docroot, 0)) { uwsgi_error("setenv()"); } if (script_name && discard_base > 1) { if (setenv("SCRIPT_NAME", uwsgi_concat2n(script_name, discard_base, "", 0), 1)) { uwsgi_error("setenv()"); } } } else { if (setenv("DOCUMENT_ROOT", docroot, 0)) { uwsgi_error("setenv()"); } if (setenv("SCRIPT_FILENAME", full_path, 0)) { uwsgi_error("setenv()"); } if (setenv("SCRIPT_NAME", uwsgi_concat2n(wsgi_req->path_info, discard_base, full_path+docroot_len, strlen(full_path+docroot_len)), 1)) { uwsgi_error("setenv()"); } char *base = uwsgi_get_last_char(full_path, '/'); if (base) { // a little trick :P *base = 0; if (chdir(full_path)) { uwsgi_error("chdir()"); } *base = '/'; } else if (docroot_len > 0) { if (chdir(docroot)) { uwsgi_error("chdir()"); } } } struct uwsgi_string_list *drop_env = uc.unset; while(drop_env) { unsetenv(drop_env->value); drop_env = drop_env->next; } argv = uwsgi_malloc(sizeof(char *) * 3); // check if we need to parse indexed QUERY_STRING if (wsgi_req->query_string_len > 0) { if (!memchr(wsgi_req->query_string, '=', wsgi_req->query_string_len)) { nargs = 1; for(i=0;iquery_string_len;i++) { if (wsgi_req->query_string[i] == '+') nargs++; } // reallocate argv and qs argv = uwsgi_malloc(sizeof(char *) * (3+nargs)); char *qs = uwsgi_concat2n(wsgi_req->query_string, wsgi_req->query_string_len, "", 0); // set the start position of args in argv i = 1; if (helper) i = 2; char *p, *ctx = NULL; uwsgi_foreach_token(qs, "+", p, ctx) { // create a copy for the url_decoded string char *arg_copy = uwsgi_str(p); uint16_t arg_copy_len = strlen(p); http_url_decode(p, &arg_copy_len, arg_copy); // and a final copy for shell escaped arg argv[i] = uwsgi_malloc( (arg_copy_len * 2) +1); escape_shell_arg(arg_copy, arg_copy_len, argv[i]); i++; } free(qs); } } if (helper) { if (!uwsgi_starts_with(helper, strlen(helper), "sym://", 6)) { void (*cgi_func)(char *) = dlsym(RTLD_DEFAULT, helper+6); if (cgi_func) { cgi_func(command); } else { uwsgi_log("unable to find symbol %s\n", helper+6); } exit(0); } argv[0] = helper; argv[1] = command; argv[nargs+2] = NULL; } else { argv[0] = command; argv[nargs+1] = NULL; } if (execvp(argv[0], argv)) { uwsgi_error("uwsgi_cgi_run()/execvp()"); } // never here exit(1); } static void uwsgi_cgi_after_request(struct wsgi_request *wsgi_req) { if (wsgi_req->async_plagued > 0) { int waitpid_status; pid_t cgi_pid = (pid_t) wsgi_req->async_plagued; int max_attempts = uc.async_max_attempts; if (!max_attempts) max_attempts = 10; while(max_attempts) { pid_t diedpid = waitpid(cgi_pid, &waitpid_status, WNOHANG); if (diedpid < 0) { uwsgi_error("waitpid()"); break; } else if (diedpid == 0) { int ret = uwsgi.wait_milliseconds_hook(1000); if (ret < 0) { kill_on_error if (waitpid(cgi_pid, &waitpid_status, 0) < 0) { uwsgi_error("waitpid()"); } } } else { break; } max_attempts--; } if (max_attempts == 0) { kill_on_error if (waitpid(cgi_pid, &waitpid_status, 0) < 0) { uwsgi_error("waitpid()"); } } } log_request(wsgi_req); } #ifdef UWSGI_ROUTING static int uwsgi_routing_func_cgi(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub_command = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub_command) return UWSGI_ROUTE_BREAK; struct uwsgi_buffer *ub_helper = NULL; if (ur->data2_len) { ub_helper = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data2, ur->data2_len); if (!ub_helper) { uwsgi_buffer_destroy(ub_command); return UWSGI_ROUTE_BREAK; } } else { if (!uwsgi_is_file(ub_command->buf)) { uwsgi_404(wsgi_req); uwsgi_buffer_destroy(ub_command); return UWSGI_ROUTE_BREAK; } if (access(ub_command->buf, X_OK)) { uwsgi_403(wsgi_req); uwsgi_buffer_destroy(ub_command); return UWSGI_ROUTE_BREAK; } } // we need a NULL suffix-ed copy of the docroot char *docroot = uwsgi_concat2n(wsgi_req->document_root, wsgi_req->document_root_len, "", 0); uwsgi_cgi_run(wsgi_req, wsgi_req->document_root, wsgi_req->document_root_len, ub_command->buf, ub_helper ? ub_helper->buf : NULL, NULL, NULL, 0, 0 ); free(docroot); uwsgi_buffer_destroy(ub_command); if (ub_helper) uwsgi_buffer_destroy(ub_helper); return UWSGI_ROUTE_BREAK; } static int uwsgi_router_cgi_helper(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_cgi; char *space = strchr(args, ' '); if (!space) { uwsgi_log("invalid cgihelper syntax, must be \"cgihelper:helper command\"\n"); return -1; } *space = 0; ur->data = space+1; ur->data_len = strlen(space+1); ur->data2 = args; ur->data2_len = strlen(args); return 0; } static int uwsgi_router_cgi(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_cgi; ur->data = args; ur->data_len = strlen(args); return 0; } static void uwsgi_cgi_register_router() { uwsgi_register_router("cgi", uwsgi_router_cgi); uwsgi_register_router("cgihelper", uwsgi_router_cgi_helper); } #endif struct uwsgi_plugin cgi_plugin = { .name = "cgi", .modifier1 = 9, .init = uwsgi_cgi_init, .init_apps = uwsgi_cgi_apps, .options = uwsgi_cgi_options, .request = uwsgi_cgi_request, .after_request = uwsgi_cgi_after_request, #ifdef UWSGI_ROUTING .on_load = uwsgi_cgi_register_router, #endif }; uwsgi-2.0.29/plugins/cgi/uwsgiplugin.py000066400000000000000000000001101477626554400201300ustar00rootroot00000000000000NAME='cgi' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['cgi_plugin'] uwsgi-2.0.29/plugins/cheaper_backlog2/000077500000000000000000000000001477626554400176225ustar00rootroot00000000000000uwsgi-2.0.29/plugins/cheaper_backlog2/cheaper_backlog2.c000066400000000000000000000042201477626554400231370ustar00rootroot00000000000000#include "../../uwsgi.h" /* This plugins is meant as an example for custom implementations. -- Copy of Cheaper, backlog algorithm (supported only on Linux) -- increse the number of workers when the listen queue is higher than uwsgi.cheaper_overload. Decrese when lower. */ extern struct uwsgi_server uwsgi; int cheaper_backlog2_algo(int can_spawn) { int i; #ifdef __linux__ int backlog = uwsgi.socket_timeout; #else int backlog = 0; #endif // if can_spawn == 0 we cannot spawn any new worker // this is set to 1 if --cheaper-rss-limit-* options are used and running workers are exceeding resources limit if (can_spawn && backlog > (int)uwsgi.cheaper_overload) { // activate the first available worker (taking step into account) int decheaped = 0; // search for cheaped workers for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].cheaped == 1 && uwsgi.workers[i].pid == 0) { decheaped++; if (decheaped >= uwsgi.cheaper_step) break; } } // return the maximum number of workers to spawn return decheaped; } else if (backlog < (int) uwsgi.cheaper_overload) { // count active workers int active_workers = 0; for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) { active_workers++; } } // cheap a worker if too much are running if (active_workers > uwsgi.cheaper_count) { return -1; } } return 0; } // registration hook void uwsgi_cheaper_register_backlog2(void) { uwsgi_register_cheaper_algo("backlog2", cheaper_backlog2_algo); } struct uwsgi_plugin cheaper_backlog2_plugin = { .name = "cheaper_backlog2", .on_load = uwsgi_cheaper_register_backlog2, }; uwsgi-2.0.29/plugins/cheaper_backlog2/uwsgiplugin.py000066400000000000000000000001341477626554400225470ustar00rootroot00000000000000NAME='cheaper_backlog2' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['cheaper_backlog2'] uwsgi-2.0.29/plugins/cheaper_busyness/000077500000000000000000000000001477626554400200115ustar00rootroot00000000000000uwsgi-2.0.29/plugins/cheaper_busyness/cheaper_busyness.c000066400000000000000000000441501477626554400235230ustar00rootroot00000000000000#include /* Busyness cheaper algorithm (by Łukasz Mierzwa) */ extern struct uwsgi_server uwsgi; // this global struct containes all of the relevant values struct uwsgi_cheaper_busyness_global { uint64_t busyness_max; uint64_t busyness_min; uint64_t *last_values; uint64_t *current_busyness; uint64_t total_avg_busyness; int *was_busy; uint64_t tcheck; uint64_t last_cheaped; // last time worker was cheaped due to low busyness uint64_t next_cheap; // timestamp, we can cheap worker after it uint64_t penalty; // penalty for respawning to fast, it will be added to multiplier uint64_t min_multi; //initial multiplier will be stored here uint64_t cheap_multi; // current multiplier value int last_action; // 1 - spawn workers ; 2 - cheap worker int verbose; // 1 - show debug logs, 0 - only important uint64_t tolerance_counter; // used to keep track of what to do if min <= busyness <= max for few cycles in row int emergency_workers; // counts the number of running emergency workers #ifdef __linux__ int backlog_alert; int backlog_step; uint64_t backlog_multi; // multiplier used to cheap emergency workers uint64_t backlog_nonzero_alert; int backlog_is_nonzero; uint64_t backlog_nonzero_since; // since when backlog is > 0 #endif } uwsgi_cheaper_busyness_global; struct uwsgi_option uwsgi_cheaper_busyness_options[] = { {"cheaper-busyness-max", required_argument, 0, "set the cheaper busyness high percent limit, above that value worker is considered loaded (default 50)", uwsgi_opt_set_64bit, &uwsgi_cheaper_busyness_global.busyness_max, 0}, {"cheaper-busyness-min", required_argument, 0, "set the cheaper busyness low percent limit, below that value worker is considered idle (default 25)", uwsgi_opt_set_64bit, &uwsgi_cheaper_busyness_global.busyness_min, 0}, {"cheaper-busyness-multiplier", required_argument, 0, "set initial cheaper multiplier, worker needs to be idle for cheaper-overload*multiplier seconds to be cheaped (default 10)", uwsgi_opt_set_64bit, &uwsgi_cheaper_busyness_global.cheap_multi, 0}, {"cheaper-busyness-penalty", required_argument, 0, "penalty for respawning workers to fast, it will be added to the current multiplier value if worker is cheaped and than respawned back too fast (default 2)", uwsgi_opt_set_64bit, &uwsgi_cheaper_busyness_global.penalty, 0}, {"cheaper-busyness-verbose", no_argument, 0, "enable verbose log messages from busyness algorithm", uwsgi_opt_true, &uwsgi_cheaper_busyness_global.verbose, 0}, #ifdef __linux__ {"cheaper-busyness-backlog-alert", required_argument, 0, "spawn emergency worker(s) if any time listen queue is higher than this value (default 33)", uwsgi_opt_set_int, &uwsgi_cheaper_busyness_global.backlog_alert, 0}, {"cheaper-busyness-backlog-multiplier", required_argument, 0, "set cheaper multiplier used for emergency workers (default 3)", uwsgi_opt_set_64bit, &uwsgi_cheaper_busyness_global.backlog_multi, 0}, {"cheaper-busyness-backlog-step", required_argument, 0, "number of emergency workers to spawn at a time (default 1)", uwsgi_opt_set_int, &uwsgi_cheaper_busyness_global.backlog_step, 0}, {"cheaper-busyness-backlog-nonzero", required_argument, 0, "spawn emergency worker(s) if backlog is > 0 for more then N seconds (default 60)", uwsgi_opt_set_64bit, &uwsgi_cheaper_busyness_global.backlog_nonzero_alert, 0}, #endif {0, 0, 0, 0, 0, 0 ,0}, }; // used to set time after when we allow to cheap workers void set_next_cheap_time(void) { uint64_t now = uwsgi_micros(); #ifdef __linux__ if (uwsgi_cheaper_busyness_global.emergency_workers > 0) { // we have some emergency workers running, we will use minimum delay (2 cycles) to cheap workers // to have quicker recovery from big but short load spikes // otherwise we might wait a lot before cheaping all emergency workers if (uwsgi_cheaper_busyness_global.verbose) uwsgi_log("[busyness] %d emergency worker(s) running, using %llu seconds cheaper timer\n", uwsgi_cheaper_busyness_global.emergency_workers, uwsgi.cheaper_overload*uwsgi_cheaper_busyness_global.backlog_multi); uwsgi_cheaper_busyness_global.next_cheap = now + uwsgi.cheaper_overload*uwsgi_cheaper_busyness_global.backlog_multi*1000000; } else { #endif // no emergency workers running, we use normal math for setting timer uwsgi_cheaper_busyness_global.next_cheap = now + uwsgi.cheaper_overload*uwsgi_cheaper_busyness_global.cheap_multi*1000000; #ifdef __linux__ } #endif } void decrease_multi(void) { // will decrease multiplier but only down to initial value if (uwsgi_cheaper_busyness_global.cheap_multi > uwsgi_cheaper_busyness_global.min_multi) { uwsgi_cheaper_busyness_global.cheap_multi--; uwsgi_log("[busyness] decreasing cheaper multiplier to %llu\n", uwsgi_cheaper_busyness_global.cheap_multi); } } #ifdef __linux__ int spawn_emergency_worker(int backlog) { // reset cheaper multiplier to minimum value so we can start cheaping workers sooner // if this was just random spike uwsgi_cheaper_busyness_global.cheap_multi = uwsgi_cheaper_busyness_global.min_multi; // set last action to spawn uwsgi_cheaper_busyness_global.last_action = 1; int decheaped = 0; int i; for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].cheaped == 1 && uwsgi.workers[i].pid == 0) { decheaped++; if (decheaped >= uwsgi_cheaper_busyness_global.backlog_step) break; } } // reset cheap timer, so that we need to start counting idle cycles from zero set_next_cheap_time(); if (decheaped > 0) { uwsgi_cheaper_busyness_global.emergency_workers += decheaped; uwsgi_log("[busyness] %d requests in listen queue, spawning %d emergency worker(s) (%d)!\n", backlog, decheaped, uwsgi_cheaper_busyness_global.emergency_workers); } else { uwsgi_log("[busyness] %d requests in listen queue but we are already started maximum number of workers (%d)\n", backlog, uwsgi.numproc); } return decheaped; } #endif int cheaper_busyness_algo(int can_spawn) { int i; // we use microseconds uint64_t t = uwsgi.cheaper_overload*1000000; int active_workers = 0; uint64_t total_busyness = 0; uint64_t avg_busyness = 0; for (i = 0; i < uwsgi.numproc; i++) { if (uwsgi.workers[i+1].cheaped == 0 && uwsgi.workers[i+1].pid > 0) { active_workers++; uwsgi_cheaper_busyness_global.was_busy[i] += uwsgi_worker_is_busy(i+1); } else { uwsgi_cheaper_busyness_global.was_busy[i] = 0; } } #ifdef __linux__ int backlog = uwsgi.shared->backlog; #endif uint64_t now = uwsgi_micros(); if (now - uwsgi_cheaper_busyness_global.tcheck >= t) { uwsgi_cheaper_busyness_global.tcheck = now; for (i = 0; i < uwsgi.numproc; i++) { if (uwsgi.workers[i+1].cheaped == 0 && uwsgi.workers[i+1].pid > 0) { uint64_t percent = (( (uwsgi.workers[i+1].running_time-uwsgi_cheaper_busyness_global.last_values[i])*100)/t); if (percent > 100) { percent = 100; } else if (uwsgi.workers[i+1].running_time-uwsgi_cheaper_busyness_global.last_values[i] == 0 && percent == 0 && uwsgi_cheaper_busyness_global.was_busy[i] > 0) { // running_time did not change but workers were busy // this means that workers had response times > busyness check interval if (uwsgi_cheaper_busyness_global.verbose) { uwsgi_log("[busyness] worker %d was busy %d time(s) in last cycle but no request was completed during this time, marking as 100%% busy\n", i+1, uwsgi_cheaper_busyness_global.was_busy[i]); } percent = 100; } uwsgi_cheaper_busyness_global.was_busy[i] = 0; total_busyness += percent; if (uwsgi_cheaper_busyness_global.verbose && active_workers > 1) uwsgi_log("[busyness] worker nr %d %llus average busyness is at %llu%%\n", i+1, uwsgi.cheaper_overload, percent); if (uwsgi.has_metrics) { // update metrics uwsgi_wlock(uwsgi.metrics_lock); uwsgi_cheaper_busyness_global.current_busyness[i] = percent; uwsgi_rwunlock(uwsgi.metrics_lock); } } uwsgi_cheaper_busyness_global.last_values[i] = uwsgi.workers[i+1].running_time; } avg_busyness = (active_workers ? total_busyness / active_workers : 0); if (uwsgi.has_metrics) { uwsgi_wlock(uwsgi.metrics_lock); uwsgi_cheaper_busyness_global.total_avg_busyness = avg_busyness; uwsgi_rwunlock(uwsgi.metrics_lock); } if (uwsgi_cheaper_busyness_global.verbose) uwsgi_log("[busyness] %ds average busyness of %d worker(s) is at %d%%\n", (int) uwsgi.cheaper_overload, (int) active_workers, (int) avg_busyness); if (avg_busyness > uwsgi_cheaper_busyness_global.busyness_max) { // we need to reset this to 0 since this is not idle cycle uwsgi_cheaper_busyness_global.tolerance_counter = 0; int decheaped = 0; if (can_spawn) { for (i = 1; i <= uwsgi.numproc; i++) { if (uwsgi.workers[i].cheaped == 1 && uwsgi.workers[i].pid == 0) { decheaped++; if (decheaped >= uwsgi.cheaper_step) break; } } } if (decheaped > 0) { // store information that we just spawned new workers uwsgi_cheaper_busyness_global.last_action = 1; // calculate number of seconds since last worker was cheaped if ((now - uwsgi_cheaper_busyness_global.last_cheaped)/uwsgi.cheaper_overload/1000000 <= uwsgi_cheaper_busyness_global.cheap_multi) { // worker was cheaped and then spawned back in less than current multiplier*cheaper_overload seconds // we will increase the multiplier so that next time worker will need to wait longer before being cheaped uwsgi_cheaper_busyness_global.cheap_multi += uwsgi_cheaper_busyness_global.penalty; uwsgi_log("[busyness] worker(s) respawned to fast, increasing cheaper multiplier to %llu (+%llu)\n", uwsgi_cheaper_busyness_global.cheap_multi, uwsgi_cheaper_busyness_global.penalty); } else { decrease_multi(); } set_next_cheap_time(); uwsgi_log("[busyness] %llus average busyness is at %llu%%, will spawn %d new worker(s)\n", uwsgi.cheaper_overload, avg_busyness, decheaped); } else { uwsgi_log("[busyness] %llus average busyness is at %llu%% but we already started maximum number of workers available with current limits (%d)\n", uwsgi.cheaper_overload, avg_busyness, active_workers); } // return the maximum number of workers to spawn return decheaped; #ifdef __linux__ } else if (can_spawn && backlog > uwsgi_cheaper_busyness_global.backlog_alert && active_workers < uwsgi.numproc) { return spawn_emergency_worker(backlog); #endif } else if (avg_busyness < uwsgi_cheaper_busyness_global.busyness_min) { // with only 1 worker running there is no point in doing all that magic if (active_workers == 1) return 0; // we need to reset this to 0 since this is not idle cycle uwsgi_cheaper_busyness_global.tolerance_counter = 0; if (active_workers > uwsgi.cheaper_count) { // cheap a worker if too much are running if (now >= uwsgi_cheaper_busyness_global.next_cheap) { // lower cheaper multiplier if this is subsequent cheap if (uwsgi_cheaper_busyness_global.last_action == 2) decrease_multi(); set_next_cheap_time(); uwsgi_log("[busyness] %llus average busyness is at %llu%%, cheap one of %d running workers\n", uwsgi.cheaper_overload, avg_busyness, (int) active_workers); // store timestamp uwsgi_cheaper_busyness_global.last_cheaped = uwsgi_micros(); // store information that last action performed was cheaping worker uwsgi_cheaper_busyness_global.last_action = 2; if (uwsgi_cheaper_busyness_global.emergency_workers > 0) uwsgi_cheaper_busyness_global.emergency_workers--; return -1; } else if (uwsgi_cheaper_busyness_global.verbose) uwsgi_log("[busyness] need to wait %llu more second(s) to cheap worker\n", (uwsgi_cheaper_busyness_global.next_cheap - now)/1000000); } } else { // with only 1 worker running there is no point in doing all that magic if (active_workers == 1) return 0; if (uwsgi_cheaper_busyness_global.emergency_workers > 0) // we had emergency workers running and we went down to the busyness // level that is high enough to slow down cheaping workers at extra speed uwsgi_cheaper_busyness_global.emergency_workers--; // we have min <= busyness <= max we need to check what happened before uwsgi_cheaper_busyness_global.tolerance_counter++; if (uwsgi_cheaper_busyness_global.tolerance_counter >= 3) { // we had three or more cycles when min <= busyness <= max, lets reset the cheaper timer // this is to prevent workers from being cheaped if we had idle cycles for almost all // time needed to cheap them, than a lot min uwsgi_cheaper_busyness_global.backlog_alert && active_workers < uwsgi.numproc) { // we check for backlog overload every cycle return spawn_emergency_worker(backlog); } else if (backlog > 0) { if (uwsgi_cheaper_busyness_global.backlog_is_nonzero) { // backlog was > 0 last time, check timestamp and spawn workers if needed if (can_spawn && (now - uwsgi_cheaper_busyness_global.backlog_nonzero_since)/1000000 >= uwsgi_cheaper_busyness_global.backlog_nonzero_alert) { uwsgi_log("[busyness] backlog was non-zero for %llu second(s), spawning new worker(s)\n", (now - uwsgi_cheaper_busyness_global.backlog_nonzero_since)/1000000); uwsgi_cheaper_busyness_global.backlog_nonzero_since = now; return spawn_emergency_worker(backlog); } } else { // this is first > 0 pass, setup timer if (uwsgi_cheaper_busyness_global.verbose) uwsgi_log("[busyness] backlog is starting to fill (%d)\n", backlog); uwsgi_cheaper_busyness_global.backlog_is_nonzero = 1; uwsgi_cheaper_busyness_global.backlog_nonzero_since = now; } } else if (uwsgi_cheaper_busyness_global.backlog_is_nonzero) { if (uwsgi_cheaper_busyness_global.verbose) uwsgi_log("[busyness] backlog is now empty\n"); uwsgi_cheaper_busyness_global.backlog_is_nonzero = 0; } #endif return 0; } // registration hook void uwsgi_cheaper_register_busyness(void) { uwsgi_register_cheaper_algo("busyness", cheaper_busyness_algo); } static int uwsgi_cheaper_busyness_init(void) { if (!uwsgi.requested_cheaper_algo || strcmp(uwsgi.requested_cheaper_algo, "busyness")) return 0; // this happens on the first run, the required memory is allocated uwsgi_cheaper_busyness_global.last_values = uwsgi_calloc(sizeof(uint64_t) * uwsgi.numproc); uwsgi_cheaper_busyness_global.was_busy = uwsgi_calloc(sizeof(int) * uwsgi.numproc); if (uwsgi.has_metrics) { // allocate metrics memory uwsgi_cheaper_busyness_global.current_busyness = uwsgi_calloc(sizeof(uint64_t) * uwsgi.numproc); } // set defaults if (!uwsgi_cheaper_busyness_global.busyness_max) uwsgi_cheaper_busyness_global.busyness_max = 50; if (!uwsgi_cheaper_busyness_global.busyness_min) uwsgi_cheaper_busyness_global.busyness_min = 25; if (!uwsgi_cheaper_busyness_global.cheap_multi) uwsgi_cheaper_busyness_global.cheap_multi = 10; if (!uwsgi_cheaper_busyness_global.penalty) uwsgi_cheaper_busyness_global.penalty = 2; #ifdef __linux__ if (!uwsgi_cheaper_busyness_global.backlog_alert) uwsgi_cheaper_busyness_global.backlog_alert = 33; if (!uwsgi_cheaper_busyness_global.backlog_multi) uwsgi_cheaper_busyness_global.backlog_multi = 3; if (!uwsgi_cheaper_busyness_global.backlog_step) uwsgi_cheaper_busyness_global.backlog_step = 1; if (!uwsgi_cheaper_busyness_global.backlog_nonzero_alert) uwsgi_cheaper_busyness_global.backlog_nonzero_alert = 60; #endif // store initial multiplier so we don't loose that value uwsgi_cheaper_busyness_global.min_multi = uwsgi_cheaper_busyness_global.cheap_multi; // since this is first run we will print current values uwsgi_log("[busyness] settings: min=%llu%%, max=%llu%%, overload=%llu, multiplier=%llu, respawn penalty=%llu\n", uwsgi_cheaper_busyness_global.busyness_min, uwsgi_cheaper_busyness_global.busyness_max, uwsgi.cheaper_overload, uwsgi_cheaper_busyness_global.cheap_multi, uwsgi_cheaper_busyness_global.penalty); #ifdef __linux__ uwsgi_log("[busyness] backlog alert is set to %d request(s), step is %d\n", uwsgi_cheaper_busyness_global.backlog_alert, uwsgi_cheaper_busyness_global.backlog_step); uwsgi_log("[busyness] backlog non-zero alert is set to %llu second(s)\n", uwsgi_cheaper_busyness_global.backlog_nonzero_alert); #endif // register metrics if enabled if (uwsgi.has_metrics) { int i; char buf[4096]; char buf2[4096]; for (i = 0; i < uwsgi.numproc; i++) { if (snprintf(buf, 4096, "worker.%d.plugin.cheaper_busyness.busyness", i+1) <= 0) { uwsgi_log("[busyness] unable to register busyness metric for worker %d\n", i+1); exit(1); } if (snprintf(buf2, 4096, "3.%d.100.1", i+1) <= 0) { uwsgi_log("[busyness] unable to register busyness metric oid for worker %d\n", i+1); exit(1); } uwsgi_register_metric(buf, buf2, UWSGI_METRIC_GAUGE, "ptr", &uwsgi_cheaper_busyness_global.current_busyness[i], 0, NULL); } uwsgi_register_metric("plugin.cheaper_busyness.total_avg_busyness", "4.100.1", UWSGI_METRIC_GAUGE, "ptr", &uwsgi_cheaper_busyness_global.total_avg_busyness, 0, NULL); uwsgi_log("[busyness] metrics registered\n"); } // initialize timers uwsgi_cheaper_busyness_global.tcheck = uwsgi_micros(); set_next_cheap_time(); return 0; } struct uwsgi_plugin cheaper_busyness_plugin = { .name = "cheaper_busyness", .on_load = uwsgi_cheaper_register_busyness, .options = uwsgi_cheaper_busyness_options, .init = uwsgi_cheaper_busyness_init }; uwsgi-2.0.29/plugins/cheaper_busyness/uwsgiplugin.py000066400000000000000000000001341477626554400227360ustar00rootroot00000000000000NAME='cheaper_busyness' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['cheaper_busyness'] uwsgi-2.0.29/plugins/clock_monotonic/000077500000000000000000000000001477626554400176275ustar00rootroot00000000000000uwsgi-2.0.29/plugins/clock_monotonic/clock_monotonic.c000066400000000000000000000013321477626554400231520ustar00rootroot00000000000000#include "../../uwsgi.h" // timespecs have nanoseconds resolution time_t uwsgi_monotonic_seconds() { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return ts.tv_sec; } uint64_t uwsgi_monotonic_microseconds() { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return ((uint64_t)ts.tv_sec * 1000000) + (ts.tv_nsec/1000); } static struct uwsgi_clock uwsgi_monotonic_clock = { .name = "monotonic", .seconds = uwsgi_monotonic_seconds, .microseconds = uwsgi_monotonic_microseconds, }; void uwsgi_monotonic_clock_load() { uwsgi_register_clock(&uwsgi_monotonic_clock); } struct uwsgi_plugin clock_monotonic_plugin = { .name = "clock_monotonic", .on_load = uwsgi_monotonic_clock_load }; uwsgi-2.0.29/plugins/clock_monotonic/uwsgiplugin.py000066400000000000000000000001401477626554400225510ustar00rootroot00000000000000NAME='clock_monotonic' CFLAGS = [] LDFLAGS = [] LIBS = ['-lrt'] GCC_LIST = ['clock_monotonic'] uwsgi-2.0.29/plugins/clock_realtime/000077500000000000000000000000001477626554400174245ustar00rootroot00000000000000uwsgi-2.0.29/plugins/clock_realtime/clock_realtime.c000066400000000000000000000013161477626554400225460ustar00rootroot00000000000000#include "../../uwsgi.h" // timespecs have nanoseconds resolution time_t uwsgi_realtime_seconds() { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); return ts.tv_sec; } uint64_t uwsgi_realtime_microseconds() { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); return ((uint64_t) ts.tv_sec * 1000000) + (ts.tv_nsec/1000); } static struct uwsgi_clock uwsgi_realtime_clock = { .name = "realtime", .seconds = uwsgi_realtime_seconds, .microseconds = uwsgi_realtime_microseconds, }; void uwsgi_realtime_clock_load() { uwsgi_register_clock(&uwsgi_realtime_clock); } struct uwsgi_plugin clock_realtime_plugin = { .name = "clock_realtime", .on_load = uwsgi_realtime_clock_load }; uwsgi-2.0.29/plugins/clock_realtime/uwsgiplugin.py000066400000000000000000000001361477626554400223530ustar00rootroot00000000000000NAME='clock_realtime' CFLAGS = [] LDFLAGS = [] LIBS = ['-lrt'] GCC_LIST = ['clock_realtime'] uwsgi-2.0.29/plugins/corerouter/000077500000000000000000000000001477626554400166405ustar00rootroot00000000000000uwsgi-2.0.29/plugins/corerouter/corerouter.c000066400000000000000000001026641477626554400212060ustar00rootroot00000000000000/* uWSGI corerouter requires: - async - caching - pcre (optional) */ #include extern struct uwsgi_server uwsgi; #include "cr.h" struct corerouter_peer *uwsgi_cr_peer_find_by_sid(struct corerouter_session *cs, uint32_t sid) { struct corerouter_peer *peers = cs->peers; while(peers) { if (peers->sid == sid) { return peers; } peers = peers->next; } return NULL; } // add a new peer to the session struct corerouter_peer *uwsgi_cr_peer_add(struct corerouter_session *cs) { struct corerouter_peer *old_peers = NULL, *peers = cs->peers; while(peers) { old_peers = peers; peers = peers->next; } peers = uwsgi_calloc(sizeof(struct corerouter_peer)); peers->session = cs; peers->fd = -1; // create input buffer size_t bufsize = cs->corerouter->buffer_size; if (!bufsize) bufsize = uwsgi.page_size; peers->in = uwsgi_buffer_new(bufsize); // add timeout peers->current_timeout = cs->corerouter->socket_timeout; peers->timeout = cr_add_timeout(cs->corerouter, peers); peers->prev = old_peers; if (old_peers) { old_peers->next = peers; } else { cs->peers = peers; } return peers; } // reset a peer (allows it to connect to another backend) void uwsgi_cr_peer_reset(struct corerouter_peer *peer) { if (peer->tmp_socket_name) { free(peer->tmp_socket_name); peer->tmp_socket_name = NULL; } cr_del_timeout(peer->session->corerouter, peer); if (peer->fd != -1) { close(peer->fd); peer->session->corerouter->cr_table[peer->fd] = NULL; peer->fd = -1; peer->hook_read = NULL; peer->hook_write = NULL; } if (peer->is_buffering) { if (peer->buffering_fd != -1) { close(peer->buffering_fd); } } peer->failed = 0; peer->soopt = 0; peer->timed_out = 0; peer->un = NULL; peer->static_node = NULL; } // destroy a peer int uwsgi_cr_peer_del(struct corerouter_peer *peer) { // first of all check if we need to run a flush procedure if (peer->flush && !peer->is_flushing) { peer->is_flushing = 1; // on success, suspend the execution if (peer->flush(peer) > 0) return -1; } struct corerouter_peer *prev = peer->prev; struct corerouter_peer *next = peer->next; if (prev) { prev->next = peer->next; } if (next) { next->prev = peer->prev; } if (peer == peer->session->peers) { peer->session->peers = peer->next; } uwsgi_cr_peer_reset(peer); if (peer->in) { uwsgi_buffer_destroy(peer->in); } // main_peer bring the output buffer from backend peers if (peer->out && peer->out_need_free) { uwsgi_buffer_destroy(peer->out); } free(peer); return 0; } void uwsgi_opt_corerouter(char *opt, char *value, void *cr) { struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) cr; uwsgi_new_gateway_socket(value, ucr->name); ucr->has_sockets++; } void uwsgi_opt_undeferred_corerouter(char *opt, char *value, void *cr) { struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) cr; struct uwsgi_gateway_socket *ugs = uwsgi_new_gateway_socket(value, ucr->name); ugs->no_defer = 1; ucr->has_sockets++; } void uwsgi_opt_corerouter_use_socket(char *opt, char *value, void *cr) { struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) cr; ucr->use_socket = 1; ucr->has_backends++; if (value) { ucr->socket_num = atoi(value); } } void uwsgi_opt_corerouter_use_base(char *opt, char *value, void *cr) { struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) cr; ucr->base = value; ucr->base_len = strlen(ucr->base); ucr->has_backends++; } void uwsgi_opt_corerouter_use_pattern(char *opt, char *value, void *cr) { struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) cr; ucr->pattern = value; ucr->pattern_len = strlen(ucr->pattern); ucr->has_backends++; } void uwsgi_opt_corerouter_zerg(char *opt, char *value, void *cr) { int j; int count = 8; struct uwsgi_gateway_socket *ugs; struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) cr; int zerg_fd = uwsgi_connect(value, 30, 0); if (zerg_fd < 0) { uwsgi_log("--- unable to connect to zerg server ---\n"); exit(1); } int last_count = count; int *zerg = uwsgi_attach_fd(zerg_fd, &count, "uwsgi-zerg", 10); if (zerg == NULL) { if (last_count != count) { close(zerg_fd); zerg_fd = uwsgi_connect(value, 30, 0); if (zerg_fd < 0) { uwsgi_log("--- unable to connect to zerg server ---\n"); exit(1); } zerg = uwsgi_attach_fd(zerg_fd, &count, "uwsgi-zerg", 10); } else { uwsgi_log("--- invalid data received from zerg-server ---\n"); exit(1); } } if (zerg == NULL) { uwsgi_log("--- invalid data received from zerg-server ---\n"); exit(1); } close(zerg_fd); for(j=0;jname); ugs->zerg = optarg; } free(zerg); } void uwsgi_opt_corerouter_cs(char *opt, char *value, void *cr) { struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) cr; char *cs = uwsgi_str(value); char *cs_code = strchr(cs, ':'); if (!cs_code) { uwsgi_log("invalid code_string option\n"); exit(1); } cs_code[0] = 0; char *cs_func = strchr(cs_code + 1, ':'); if (!cs_func) { uwsgi_log("invalid code_string option\n"); exit(1); } cs_func[0] = 0; ucr->code_string_modifier1 = atoi(cs); ucr->code_string_code = cs_code + 1; ucr->code_string_function = cs_func + 1; ucr->has_backends++; } void uwsgi_opt_corerouter_ss(char *opt, char *value, void *cr) { struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) cr; struct uwsgi_gateway_socket *ugs = uwsgi_new_gateway_socket(value, ucr->name); ugs->subscription = 1; ucr->has_subscription_sockets++; // this is the subscription hash table ucr->subscriptions = uwsgi_subscription_init_ht(); ucr->has_backends++; } void uwsgi_opt_corerouter_fallback_key(char *opt, char *value, void *key) { struct uwsgi_corerouter *ptr = (struct uwsgi_corerouter *) key; if (!value) { ptr->fallback_key = NULL; ptr->fallback_key_len = 0; return; } ptr->fallback_key = value; ptr->fallback_key_len = strlen(value); } void corerouter_send_stats(struct uwsgi_corerouter *); void corerouter_manage_subscription(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) { struct uwsgi_subscribe_req *usr = (struct uwsgi_subscribe_req *) data; if (!uwsgi_strncmp("key", 3, key, keylen)) { usr->key = val; usr->keylen = vallen; } else if (!uwsgi_strncmp("address", 7, key, keylen)) { usr->address = val; usr->address_len = vallen; } else if (!uwsgi_strncmp("modifier1", 9, key, keylen)) { usr->modifier1 = uwsgi_str_num(val, vallen); } else if (!uwsgi_strncmp("modifier2", 9, key, keylen)) { usr->modifier2 = uwsgi_str_num(val, vallen); } else if (!uwsgi_strncmp("cores", 5, key, keylen)) { usr->cores = uwsgi_str_num(val, vallen); } else if (!uwsgi_strncmp("load", 4, key, keylen)) { usr->load = uwsgi_str_num(val, vallen); } else if (!uwsgi_strncmp("weight", 6, key, keylen)) { usr->weight = uwsgi_str_num(val, vallen); } else if (!uwsgi_strncmp("unix", 4, key, keylen)) { usr->unix_check = uwsgi_str_num(val, vallen); } else if (!uwsgi_strncmp("sign", 4, key, keylen)) { usr->sign = val; usr->sign_len = vallen; } else if (!uwsgi_strncmp("sni_key", 7, key, keylen)) { usr->sni_key = val; usr->sni_key_len = vallen; } else if (!uwsgi_strncmp("sni_crt", 7, key, keylen)) { usr->sni_crt = val; usr->sni_crt_len = vallen; } else if (!uwsgi_strncmp("sni_ca", 6, key, keylen)) { usr->sni_ca = val; usr->sni_ca_len = vallen; } else if (!uwsgi_strncmp("notify", 6, key, keylen)) { usr->notify = val; usr->notify_len = vallen; } } void corerouter_close_peer(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) { struct corerouter_session *cs = peer->session; // manage subscription reference count if (ucr->subscriptions && peer->un && peer->un->len > 0) { // decrease reference count #ifdef UWSGI_DEBUG uwsgi_log("[1] node %.*s refcnt: %llu\n", peer->un->len, peer->un->name, peer->un->reference); #endif peer->un->reference--; #ifdef UWSGI_DEBUG uwsgi_log("[2] node %.*s refcnt: %llu\n", peer->un->len, peer->un->name, peer->un->reference); #endif } if (peer->failed) { if (peer->soopt) { if (!ucr->quiet) uwsgi_log("[uwsgi-%s] unable to connect() to node \"%.*s\" (%d retries): %s\n", ucr->short_name, (int) peer->instance_address_len, peer->instance_address, peer->retries, strerror(peer->soopt)); } else if (peer->timed_out) { if (peer->instance_address_len > 0) { if (peer->connecting) { if (!ucr->quiet) uwsgi_log("[uwsgi-%s] unable to connect() to node \"%.*s\" (%d retries): timeout\n", ucr->short_name, (int) peer->instance_address_len, peer->instance_address, peer->retries); } } } // now check for dead nodes if (ucr->subscriptions && peer->un && peer->un->len > 0) { if (peer->un->death_mark == 0) uwsgi_log("[uwsgi-%s] %.*s => marking %.*s as failed\n", ucr->short_name, (int) peer->key_len, peer->key, (int) peer->instance_address_len, peer->instance_address); peer->un->failcnt++; peer->un->death_mark = 1; // check if i can remove the node if (peer->un->reference == 0) { uwsgi_remove_subscribe_node(ucr->subscriptions, peer->un); } if (ucr->cheap && !ucr->i_am_cheap && !ucr->fallback && uwsgi_no_subscriptions(ucr->subscriptions)) { uwsgi_gateway_go_cheap(ucr->name, ucr->queue, &ucr->i_am_cheap); } } else if (peer->static_node) { peer->static_node->custom = uwsgi_now(); uwsgi_log("[uwsgi-%s] %.*s => marking %.*s as failed\n", ucr->short_name, (int) peer->key_len, peer->key, (int) peer->instance_address_len, peer->instance_address); } // check if the router supports the retry hook if (!peer->can_retry) goto end; if (peer->retries >= (size_t) ucr->max_retries) goto end; peer->retries++; // reset the peer uwsgi_cr_peer_reset(peer); // set new timeout peer->timeout = cr_add_timeout(ucr, peer); if (ucr->fallback) { // ok let's try with the fallback nodes if (!cs->fallback) { cs->fallback = ucr->fallback; } else { cs->fallback = cs->fallback->next; if (!cs->fallback) goto end; } peer->instance_address = cs->fallback->value; peer->instance_address_len = cs->fallback->len; if (cs->retry(peer)) { if (!peer->failed) goto end; } return; } peer->instance_address = NULL; peer->instance_address_len = 0; if (cs->retry(peer)) { if (!peer->failed) goto end; } return; } end: if (uwsgi_cr_peer_del(peer) < 0) return; if (peer == cs->main_peer) { cs->main_peer = NULL; corerouter_close_session(ucr, cs); } else { if (cs->can_keepalive == 0 && cs->wait_full_write == 0) { corerouter_close_session(ucr, cs); } } } // destroy a session void corerouter_close_session(struct uwsgi_corerouter *ucr, struct corerouter_session *cr_session) { struct corerouter_peer *main_peer = cr_session->main_peer; if (main_peer) { if (uwsgi_cr_peer_del(main_peer) < 0) return; } // free peers struct corerouter_peer *peers = cr_session->peers; while(peers) { struct corerouter_peer *tmp_peer = peers; peers = peers->next; // special case here for subscription system if (ucr->subscriptions && tmp_peer->un && tmp_peer->un->len) { tmp_peer->un->reference--; } if (uwsgi_cr_peer_del(tmp_peer) < 0) return; } // could be used to free additional resources if (cr_session->close) cr_session->close(cr_session); free(cr_session); if (ucr->active_sessions == 0) { uwsgi_log("[BUG] number of active sessions already 0 !!!\n"); return; } ucr->active_sessions--; } struct uwsgi_rb_timer *corerouter_reset_timeout(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) { cr_del_timeout(ucr, peer); return cr_add_timeout(ucr, peer); } struct uwsgi_rb_timer *corerouter_reset_timeout_fast(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer, time_t now) { cr_del_timeout(ucr, peer); return cr_add_timeout_fast(ucr, peer, now); } static void corerouter_expire_timeouts(struct uwsgi_corerouter *ucr, time_t now) { uint64_t current = (uint64_t) now; struct uwsgi_rb_timer *urbt; struct corerouter_peer *peer; for (;;) { urbt = uwsgi_min_rb_timer(ucr->timeouts, NULL); if (urbt == NULL) return; if (urbt->value <= current) { peer = (struct corerouter_peer *) urbt->data; peer->timed_out = 1; if (peer->connecting) { peer->failed = 1; } corerouter_close_peer(ucr, peer); continue; } break; } } int uwsgi_cr_set_hooks(struct corerouter_peer *peer, ssize_t (*read_hook)(struct corerouter_peer *), ssize_t (*write_hook)(struct corerouter_peer *)) { struct corerouter_session *cs = peer->session; struct uwsgi_corerouter *ucr = cs->corerouter; //uwsgi_log("uwsgi_cr_set_hooks(%d, %p, %p)\n", peer->fd, read_hook, write_hook); if (read_hook) { peer->last_hook_read = read_hook; } if (write_hook) { peer->last_hook_write = write_hook; } int read_changed = 1; int write_changed = 1; if (read_hook && peer->hook_read) { read_changed = 0; } else if (!read_hook && !peer->hook_read) { read_changed = 0; } if (write_hook && peer->hook_write) { write_changed = 0; } else if (!write_hook && !peer->hook_write) { write_changed = 0; } if (!read_changed && !write_changed) { goto unchanged; } int has_read = 0; int has_write = 0; if (peer->hook_read) { has_read = 1; } if (peer->hook_write) { has_write = 1; } if (!read_hook && !write_hook) { if (has_read) { if (event_queue_del_fd(ucr->queue, peer->fd, event_queue_read())) return -1; } if (has_write) { if (event_queue_del_fd(ucr->queue, peer->fd, event_queue_write())) return -1; } } else if (read_hook && write_hook) { if (has_read) { if (event_queue_fd_read_to_readwrite(ucr->queue, peer->fd)) return -1; } else if (has_write) { if (event_queue_fd_write_to_readwrite(ucr->queue, peer->fd)) return -1; } } else if (read_hook) { if (has_write) { if (write_changed) { if (event_queue_fd_write_to_read(ucr->queue, peer->fd)) return -1; } else { if (event_queue_fd_write_to_readwrite(ucr->queue, peer->fd)) return -1; } } else { if (event_queue_add_fd_read(ucr->queue, peer->fd)) return -1; } } else if (write_hook) { if (has_read) { if (read_changed) { if (event_queue_fd_read_to_write(ucr->queue, peer->fd)) return -1; } else { if (event_queue_fd_read_to_readwrite(ucr->queue, peer->fd)) return -1; } } else { if (event_queue_add_fd_write(ucr->queue, peer->fd)) return -1; } } unchanged: peer->hook_read = read_hook; peer->hook_write = write_hook; return 0; } struct corerouter_session *corerouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket *ugs, int new_connection, struct sockaddr *cr_addr, socklen_t cr_addr_len) { struct corerouter_session *cs = uwsgi_calloc(ucr->session_size); struct corerouter_peer *peer = uwsgi_calloc(sizeof(struct corerouter_peer)); // main_peer has only input buffer as output buffer is taken from backend peers size_t bufsize = ucr->buffer_size; if (!bufsize) bufsize = uwsgi.page_size; peer->in = uwsgi_buffer_new(bufsize); ucr->cr_table[new_connection] = peer; cs->main_peer = peer; peer->fd = new_connection; peer->session = cs; // map corerouter and socket cs->corerouter = ucr; cs->ugs = ugs; // set initial timeout (could be overridden) peer->current_timeout = ucr->socket_timeout; ucr->active_sessions++; // build the client address memcpy(&cs->client_sockaddr, cr_addr, cr_addr_len); switch(cr_addr->sa_family) { case AF_INET: if (inet_ntop(AF_INET, &cs->client_sockaddr.sa_in.sin_addr, cs->client_address, sizeof(cs->client_address)) == NULL) { uwsgi_error("corerouter_alloc_session/inet_ntop()"); memcpy(cs->client_address, "0.0.0.0", 7); cs->client_port[0] = '0'; cs->client_port[1] = 0; } uwsgi_num2str2(cs->client_sockaddr.sa_in.sin_port, cs->client_port); break; #ifdef AF_INET6 case AF_INET6: if (inet_ntop(AF_INET6, &cs->client_sockaddr.sa_in6.sin6_addr, cs->client_address, sizeof(cs->client_address)) == NULL) { uwsgi_error("corerouter_alloc_session/inet_ntop()"); memcpy(cs->client_address, "0.0.0.0", 7); cs->client_port[0] = '0'; cs->client_port[1] = 0; } uwsgi_num2str2(cs->client_sockaddr.sa_in6.sin6_port, cs->client_port); break; #endif default: memcpy(cs->client_address, "0.0.0.0", 7); cs->client_port[0] = '0'; cs->client_port[1] = 0; break; } // here we prepare the real session and set the hooks if (ucr->alloc_session(ucr, ugs, cs, cr_addr, cr_addr_len)) { corerouter_close_session(ucr, cs); cs = NULL; } else { // truly set the timeout peer->timeout = cr_add_timeout(ucr, ucr->cr_table[new_connection]); } return cs; } void uwsgi_corerouter_loop(int id, void *data) { int i; struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) data; ucr->cr_stats_server = -1; ucr->cr_table = uwsgi_malloc(sizeof(struct corerouter_session *) * uwsgi.max_fd); for (i = 0; i < (int) uwsgi.max_fd; i++) { ucr->cr_table[i] = NULL; } ucr->i_am_cheap = ucr->cheap; void *events = uwsgi_corerouter_setup_event_queue(ucr, id); if (ucr->has_subscription_sockets) event_queue_add_fd_read(ucr->queue, ushared->gateways[id].internal_subscription_pipe[1]); if (!ucr->socket_timeout) ucr->socket_timeout = 60; if (!ucr->static_node_gracetime) ucr->static_node_gracetime = 30; int i_am_the_first = 1; for(i=0;igateways[i].name, ucr->name)) { i_am_the_first = 0; break; } } if (ucr->stats_server && i_am_the_first) { char *tcp_port = strchr(ucr->stats_server, ':'); if (tcp_port) { // disable deferred accept for this socket int current_defer_accept = uwsgi.no_defer_accept; uwsgi.no_defer_accept = 1; ucr->cr_stats_server = bind_to_tcp(ucr->stats_server, uwsgi.listen_queue, tcp_port); uwsgi.no_defer_accept = current_defer_accept; } else { ucr->cr_stats_server = bind_to_unix(ucr->stats_server, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); } event_queue_add_fd_read(ucr->queue, ucr->cr_stats_server); uwsgi_log("*** %s stats server enabled on %s fd: %d ***\n", ucr->short_name, ucr->stats_server, ucr->cr_stats_server); } if (ucr->use_socket) { ucr->to_socket = uwsgi_get_socket_by_num(ucr->socket_num); if (ucr->to_socket) { // fix socket name_len if (ucr->to_socket->name_len == 0 && ucr->to_socket->name) { ucr->to_socket->name_len = strlen(ucr->to_socket->name); } } } if (!ucr->pb_base_dir) { ucr->pb_base_dir = getenv("TMPDIR"); if (!ucr->pb_base_dir) ucr->pb_base_dir = "/tmp"; } int nevents; time_t delta; struct uwsgi_rb_timer *min_timeout; int new_connection; if (ucr->pattern) { init_magic_table(ucr->magic_table); } union uwsgi_sockaddr cr_addr; socklen_t cr_addr_len = sizeof(struct sockaddr_un); ucr->mapper = uwsgi_cr_map_use_void; if (ucr->use_cache) { ucr->cache = uwsgi_cache_by_name(ucr->use_cache); if (!ucr->cache) { uwsgi_log("!!! unable to find cache \"%s\" !!!\n", ucr->use_cache); exit(1); } ucr->mapper = uwsgi_cr_map_use_cache; } else if (ucr->pattern) { ucr->mapper = uwsgi_cr_map_use_pattern; } else if (ucr->has_subscription_sockets) { ucr->mapper = uwsgi_cr_map_use_subscription; if (uwsgi.subscription_dotsplit) { ucr->mapper = uwsgi_cr_map_use_subscription_dotsplit; } } else if (ucr->base) { ucr->mapper = uwsgi_cr_map_use_base; } else if (ucr->code_string_code && ucr->code_string_function) { ucr->mapper = uwsgi_cr_map_use_cs; } else if (ucr->to_socket) { ucr->mapper = uwsgi_cr_map_use_to; } else if (ucr->static_nodes) { ucr->mapper = uwsgi_cr_map_use_static_nodes; } ucr->timeouts = uwsgi_init_rb_timer(); for (;;) { time_t now = uwsgi_now(); // set timeouts and harakiri min_timeout = uwsgi_min_rb_timer(ucr->timeouts, NULL); if (min_timeout == NULL) { delta = -1; } else { delta = min_timeout->value - now; if (delta <= 0) { corerouter_expire_timeouts(ucr, now); delta = 0; } } if (uwsgi.master_process && ucr->harakiri > 0) { ushared->gateways_harakiri[id] = 0; } // wait for events nevents = event_queue_wait_multi(ucr->queue, delta, events, ucr->nevents); now = uwsgi_now(); if (uwsgi.master_process && ucr->harakiri > 0) { ushared->gateways_harakiri[id] = now + ucr->harakiri; } if (nevents == 0) { corerouter_expire_timeouts(ucr, now); } for (i = 0; i < nevents; i++) { // get the interesting fd ucr->interesting_fd = event_queue_interesting_fd(events, i); // something bad happened if (ucr->interesting_fd < 0) continue; // check if the ucr->interesting_fd matches a gateway socket struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets; int taken = 0; while (ugs) { if (ugs->gateway == &ushared->gateways[id] && ucr->interesting_fd == ugs->fd) { if (!ugs->subscription) { #if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL) new_connection = accept4(ucr->interesting_fd, (struct sockaddr *) &cr_addr, &cr_addr_len, SOCK_NONBLOCK); if (new_connection < 0) { taken = 1; break; } #else new_connection = accept(ucr->interesting_fd, (struct sockaddr *) &cr_addr, &cr_addr_len); if (new_connection < 0) { taken = 1; break; } // set socket in non-blocking mode, on non-linux platforms, clients get the server mode #ifdef __linux__ uwsgi_socket_nb(new_connection); #endif #endif struct corerouter_session *cr = corerouter_alloc_session(ucr, ugs, new_connection, (struct sockaddr *) &cr_addr, cr_addr_len); //something wrong in the allocation if (!cr) break; } else if (ugs->subscription) { uwsgi_corerouter_manage_subscription(ucr, id, ugs); } taken = 1; break; } ugs = ugs->next; } if (taken) { continue; } // manage internal subscription if (ucr->interesting_fd == ushared->gateways[id].internal_subscription_pipe[1]) { uwsgi_corerouter_manage_internal_subscription(ucr, ucr->interesting_fd); } // manage a stats request else if (ucr->interesting_fd == ucr->cr_stats_server) { corerouter_send_stats(ucr); } else { struct corerouter_peer *peer = ucr->cr_table[ucr->interesting_fd]; // something is going wrong... if (peer == NULL) continue; // on error, destroy the session if (event_queue_interesting_fd_has_error(events, i)) { peer->failed = 1; corerouter_close_peer(ucr, peer); continue; } // set timeout (in main_peer too) peer->timeout = corerouter_reset_timeout_fast(ucr, peer, now); peer->session->main_peer->timeout = corerouter_reset_timeout_fast(ucr, peer->session->main_peer, now); ssize_t (*hook)(struct corerouter_peer *) = NULL; // call event hook if (event_queue_interesting_fd_is_read(events, i)) { hook = peer->hook_read; } else if (event_queue_interesting_fd_is_write(events, i)) { hook = peer->hook_write; } if (!hook) continue; // reset errno (as we use it for internal signalling) errno = 0; ssize_t ret = hook(peer); // connection closed if (ret == 0) { corerouter_close_peer(ucr, peer); continue; } else if (ret < 0) { if (errno == EINPROGRESS) continue; // remove keepalive on error peer->session->can_keepalive = 0; corerouter_close_peer(ucr, peer); continue; } } } } } int uwsgi_corerouter_has_backends(struct uwsgi_corerouter *ucr) { if (ucr->has_backends) return 1; // check if the router has configured backends if (ucr->use_cache || ucr->pattern || ucr->has_subscription_sockets || ucr->base || (ucr->code_string_code && ucr->code_string_function) || ucr->to_socket || ucr->static_nodes ) { return 1; } return 0; } int uwsgi_corerouter_init(struct uwsgi_corerouter *ucr) { int i; if (ucr->has_sockets) { if (ucr->use_cache && !uwsgi.caches) { uwsgi_log("you need to create a uwsgi cache to use the %s (add --cache )\n", ucr->name); exit(1); } if (!ucr->nevents) ucr->nevents = 64; if (!ucr->max_retries) ucr->max_retries = 3; ucr->has_backends = uwsgi_corerouter_has_backends(ucr); uwsgi_corerouter_setup_sockets(ucr); if (ucr->processes < 1) ucr->processes = 1; if (ucr->cheap) { uwsgi_log("starting %s in cheap mode\n", ucr->name); } for (i = 0; i < ucr->processes; i++) { struct uwsgi_gateway *ug = register_gateway(ucr->name, uwsgi_corerouter_loop, ucr); if (ug == NULL) { uwsgi_log("unable to register the %s gateway\n", ucr->name); exit(1); } ug->uid = ucr->uid; ug->gid = ucr->gid; } } return 0; } struct uwsgi_plugin corerouter_plugin = { .name = "corerouter", }; void corerouter_send_stats(struct uwsgi_corerouter *ucr) { struct sockaddr_un client_src; socklen_t client_src_len = 0; int client_fd = accept(ucr->cr_stats_server, (struct sockaddr *) &client_src, &client_src_len); if (client_fd < 0) { uwsgi_error("corerouter_send_stats()/accept()"); return; } if (uwsgi.stats_http) { if (uwsgi_send_http_stats(client_fd)) { close(client_fd); return; } } struct uwsgi_stats *us = uwsgi_stats_new(8192); if (uwsgi_stats_keyval_comma(us, "version", UWSGI_VERSION)) goto end; if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) getpid())) goto end; if (uwsgi_stats_keylong_comma(us, "uid", (unsigned long long) getuid())) goto end; if (uwsgi_stats_keylong_comma(us, "gid", (unsigned long long) getgid())) goto end; char *cwd = uwsgi_get_cwd(); if (uwsgi_stats_keyval_comma(us, "cwd", cwd)) goto end0; if (uwsgi_stats_keylong_comma(us, "active_sessions", (unsigned long long) ucr->active_sessions)) goto end0; if (uwsgi_stats_key(us , ucr->short_name)) goto end0; if (uwsgi_stats_list_open(us)) goto end0; struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets; while (ugs) { if (!strcmp(ugs->owner, ucr->name)) { if (uwsgi_stats_str(us, ugs->name)) goto end0; if (ugs->next) { if (uwsgi_stats_comma(us)) goto end0; } } ugs = ugs->next; } if (uwsgi_stats_list_close(us)) goto end0; if (uwsgi_stats_comma(us)) goto end0; if (ucr->static_nodes) { if (uwsgi_stats_key(us , "static_nodes")) goto end0; if (uwsgi_stats_list_open(us)) goto end0; struct uwsgi_string_list *usl = ucr->static_nodes; while(usl) { if (uwsgi_stats_object_open(us)) goto end0; if (uwsgi_stats_keyvaln_comma(us, "name", usl->value, usl->len)) goto end0; if (uwsgi_stats_keylong_comma(us, "hits", (unsigned long long) usl->custom2)) goto end0; if (uwsgi_stats_keylong(us, "grace", (unsigned long long) usl->custom)) goto end0; if (uwsgi_stats_object_close(us)) goto end0; usl = usl->next; if (usl) { if (uwsgi_stats_comma(us)) goto end0; } } if (uwsgi_stats_list_close(us)) goto end0; if (uwsgi_stats_comma(us)) goto end0; } if (ucr->has_subscription_sockets) { if (uwsgi_stats_key(us , "subscriptions")) goto end0; if (uwsgi_stats_list_open(us)) goto end0; int i; int first_processed = 0; for(i=0;isubscriptions[i]; if (s_slot && first_processed) { if (uwsgi_stats_comma(us)) goto end0; } while (s_slot) { first_processed = 1; if (uwsgi_stats_object_open(us)) goto end0; if (uwsgi_stats_keyvaln_comma(us, "key", s_slot->key, s_slot->keylen)) goto end0; if (uwsgi_stats_keylong_comma(us, "hash", (unsigned long long) s_slot->hash)) goto end0; if (uwsgi_stats_keylong_comma(us, "hits", (unsigned long long) s_slot->hits)) goto end0; #ifdef UWSGI_SSL if (uwsgi_stats_keylong_comma(us, "sni_enabled", (unsigned long long) s_slot->sni_enabled)) goto end0; #endif if (uwsgi_stats_key(us , "nodes")) goto end0; if (uwsgi_stats_list_open(us)) goto end0; struct uwsgi_subscribe_node *s_node = s_slot->nodes; while (s_node) { if (uwsgi_stats_object_open(us)) goto end0; if (uwsgi_stats_keyvaln_comma(us, "name", s_node->name, s_node->len)) goto end0; if (uwsgi_stats_keylong_comma(us, "modifier1", (unsigned long long) s_node->modifier1)) goto end0; if (uwsgi_stats_keylong_comma(us, "modifier2", (unsigned long long) s_node->modifier2)) goto end0; if (uwsgi_stats_keylong_comma(us, "last_check", (unsigned long long) s_node->last_check)) goto end0; if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) s_node->pid)) goto end0; if (uwsgi_stats_keylong_comma(us, "uid", (unsigned long long) s_node->uid)) goto end0; if (uwsgi_stats_keylong_comma(us, "gid", (unsigned long long) s_node->gid)) goto end0; if (uwsgi_stats_keylong_comma(us, "requests", (unsigned long long) s_node->requests)) goto end0; if (uwsgi_stats_keylong_comma(us, "last_requests", (unsigned long long) s_node->last_requests)) goto end0; if (uwsgi_stats_keylong_comma(us, "tx", (unsigned long long) s_node->tx)) goto end0; if (uwsgi_stats_keylong_comma(us, "rx", (unsigned long long) s_node->rx)) goto end0; if (uwsgi_stats_keylong_comma(us, "cores", (unsigned long long) s_node->cores)) goto end0; if (uwsgi_stats_keylong_comma(us, "load", (unsigned long long) s_node->load)) goto end0; if (uwsgi_stats_keylong_comma(us, "weight", (unsigned long long) s_node->weight)) goto end0; if (uwsgi_stats_keylong_comma(us, "wrr", (unsigned long long) s_node->wrr)) goto end0; if (uwsgi_stats_keylong_comma(us, "ref", (unsigned long long) s_node->reference)) goto end0; if (uwsgi_stats_keylong_comma(us, "failcnt", (unsigned long long) s_node->failcnt)) goto end0; if (uwsgi_stats_keylong(us, "death_mark", (unsigned long long) s_node->death_mark)) goto end0; if (uwsgi_stats_object_close(us)) goto end0; if (s_node->next) { if (uwsgi_stats_comma(us)) goto end0; } s_node = s_node->next; } if (uwsgi_stats_list_close(us)) goto end0; if (uwsgi_stats_object_close(us)) goto end0; if (s_slot->next) { if (uwsgi_stats_comma(us)) goto end0; } s_slot = s_slot->next; // check for loopy optimization if (s_slot == ucr->subscriptions[i]) break; } } if (uwsgi_stats_list_close(us)) goto end0; if (uwsgi_stats_comma(us)) goto end0; } if (uwsgi_stats_keylong(us, "cheap", (unsigned long long) ucr->i_am_cheap)) goto end0; if (uwsgi_stats_object_close(us)) goto end0; size_t remains = us->pos; off_t pos = 0; while(remains > 0) { int ret = uwsgi_waitfd_write(client_fd, uwsgi.socket_timeout); if (ret <= 0) { goto end0; } ssize_t res = write(client_fd, us->base + pos, remains); if (res <= 0) { if (res < 0) { uwsgi_error("write()"); } goto end0; } pos += res; remains -= res; } end0: free(cwd); end: free(us->base); free(us); close(client_fd); } uwsgi-2.0.29/plugins/corerouter/cr.h000066400000000000000000000307771477626554400174330ustar00rootroot00000000000000#define COREROUTER_STATUS_FREE 0 #define COREROUTER_STATUS_CONNECTING 1 #define COREROUTER_STATUS_RECV_HDR 2 #define COREROUTER_STATUS_RESPONSE 3 #define cr_add_timeout(u, x) uwsgi_add_rb_timer(u->timeouts, uwsgi_now()+x->current_timeout, x) #define cr_add_timeout_fast(u, x, t) uwsgi_add_rb_timer(u->timeouts, t+x->current_timeout, x) #define cr_del_timeout(u, x) uwsgi_del_rb_timer(u->timeouts, x->timeout); free(x->timeout); #define uwsgi_cr_error(x, y) uwsgi_log("[uwsgi-%s key: %.*s client_addr: %s client_port: %s] %s: %s [%s line %d]\n", x->session->corerouter->short_name, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key_len: 0) : x->key_len, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key: "") : x->key, x->session->client_address, x->session->client_port, y, strerror(errno), __FILE__, __LINE__) #define uwsgi_cr_log(x, y, ...) uwsgi_log("[uwsgi-%s key: %.*s client_addr: %s client_port: %s]" y, x->session->corerouter->short_name, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key_len: 0) : x->key_len, (x == x->session->main_peer) ? (x->session->peers ? x->session->peers->key: "") : x->key, x->session->client_address, x->session->client_port, __VA_ARGS__) #define cr_try_again if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {\ errno = EINPROGRESS;\ return -1;\ } #define cr_write(peer, f) write(peer->fd, peer->out->buf + peer->out_pos, peer->out->pos - peer->out_pos);\ if (len < 0) {\ cr_try_again;\ uwsgi_cr_error(peer, f);\ return -1;\ }\ if (peer != peer->session->main_peer && peer->un) peer->un->rx+=len;\ peer->out_pos += len; #define cr_write_buf(peer, ubuf, f) write(peer->fd, ubuf->buf + ubuf##_pos, ubuf->pos - ubuf##_pos);\ if (len < 0) {\ cr_try_again;\ uwsgi_cr_error(peer, f);\ return -1;\ }\ if (peer != peer->session->main_peer && peer->un) peer->un->rx+=len;\ ubuf##_pos += len; #define cr_write_complete(peer) peer->out_pos == peer->out->pos #define cr_write_complete_buf(peer, buf) buf##_pos == buf->pos #define cr_connect(peer, f) peer->fd = uwsgi_connectn(peer->instance_address, peer->instance_address_len, 0, 1);\ if (peer->fd < 0) {\ peer->failed = 1;\ peer->soopt = errno;\ return -1;\ }\ peer->session->corerouter->cr_table[peer->fd] = peer;\ peer->connecting = 1;\ cr_write_to_backend(peer, f); #define cr_read(peer, f) read(peer->fd, peer->in->buf + peer->in->pos, peer->in->len - peer->in->pos);\ if (len < 0) {\ cr_try_again;\ uwsgi_cr_error(peer, f);\ return -1;\ }\ if (peer != peer->session->main_peer && peer->un) peer->un->tx+=len;\ peer->in->pos += len;\ #define cr_read_exact(peer, l, f) read(peer->fd, peer->in->buf + peer->in->pos, (l - peer->in->pos));\ if (len < 0) {\ cr_try_again;\ uwsgi_cr_error(peer, f);\ return -1;\ }\ if (peer != peer->session->main_peer && peer->un) peer->un->tx+=len;\ peer->in->pos += len;\ #define cr_reset_hooks(peer) if(!peer->session->main_peer->disabled) {\ if (uwsgi_cr_set_hooks(peer->session->main_peer, peer->session->main_peer->last_hook_read, NULL)) return -1;\ }\ else {\ if (uwsgi_cr_set_hooks(peer->session->main_peer, NULL, NULL)) return -1;\ }\ struct corerouter_peer *peers = peer->session->peers;\ while(peers) {\ if (uwsgi_cr_set_hooks(peers, peers->last_hook_read, NULL)) return -1;\ peers = peers->next;\ } #define cr_reset_hooks_and_read(peer, f) if (uwsgi_cr_set_hooks(peer->session->main_peer, peer->session->main_peer->last_hook_read, NULL)) return -1;\ peer->last_hook_read = f;\ struct corerouter_peer *peers = peer->session->peers;\ while(peers) {\ if (uwsgi_cr_set_hooks(peers, peers->last_hook_read, NULL)) return -1;\ peers = peers->next;\ } #define cr_write_to_main(peer, f) if (uwsgi_cr_set_hooks(peer->session->main_peer, NULL, f)) return -1;\ struct corerouter_peer *peers = peer->session->peers;\ while(peers) {\ if (uwsgi_cr_set_hooks(peers, NULL, NULL)) return -1;\ peers = peers->next;\ } #define cr_write_to_backend(peer, f) if (uwsgi_cr_set_hooks(peer->session->main_peer, NULL, NULL)) return -1;\ if (uwsgi_cr_set_hooks(peer, NULL, f)) return -1;\ struct corerouter_peer *peers = peer->session->peers;\ while(peers) {\ if (peers != peer) {\ if (uwsgi_cr_set_hooks(peers, NULL, NULL)) return -1;\ }\ peers = peers->next;\ } #define cr_peer_connected(peer, f) socklen_t solen = sizeof(int);\ if (getsockopt(peer->fd, SOL_SOCKET, SO_ERROR, (void *) (&peer->soopt), &solen) < 0) {\ uwsgi_cr_error(peer, f "/getsockopt()");\ peer->failed = 1;\ return -1;\ }\ if (peer->soopt) {\ peer->failed = 1;\ return -1;\ }\ peer->connecting = 0;\ peer->can_retry = 0;\ if (peer->static_node) peer->static_node->custom2++;\ if (peer->un) {\ peer->un->requests++;\ peer->un->last_requests++;\ }\ struct corerouter_session; // a peer is a connection to a socket (a client or a backend) and can be monitored for events. struct corerouter_peer { // the file descriptor int fd; // the session struct corerouter_session *session; // if set do not wait for events int disabled; // hook to run on a read event ssize_t (*hook_read)(struct corerouter_peer *); ssize_t (*last_hook_read)(struct corerouter_peer *); // hook to run on a write event ssize_t (*hook_write)(struct corerouter_peer *); ssize_t (*last_hook_write)(struct corerouter_peer *); // has the peer failed ? int failed; // is the peer connecting ? int connecting; // is there a connection error ? int soopt; // has the peer timed out ? int timed_out; // the timeout rb_tree struct uwsgi_rb_timer *timeout; // each peer can map to a different instance char *tmp_socket_name; char *instance_address; uint64_t instance_address_len; // backend info struct uwsgi_subscribe_node *un; struct uwsgi_string_list *static_node; // incoming data struct uwsgi_buffer *in; // data to send struct uwsgi_buffer *out; // amount of sent data (partial write management) size_t out_pos; int out_need_free; // stream id (could have various use) uint32_t sid; // internal parser status int r_parser_status; // can retry ? int can_retry; // how many retries ? uint16_t retries; // parsed key char key[0xff]; uint8_t key_len; uint8_t modifier1; uint8_t modifier2; struct corerouter_peer *prev; struct corerouter_peer *next; int current_timeout; ssize_t (*flush)(struct corerouter_peer *); int is_flushing; int is_buffering; int buffering_fd; }; struct uwsgi_corerouter { char *name; char *short_name; size_t session_size; int (*alloc_session)(struct uwsgi_corerouter *, struct uwsgi_gateway_socket *, struct corerouter_session *, struct sockaddr *, socklen_t); int (*mapper)(struct uwsgi_corerouter *, struct corerouter_peer *); int has_sockets; int has_backends; int has_subscription_sockets; int processes; int quiet; struct uwsgi_rbtree *timeouts; char *use_cache; struct uwsgi_cache *cache; int nevents; int max_retries; char *magic_table[256]; int queue; char *pattern; int pattern_len; char *base; int base_len; size_t post_buffering; char *pb_base_dir; struct uwsgi_string_list *static_nodes; struct uwsgi_string_list *current_static_node; int static_node_gracetime; char *stats_server; int cr_stats_server; int use_socket; int socket_num; struct uwsgi_socket *to_socket; struct uwsgi_subscribe_slot **subscriptions; struct uwsgi_string_list *fallback; int socket_timeout; uint8_t code_string_modifier1; char *code_string_code; char *code_string_function; struct uwsgi_rb_timer *subscriptions_check; int cheap; int i_am_cheap; int tolerance; int harakiri; struct corerouter_peer **cr_table; int interesting_fd; uint64_t active_sessions; uid_t uid; gid_t gid; struct uwsgi_string_list *resubscribe; char *resubscribe_bind; size_t buffer_size; int fallback_on_no_key; char *fallback_key; int fallback_key_len; }; // a session is started when a client connect to the router struct corerouter_session { // corerouter related to this session struct uwsgi_corerouter *corerouter; // gateway socket related to this session struct uwsgi_gateway_socket *ugs; // the list of fallback instances struct uwsgi_string_list *fallback; // store the client address struct sockaddr_un addr; socklen_t addr_len; void (*close)(struct corerouter_session *); int (*retry)(struct corerouter_peer *); // leave the main peer alive int can_keepalive; // destroy the main peer after the last full write int wait_full_write; // this is the peer of the client struct corerouter_peer *main_peer; // this is the linked list of backends struct corerouter_peer *peers; // connect after the next successfull write struct corerouter_peer *connect_peer_after_write; union uwsgi_sockaddr client_sockaddr; #ifdef AF_INET6 char client_address[INET6_ADDRSTRLEN]; #else char client_address[INET_ADDRSTRLEN]; #endif // use 11 bytes to be snprintf friendly char client_port[11]; }; void uwsgi_opt_corerouter(char *, char *, void *); void uwsgi_opt_undeferred_corerouter(char *, char *, void *); void uwsgi_opt_corerouter_use_socket(char *, char *, void *); void uwsgi_opt_corerouter_use_base(char *, char *, void *); void uwsgi_opt_corerouter_use_pattern(char *, char *, void *); void uwsgi_opt_corerouter_zerg(char *, char *, void *); void uwsgi_opt_corerouter_cs(char *, char *, void *); void uwsgi_opt_corerouter_ss(char *, char *, void *); void uwsgi_opt_corerouter_fallback_key(char *, char *, void *); void corerouter_manage_subscription(char *, uint16_t, char *, uint16_t, void *); void *uwsgi_corerouter_setup_event_queue(struct uwsgi_corerouter *, int); void uwsgi_corerouter_manage_subscription(struct uwsgi_corerouter *, int id, struct uwsgi_gateway_socket *); void uwsgi_corerouter_manage_internal_subscription(struct uwsgi_corerouter *, int); void uwsgi_corerouter_setup_sockets(struct uwsgi_corerouter *); int uwsgi_corerouter_init(struct uwsgi_corerouter *); struct corerouter_session *corerouter_alloc_session(struct uwsgi_corerouter *, struct uwsgi_gateway_socket *, int, struct sockaddr *, socklen_t); void corerouter_close_session(struct uwsgi_corerouter *, struct corerouter_session *); int uwsgi_cr_map_use_void(struct uwsgi_corerouter *, struct corerouter_peer *); int uwsgi_cr_map_use_cache(struct uwsgi_corerouter *, struct corerouter_peer *); int uwsgi_cr_map_use_pattern(struct uwsgi_corerouter *, struct corerouter_peer *); int uwsgi_cr_map_use_cluster(struct uwsgi_corerouter *, struct corerouter_peer *); int uwsgi_cr_map_use_subscription(struct uwsgi_corerouter *, struct corerouter_peer *); int uwsgi_cr_map_use_subscription_dotsplit(struct uwsgi_corerouter *, struct corerouter_peer *); int uwsgi_cr_map_use_base(struct uwsgi_corerouter *, struct corerouter_peer *); int uwsgi_cr_map_use_cs(struct uwsgi_corerouter *, struct corerouter_peer *); int uwsgi_cr_map_use_to(struct uwsgi_corerouter *, struct corerouter_peer *); int uwsgi_cr_map_use_static_nodes(struct uwsgi_corerouter *, struct corerouter_peer *); int uwsgi_corerouter_has_backends(struct uwsgi_corerouter *); int uwsgi_cr_set_hooks(struct corerouter_peer *, ssize_t (*)(struct corerouter_peer *), ssize_t (*)(struct corerouter_peer *)); struct corerouter_peer *uwsgi_cr_peer_add(struct corerouter_session *); struct corerouter_peer *uwsgi_cr_peer_find_by_sid(struct corerouter_session *, uint32_t); void corerouter_close_peer(struct uwsgi_corerouter *, struct corerouter_peer *); struct uwsgi_rb_timer *corerouter_reset_timeout(struct uwsgi_corerouter *, struct corerouter_peer *); uwsgi-2.0.29/plugins/corerouter/cr_common.c000066400000000000000000000202611477626554400207610ustar00rootroot00000000000000/* common functions for various routers (fastrouter, http...) */ #include extern struct uwsgi_server uwsgi; #include "cr.h" void uwsgi_corerouter_setup_sockets(struct uwsgi_corerouter *ucr) { struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets; while (ugs) { if (!strcmp(ucr->name, ugs->owner)) { if (!ugs->subscription) { if (ugs->name[0] == '=') { int shared_socket = atoi(ugs->name + 1); if (shared_socket >= 0) { ugs->fd = uwsgi_get_shared_socket_fd_by_num(shared_socket); ugs->shared = 1; if (ugs->fd == -1) { uwsgi_log("unable to use shared socket %d\n", shared_socket); exit(1); } ugs->name = uwsgi_getsockname(ugs->fd); } } else if (!uwsgi_startswith("fd://", ugs->name, 5)) { int fd_socket = atoi(ugs->name + 5); if (fd_socket >= 0) { ugs->fd = fd_socket; ugs->name = uwsgi_getsockname(ugs->fd); if (!ugs->name) { uwsgi_log("unable to use file descriptor %d as socket\n", fd_socket); exit(1); } } } else { ugs->port = strrchr(ugs->name, ':'); int current_defer_accept = uwsgi.no_defer_accept; if (ugs->no_defer) { uwsgi.no_defer_accept = 1; } if (ugs->fd == -1) { if (ugs->port) { ugs->fd = bind_to_tcp(ugs->name, uwsgi.listen_queue, ugs->port); ugs->port++; ugs->port_len = strlen(ugs->port); } else { ugs->fd = bind_to_unix(ugs->name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); } } if (ugs->no_defer) { uwsgi.no_defer_accept = current_defer_accept; } } // fix SERVER_PORT if (!ugs->port || !ugs->port_len) { ugs->port = strrchr(ugs->name, ':'); if (ugs->port) { ugs->port++; ugs->port_len = strlen(ugs->port); } } // put socket in non-blocking mode uwsgi_socket_nb(ugs->fd); uwsgi_log("%s bound on %s fd %d\n", ucr->name, ugs->name, ugs->fd); } else if (ugs->subscription) { if (ugs->fd == -1) { if (strchr(ugs->name, ':')) { ugs->fd = bind_to_udp(ugs->name, 0, 0); } else { ugs->fd = bind_to_unix_dgram(ugs->name); if (ugs->fd < 1 || (uwsgi.subscriptions_use_credentials && uwsgi_socket_passcred(ugs->fd))) { exit(1); } } uwsgi_socket_nb(ugs->fd); } uwsgi_log("%s subscription server bound on %s fd %d\n", ucr->name, ugs->name, ugs->fd); } } ugs = ugs->next; } } void *uwsgi_corerouter_setup_event_queue(struct uwsgi_corerouter *ucr, int id) { ucr->queue = event_queue_init(); struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets; while (ugs) { if (!strcmp(ucr->name, ugs->owner)) { if (!ucr->cheap || ugs->subscription) { event_queue_add_fd_read(ucr->queue, ugs->fd); } ugs->gateway = &ushared->gateways[id]; } ugs = ugs->next; } return event_queue_alloc(ucr->nevents); } void uwsgi_corerouter_manage_subscription(struct uwsgi_corerouter *ucr, int id, struct uwsgi_gateway_socket *ugs) { int i; struct uwsgi_subscribe_req usr; char bbuf[4096]; ssize_t len = -1; memset(&usr, 0, sizeof(struct uwsgi_subscribe_req)); if (uwsgi.subscriptions_use_credentials) { len = uwsgi_recv_cred2(ugs->fd, bbuf, 4096, &usr.pid, &usr.uid, &usr.gid); } else { len = recv(ugs->fd, bbuf, 4096, 0); } if (len > 0) { uwsgi_hooked_parse(bbuf + 4, len - 4, corerouter_manage_subscription, &usr); if (usr.sign_len > 0) { // calc the base size usr.base = bbuf + 4; usr.base_len = len - 4 - (2 + 4 + 2 + usr.sign_len); } // subscribe request ? if (bbuf[3] == 0) { if (uwsgi_add_subscribe_node(ucr->subscriptions, &usr) && ucr->i_am_cheap) { struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets; while (ugs) { if (!strcmp(ugs->owner, ucr->name) && !ugs->subscription) { event_queue_add_fd_read(ucr->queue, ugs->fd); } ugs = ugs->next; } ucr->i_am_cheap = 0; uwsgi_log("[%s pid %d] leaving cheap mode...\n", ucr->name, (int) uwsgi.mypid); } } //unsubscribe else { struct uwsgi_subscribe_node *node = uwsgi_get_subscribe_node_by_name(ucr->subscriptions, usr.key, usr.keylen, usr.address, usr.address_len); if (node && node->len) { #ifdef UWSGI_SSL if (uwsgi.subscriptions_sign_check_dir) { if (!uwsgi_subscription_sign_check(node->slot, &usr)) { return; } } #endif if (node->death_mark == 0) uwsgi_log("[%s pid %d] %.*s => marking %.*s as failed\n", ucr->name, (int) uwsgi.mypid, (int) usr.keylen, usr.key, (int) usr.address_len, usr.address); node->failcnt++; node->death_mark = 1; // check if i can remove the node if (node->reference == 0) { uwsgi_remove_subscribe_node(ucr->subscriptions, node); } if (ucr->cheap && !ucr->i_am_cheap && uwsgi_no_subscriptions(ucr->subscriptions)) { uwsgi_gateway_go_cheap(ucr->name, ucr->queue, &ucr->i_am_cheap); } } } // propagate the subscription to other nodes for (i = 0; i < ushared->gateways_cnt; i++) { if (i == id) continue; if (!strcmp(ushared->gateways[i].name, ucr->name)) { if (send(ushared->gateways[i].internal_subscription_pipe[0], bbuf, len, 0) != len) { uwsgi_error("uwsgi_corerouter_manage_subscription()/send()"); } } } // resubscribe if needed ? if (ucr->resubscribe) { static char *address = NULL; if (!address) { struct uwsgi_gateway_socket *augs = uwsgi.gateway_sockets; while (augs) { if (!strcmp(ucr->name, augs->owner)) { if (!augs->subscription) { address = augs->name; break; } } augs = augs->next; } } struct uwsgi_string_list *usl = NULL; char *sni_key = NULL; char *sni_cert = NULL; char *sni_ca = NULL; if (usr.sni_key_len) { sni_key = uwsgi_concat2n(usr.sni_key, usr.sni_key_len, "", 0); } if (usr.sni_crt_len) { sni_cert = uwsgi_concat2n(usr.sni_crt, usr.sni_crt_len, "", 0); } if (usr.sni_ca_len) { sni_ca = uwsgi_concat2n(usr.sni_ca, usr.sni_ca_len, "", 0); } uwsgi_foreach(usl, ucr->resubscribe) { if (ucr->resubscribe_bind) { static int rfd = -1; if (rfd == -1) { rfd = bind_to_udp(ucr->resubscribe_bind, 0, 0); } uwsgi_send_subscription_from_fd(rfd, usl->value, usr.key, usr.keylen, usr.modifier1, usr.modifier2, bbuf[3], address, NULL, sni_key, sni_cert, sni_ca); } else { uwsgi_send_subscription_from_fd(-2, usl->value, usr.key, usr.keylen, usr.modifier1, usr.modifier2, bbuf[3], address, NULL, sni_key, sni_cert, sni_ca); } } if (sni_key) free(sni_key); if (sni_cert) free(sni_cert); if (sni_ca) free(sni_ca); } } } void uwsgi_corerouter_manage_internal_subscription(struct uwsgi_corerouter *ucr, int fd) { struct uwsgi_subscribe_req usr; char bbuf[4096]; ssize_t len = recv(fd, bbuf, 4096, 0); if (len > 0) { memset(&usr, 0, sizeof(struct uwsgi_subscribe_req)); uwsgi_hooked_parse(bbuf + 4, len - 4, corerouter_manage_subscription, &usr); // subscribe request ? if (bbuf[3] == 0) { if (uwsgi_add_subscribe_node(ucr->subscriptions, &usr) && ucr->i_am_cheap) { struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets; while (ugs) { if (!strcmp(ugs->owner, ucr->name) && !ugs->subscription) { event_queue_add_fd_read(ucr->queue, ugs->fd); } ugs = ugs->next; } ucr->i_am_cheap = 0; uwsgi_log("[%s pid %d] leaving cheap mode...\n", ucr->name, (int) uwsgi.mypid); } } //unsubscribe else { struct uwsgi_subscribe_node *node = uwsgi_get_subscribe_node_by_name(ucr->subscriptions, usr.key, usr.keylen, usr.address, usr.address_len); if (node && node->len) { if (node->death_mark == 0) uwsgi_log("[%s pid %d] %.*s => marking %.*s as failed\n", ucr->name, (int) uwsgi.mypid, (int) usr.keylen, usr.key, (int) usr.address_len, usr.address); node->failcnt++; node->death_mark = 1; // check if i can remove the node if (node->reference == 0) { uwsgi_remove_subscribe_node(ucr->subscriptions, node); } if (ucr->cheap && !ucr->i_am_cheap && uwsgi_no_subscriptions(ucr->subscriptions)) { uwsgi_gateway_go_cheap(ucr->name, ucr->queue, &ucr->i_am_cheap); } } } } } uwsgi-2.0.29/plugins/corerouter/cr_map.c000066400000000000000000000137671477626554400202630ustar00rootroot00000000000000#include #include "cr.h" extern struct uwsgi_server uwsgi; int uwsgi_cr_map_use_void(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) { return 0; } int uwsgi_cr_map_use_cache(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) { uint64_t hits = 0; uwsgi_rlock(ucr->cache->lock); char *value = uwsgi_cache_get4(ucr->cache, peer->key, peer->key_len, &peer->instance_address_len, &hits); if (!value) goto end; peer->tmp_socket_name = uwsgi_concat2n(value, peer->instance_address_len, "", 0); size_t nodes = uwsgi_str_occurence(peer->tmp_socket_name, peer->instance_address_len, '|'); if (nodes > 0) { size_t choosen_node = hits % (nodes + 1); size_t choosen_node_len = 0; peer->instance_address = uwsgi_str_split_nget(peer->tmp_socket_name, peer->instance_address_len, '|', choosen_node, &choosen_node_len); if (!peer->instance_address) goto end; peer->instance_address_len = choosen_node_len; } else { peer->instance_address = peer->tmp_socket_name; } char *cs_mod = uwsgi_str_contains(peer->instance_address, peer->instance_address_len, ','); if (cs_mod) { peer->modifier1 = uwsgi_str_num(cs_mod + 1, (peer->instance_address_len - (cs_mod - peer->instance_address)) - 1); peer->instance_address_len = (cs_mod - peer->instance_address); } end: uwsgi_rwunlock(ucr->cache->lock); return 0; } int uwsgi_cr_map_use_pattern(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) { size_t tmp_socket_name_len = 0; ucr->magic_table['s'] = uwsgi_concat2n(peer->key, peer->key_len, "", 0); peer->tmp_socket_name = magic_sub(ucr->pattern, ucr->pattern_len, &tmp_socket_name_len, ucr->magic_table); free(ucr->magic_table['s']); peer->instance_address_len = tmp_socket_name_len; peer->instance_address = peer->tmp_socket_name; return 0; } int uwsgi_cr_map_use_subscription(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) { peer->un = uwsgi_get_subscribe_node(ucr->subscriptions, peer->key, peer->key_len); if((peer->un == NULL) && (ucr->fallback_key != NULL)) { peer->un = uwsgi_get_subscribe_node(ucr->subscriptions, ucr->fallback_key, ucr->fallback_key_len); } if (peer->un && peer->un->len) { peer->instance_address = peer->un->name; peer->instance_address_len = peer->un->len; peer->modifier1 = peer->un->modifier1; peer->modifier2 = peer->un->modifier2; } else if (ucr->cheap && !ucr->i_am_cheap && uwsgi_no_subscriptions(ucr->subscriptions)) { uwsgi_gateway_go_cheap(ucr->name, ucr->queue, &ucr->i_am_cheap); } return 0; } int uwsgi_cr_map_use_subscription_dotsplit(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) { char *name = peer->key; uint16_t name_len = peer->key_len; // max 5 split, reduce DOS attempts int count = 5; split: if (!count) return 0; #ifdef UWSGI_DEBUG uwsgi_log("trying with %.*s\n", name_len, name); #endif peer->un = uwsgi_get_subscribe_node(ucr->subscriptions, name, name_len); if (!peer->un) { char *next = memchr(name + 1, '.', name_len - 1); if (next) { name_len -= next - name; name = next; count--; goto split; } } if (peer->un && peer->un->len) { peer->instance_address = peer->un->name; peer->instance_address_len = peer->un->len; peer->modifier1 = peer->un->modifier1; peer->modifier2 = peer->un->modifier2; } else if (ucr->cheap && !ucr->i_am_cheap && uwsgi_no_subscriptions(ucr->subscriptions)) { uwsgi_gateway_go_cheap(ucr->name, ucr->queue, &ucr->i_am_cheap); } return 0; } int uwsgi_cr_map_use_base(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) { int tmp_socket_name_len = 0; peer->tmp_socket_name = uwsgi_concat2nn(ucr->base, ucr->base_len, peer->key, peer->key_len, &tmp_socket_name_len); peer->instance_address_len = tmp_socket_name_len; peer->instance_address = peer->tmp_socket_name; return 0; } int uwsgi_cr_map_use_cs(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) { if (uwsgi.p[ucr->code_string_modifier1]->code_string) { char *name = uwsgi_concat2("uwsgi_", ucr->short_name); peer->instance_address = uwsgi.p[ucr->code_string_modifier1]->code_string(name, ucr->code_string_code, ucr->code_string_function, peer->key, peer->key_len); free(name); if (peer->instance_address) { peer->instance_address_len = strlen(peer->instance_address); char *cs_mod = uwsgi_str_contains(peer->instance_address, peer->instance_address_len, ','); if (cs_mod) { peer->modifier1 = uwsgi_str_num(cs_mod + 1, (peer->instance_address_len - (cs_mod - peer->instance_address)) - 1); peer->instance_address_len = (cs_mod - peer->instance_address); } } } return 0; } int uwsgi_cr_map_use_to(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) { peer->instance_address = ucr->to_socket->name; peer->instance_address_len = ucr->to_socket->name_len; return 0; } int uwsgi_cr_map_use_static_nodes(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) { if (!ucr->current_static_node) { ucr->current_static_node = ucr->static_nodes; } peer->static_node = ucr->current_static_node; // is it a dead node ? if (peer->static_node->custom > 0) { // gracetime passed ? if (peer->static_node->custom + ucr->static_node_gracetime <= (uint64_t) uwsgi_now()) { peer->static_node->custom = 0; } else { struct uwsgi_string_list *tmp_node = peer->static_node; struct uwsgi_string_list *next_node = peer->static_node->next; peer->static_node = NULL; // needed for 1-node only setups if (!next_node) next_node = ucr->static_nodes; while (tmp_node != next_node) { if (!next_node) { next_node = ucr->static_nodes; } if (tmp_node == next_node) break; if (next_node->custom == 0) { peer->static_node = next_node; break; } next_node = next_node->next; } } } if (peer->static_node) { peer->instance_address = peer->static_node->value; peer->instance_address_len = peer->static_node->len; // set the next one ucr->current_static_node = peer->static_node->next; } else { // set the next one ucr->current_static_node = ucr->current_static_node->next; } return 0; } uwsgi-2.0.29/plugins/corerouter/uwsgiplugin.py000066400000000000000000000001501477626554400215630ustar00rootroot00000000000000 NAME='corerouter' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['cr_common', 'cr_map', 'corerouter'] uwsgi-2.0.29/plugins/coroae/000077500000000000000000000000001477626554400157175ustar00rootroot00000000000000uwsgi-2.0.29/plugins/coroae/coroae.c000066400000000000000000000323401477626554400173350ustar00rootroot00000000000000#include "../psgi/psgi.h" #include "CoroAPI.h" struct uwsgi_coroae { SV *condvar; AV *watchers; int destroy; }; extern struct uwsgi_server uwsgi; extern struct uwsgi_perl uperl; struct uwsgi_coroae ucoroae; MGVTBL uwsgi_coroae_vtbl = { 0, 0, 0, 0, 0 }; #define free_req_queue uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = wsgi_req static void uwsgi_opt_setup_coroae(char *opt, char *value, void *null) { // set async mode uwsgi_opt_set_int(opt, value, &uwsgi.async); if (uwsgi.socket_timeout < 30) { uwsgi.socket_timeout = 30; } // set loop engine uwsgi.loop = "coroae"; } static struct uwsgi_option coroae_options[] = { {"coroae", required_argument, 0, "a shortcut enabling Coro::AnyEvent loop engine with the specified number of async cores and optimal parameters", uwsgi_opt_setup_coroae, NULL, 0}, {0, 0, 0, 0, 0, 0, 0}, }; static struct wsgi_request *coroae_current_wsgi_req(void) { MAGIC *mg; SV *current = CORO_CURRENT; for (mg = SvMAGIC (current); mg; mg = mg->mg_moremagic) { if (mg->mg_type == PERL_MAGIC_ext + 1 && mg->mg_virtual == &uwsgi_coroae_vtbl) { return (struct wsgi_request *) mg->mg_ptr; } } uwsgi_log("[BUG] current_wsgi_req NOT FOUND !!!\n"); // TODO allow to survive api call error as in the python plugin exit(1); } // create a new coro SV * coroae_coro_new(CV *block) { SV *newobj = NULL; dSP; ENTER; SAVETMPS; PUSHMARK(SP); mXPUSHs(newSVpvs("Coro")); mXPUSHs(newRV_noinc((SV *)block)); PUTBACK; call_method("new", G_SCALAR|G_EVAL); SPAGAIN; if(SvTRUE(ERRSV)) { uwsgi_log("[uwsgi-perl error] %s", SvPV_nolen(ERRSV)); (void)POPs; // we must pop undef from the stack in G_SCALAR context } else { newobj = SvREFCNT_inc(POPs); } PUTBACK; FREETMPS; LEAVE; return newobj; } static int coroae_wait_milliseconds(int timeout) { char buf[256]; double d = ((double)timeout)/1000.0; int ret = snprintf(buf, 256, "Coro::AnyEvent::sleep %f", d); if (ret <= 0 || ret > 256) return -1; perl_eval_pv(buf, 0); return 0; } static int coroae_wait_fd_read(int fd, int timeout) { int ret = 0; dSP; ENTER; SAVETMPS; PUSHMARK(SP); mXPUSHs(newSViv(fd)); mXPUSHs(newSViv(timeout)); PUTBACK; call_pv("Coro::AnyEvent::readable", G_SCALAR|G_EVAL); SPAGAIN; if(SvTRUE(ERRSV)) { uwsgi_log("[uwsgi-perl error] %s", SvPV_nolen(ERRSV)); (void)POPs; // we must pop undef from the stack in G_SCALAR context } else { SV *p_ret = POPs; if (SvTRUE(p_ret)) { ret = 1; } } PUTBACK; FREETMPS; LEAVE; return ret; } static int coroae_wait_fd_write(int fd, int timeout) { int ret = 0; dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSViv(fd))); XPUSHs(sv_2mortal(newSViv(timeout))); PUTBACK; call_pv("Coro::AnyEvent::writable", G_SCALAR|G_EVAL); SPAGAIN; if(SvTRUE(ERRSV)) { uwsgi_log("[uwsgi-perl error] %s", SvPV_nolen(ERRSV)); (void)POPs; // we must pop undef from the stack in G_SCALAR context } else { SV *p_ret = POPs; if (SvTRUE(p_ret)) { ret = 1; } } FREETMPS; LEAVE; return ret; } // this runs in another Coro object XS(XS_coroae_accept_request) { dXSARGS; psgi_check_args(0); struct wsgi_request *wsgi_req = (struct wsgi_request *) XSANY.any_ptr; // if in edge-triggered mode read from socket now !!! if (wsgi_req->socket->edge_trigger) { int status = wsgi_req->socket->proto(wsgi_req); if (status < 0) { goto end; } goto request; } for(;;) { int ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.socket_timeout); wsgi_req->switches++; if (ret <= 0) { goto end; } int status = wsgi_req->socket->proto(wsgi_req); if (status < 0) { goto end; } else if (status == 0) { break; } } request: #ifdef UWSGI_ROUTING if (uwsgi_apply_routes(wsgi_req) == UWSGI_ROUTE_BREAK) { goto end; } #endif for(;;) { if (uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req) <= UWSGI_OK) { goto end; } wsgi_req->switches++; // switch after each yield CORO_CEDE; } end: uwsgi_close_request(wsgi_req); free_req_queue; XSRETURN(0); } XS(XS_coroae_sighandler) { int sigfd = (long) XSANY.any_ptr; uwsgi_receive_signal(sigfd, "worker", uwsgi.mywid); } XS(XS_coroae_acceptor) { dXSARGS; psgi_check_args(0); struct uwsgi_socket *uwsgi_sock = (struct uwsgi_socket *) XSANY.any_ptr; struct wsgi_request *wsgi_req = NULL; edge: wsgi_req = find_first_available_wsgi_req(); if (wsgi_req == NULL) { uwsgi_async_queue_is_full(uwsgi_now()); goto clear; } // fill wsgi_request structure wsgi_req_setup(wsgi_req, wsgi_req->async_id, uwsgi_sock ); // mark core as used uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 1; // accept the connection if (wsgi_req_simple_accept(wsgi_req, uwsgi_sock->fd)) { free_req_queue; if (uwsgi_sock->retry && uwsgi_sock->retry[wsgi_req->async_id]) { goto edge; } // in case of errors (or thundering herd, just rest it) uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 0; goto clear; } wsgi_req->start_of_request = uwsgi_micros(); wsgi_req->start_of_request_in_sec = wsgi_req->start_of_request/1000000; // enter harakiri mode if (uwsgi.harakiri_options.workers > 0) { set_harakiri(uwsgi.harakiri_options.workers); } // here we spawn an async {} block CV *async_xs_call = newXS(NULL, XS_coroae_accept_request, "uwsgi::coroae"); CvXSUBANY(async_xs_call).any_ptr = wsgi_req; SV *coro_req = coroae_coro_new(async_xs_call); sv_magicext(SvRV(coro_req), 0, PERL_MAGIC_ext + 1, &uwsgi_coroae_vtbl, (const char *)wsgi_req, 0); CORO_READY(coro_req); SvREFCNT_dec(coro_req); if (uwsgi_sock->edge_trigger) { #ifdef UWSGI_DEBUG uwsgi_log("i am an edge triggered socket !!!\n"); #endif goto edge; } clear: XSRETURN(0); } static CV *coroae_closure_acceptor(struct uwsgi_socket *uwsgi_sock) { CV *xsub = newXS(NULL, XS_coroae_acceptor, "uwsgi::coroae"); CvXSUBANY(xsub).any_ptr = uwsgi_sock; return xsub; } static CV *coroae_closure_sighandler(int sigfd) { CV *xsub = newXS(NULL, XS_coroae_sighandler, "uwsgi::coroae"); CvXSUBANY(xsub).any_ptr = (void *) sigfd; return xsub; } static SV *coroae_add_watcher(int fd, CV *cb) { SV *newobj; dSP; ENTER; SAVETMPS; PUSHMARK(SP); mXPUSHs(newSVpvs("AnyEvent")); mXPUSHs(newSVpvs("fh")); mXPUSHs(newSViv(fd)); mXPUSHs(newSVpvs("poll")); mXPUSHs(newSVpvs("r")); mXPUSHs(newSVpvs("cb")); mXPUSHs(newRV_noinc((SV *)cb)); PUTBACK; call_method( "io", G_SCALAR|G_EVAL); SPAGAIN; if(SvTRUE(ERRSV)) { // no need to continue... uwsgi_log("[uwsgi-perl error] %s", SvPV_nolen(ERRSV)); exit(1); } else { newobj = SvREFCNT_inc(POPs); } PUTBACK; FREETMPS; LEAVE; return newobj; } static SV *coroae_add_signal_watcher(const char *signame, CV *cb) { SV *newobj; dSP; ENTER; SAVETMPS; PUSHMARK(SP); mXPUSHs(newSVpvs("AnyEvent")); mXPUSHs(newSVpvs("signal")); mXPUSHs(newSVpv(signame, 0)); mXPUSHs(newSVpvs("cb")); mXPUSHs(newRV_noinc((SV *)cb)); PUTBACK; call_method("signal", G_SCALAR|G_EVAL); SPAGAIN; if(SvTRUE(ERRSV)) { // no need to continue... uwsgi_log("[uwsgi-perl error] %s", SvPV_nolen(ERRSV)); exit(1); } else { newobj = SvREFCNT_inc(POPs); } PUTBACK; FREETMPS; LEAVE; return newobj; } static SV *coroae_condvar_new() { SV *newobj; dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv( "AnyEvent", 8))); PUTBACK; call_method( "condvar", G_SCALAR|G_EVAL); SPAGAIN; if(SvTRUE(ERRSV)) { uwsgi_log("[uwsgi-perl error] %s", SvPV_nolen(ERRSV)); (void)POPs; // we must pop undef from the stack in G_SCALAR context newobj = NULL; } else { newobj = SvREFCNT_inc(POPs); } PUTBACK; FREETMPS; LEAVE; return newobj; } static void coroae_condvar_call(SV *cv, const char *method) { dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(cv); PUTBACK; call_method(method, G_DISCARD|G_EVAL); SPAGAIN; if(SvTRUE(ERRSV)) { uwsgi_log("[uwsgi-perl error] %s", SvPV_nolen(ERRSV)); } PUTBACK; FREETMPS; LEAVE; } XS(XS_coroae_graceful) { int i; int rounds; int running_cores; for (rounds = 0; ; rounds++) { running_cores = 0; for (i = 0; i < uwsgi.async; i++) { if (uwsgi.workers[uwsgi.mywid].cores[i].in_request) { struct wsgi_request *wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[i].req; if (!rounds) { uwsgi_log_verbose("worker %d (pid: %d) core %d is managing \"%.*s %.*s\" for %.*s\n", uwsgi.mywid, uwsgi.mypid, i, wsgi_req->method_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri, wsgi_req->remote_addr_len, wsgi_req->remote_addr); } running_cores++; } } if (running_cores == 0) { break; } uwsgi_log_verbose("waiting for %d running requests on worker %d (pid: %d)...\n", running_cores, uwsgi.mywid, uwsgi.mypid); coroae_wait_milliseconds(100); } coroae_condvar_call(ucoroae.condvar, "send"); } static void coroae_graceful(void) { uwsgi_log("Gracefully killing worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid); uwsgi.workers[uwsgi.mywid].manage_next_request = 0; SvREFCNT_dec(ucoroae.watchers); SV *coro_sv = coroae_coro_new(newXS(NULL, XS_coroae_graceful, "uwsgi::coroae")); CORO_READY(coro_sv); SvREFCNT_dec(coro_sv); } static void coroae_int(void) { uwsgi_log("Brutally killing worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid); uwsgi.workers[uwsgi.mywid].manage_next_request = 0; SvREFCNT_dec(ucoroae.watchers); coroae_condvar_call(ucoroae.condvar, "send"); } XS(XS_coroae_hup_sighandler) { coroae_graceful(); } XS(XS_coroae_int_sighandler) { coroae_int(); } static void coroae_gbcw(void) { if (ucoroae.destroy) return; ucoroae.destroy = 1; uwsgi_log("...The work of process %d is done. Seeya!\n", getpid()); uwsgi_time_bomb(uwsgi.worker_reload_mercy, 0); coroae_graceful(); } static void coroae_loop() { if (uwsgi.async < 2) { if (uwsgi.mywid == 1) { uwsgi_log("the Coro::AnyEvent loop engine requires async mode (--async )\n"); } exit(1); } if (!uperl.loaded) { uwsgi_log("no perl/PSGI code loaded (with --psgi), unable to initialize Coro::AnyEvent\n"); exit(1); } perl_eval_pv("use Coro;", 1); perl_eval_pv("use AnyEvent;", 1); perl_eval_pv("use Coro::AnyEvent;", 1); uwsgi.current_wsgi_req = coroae_current_wsgi_req; uwsgi.wait_write_hook = coroae_wait_fd_write; uwsgi.wait_read_hook = coroae_wait_fd_read; uwsgi.wait_milliseconds_hook = coroae_wait_milliseconds; I_CORO_API("uwsgi::coroae"); // patch goodbye_cruel_world uwsgi.gbcw_hook = coroae_gbcw; ucoroae.watchers = newAV(); av_push(ucoroae.watchers, coroae_add_signal_watcher("HUP", newXS(NULL, XS_coroae_hup_sighandler, "uwsgi::coroae"))); av_push(ucoroae.watchers, coroae_add_signal_watcher("INT", newXS(NULL, XS_coroae_int_sighandler, "uwsgi::coroae"))); av_push(ucoroae.watchers, coroae_add_signal_watcher("TERM", newXS(NULL, XS_coroae_int_sighandler, "uwsgi::coroae"))); // create signal watchers if (uwsgi.signal_socket > -1) { av_push(ucoroae.watchers, coroae_add_watcher(uwsgi.signal_socket, coroae_closure_sighandler(uwsgi.signal_socket))); av_push(ucoroae.watchers, coroae_add_watcher(uwsgi.my_signal_socket, coroae_closure_sighandler(uwsgi.my_signal_socket))); } struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while(uwsgi_sock) { // check return value here av_push(ucoroae.watchers, coroae_add_watcher(uwsgi_sock->fd, coroae_closure_acceptor(uwsgi_sock))); uwsgi_sock = uwsgi_sock->next; }; ucoroae.condvar = coroae_condvar_new(); coroae_condvar_call(ucoroae.condvar, "recv"); SvREFCNT_dec(ucoroae.condvar); if (uwsgi.workers[uwsgi.mywid].manage_next_request == 0) { uwsgi_log("goodbye to the Coro::AnyEvent loop on worker %d (pid: %d)\n", uwsgi.mywid, uwsgi.mypid); exit(UWSGI_RELOAD_CODE); } uwsgi_log("the Coro::AnyEvent loop is no more :(\n"); } static void coroae_init() { uwsgi_register_loop( (char *) "coroae", coroae_loop); } struct uwsgi_plugin coroae_plugin = { .name = "coroae", .options = coroae_options, .on_load = coroae_init, }; uwsgi-2.0.29/plugins/coroae/uwsgiplugin.py000066400000000000000000000011151477626554400206440ustar00rootroot00000000000000import os import sys coroapi = None search_paths = os.popen('perl -MConfig -e \'print $Config{sitearch}.",".join(",", @INC);\'').read().rstrip().split(',') for p in search_paths: if os.path.exists(p + '/Coro/CoroAPI.h'): coroapi = p if not coroapi: print("unable to find the Coro perl module !!!") sys.exit(1) NAME='coroae' CFLAGS = os.popen('perl -MExtUtils::Embed -e ccopts').read().rstrip().split() CFLAGS += ['-Wno-int-to-pointer-cast', '-Wno-error=format', '-Wno-error=int-to-pointer-cast', '-I%s/Coro' % coroapi] LDFLAGS = [] LIBS = [] GCC_LIST = ['coroae'] uwsgi-2.0.29/plugins/cplusplus/000077500000000000000000000000001477626554400165015ustar00rootroot00000000000000uwsgi-2.0.29/plugins/cplusplus/base.cc000066400000000000000000000025251477626554400177260ustar00rootroot00000000000000#include extern struct uwsgi_server uwsgi; class FakeClass { public: char *foobar; uint16_t foobar_len; void hello_world(struct wsgi_request *); }; void FakeClass::hello_world(struct wsgi_request *wsgi_req) { uwsgi_response_prepare_headers(wsgi_req, (char *)"200 OK", 6); uwsgi_response_add_content_type(wsgi_req, (char *)"text/html", 9); uwsgi_response_write_body_do(wsgi_req, foobar, foobar_len); } extern "C" int uwsgi_cplusplus_init(){ uwsgi_log("Initializing example c++ plugin\n"); return 0; } extern "C" int uwsgi_cplusplus_request(struct wsgi_request *wsgi_req) { FakeClass *fc; // empty request ? if (!wsgi_req->uh->pktsize) { uwsgi_log( "Invalid request. skip.\n"); goto clear; } // get uwsgi variables if (uwsgi_parse_vars(wsgi_req)) { uwsgi_log("Invalid request. skip.\n"); goto clear; } fc = new FakeClass(); // get PATH_INFO fc->foobar = uwsgi_get_var(wsgi_req, (char *) "PATH_INFO", 9, &fc->foobar_len); if (fc->foobar) { // send output fc->hello_world(wsgi_req); } delete fc; clear: return UWSGI_OK; } extern "C" void uwsgi_cplusplus_after_request(struct wsgi_request *wsgi_req) { // call log_request(wsgi_req) if you want a standard logline uwsgi_log("logging c++ request\n"); } uwsgi-2.0.29/plugins/cplusplus/plugin.c000066400000000000000000000006251477626554400201460ustar00rootroot00000000000000#include int uwsgi_cplusplus_init(void); int uwsgi_cplusplus_request(struct wsgi_request *); void uwsgi_cplusplus_after_request(struct wsgi_request *); struct uwsgi_plugin cplusplus_plugin = { .name = "cplusplus", .modifier1 = 250, .init = uwsgi_cplusplus_init, .request = uwsgi_cplusplus_request, .after_request = uwsgi_cplusplus_after_request, }; uwsgi-2.0.29/plugins/cplusplus/uwsgiplugin.py000066400000000000000000000001401477626554400214230ustar00rootroot00000000000000NAME='cplusplus' CFLAGS = [] LDFLAGS = [] LIBS = ['-lstdc++'] GCC_LIST = ['base.cc', 'plugin'] uwsgi-2.0.29/plugins/curl_cron/000077500000000000000000000000001477626554400164355ustar00rootroot00000000000000uwsgi-2.0.29/plugins/curl_cron/curl_cron.c000066400000000000000000000054561477626554400206010ustar00rootroot00000000000000#include #include extern struct uwsgi_server uwsgi; static void curl_cron_func(struct uwsgi_cron *uc, time_t now) { CURL *curl = curl_easy_init(); // ARGH !!! if (!curl) return; curl_easy_setopt(curl, CURLOPT_URL, uc->command); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, uwsgi.socket_timeout); // use 1 minute as the cron resolution curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60); uwsgi_log("[uwsgi-curl-cron] requesting %s\n", uc->command); CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { uwsgi_log("[uwsgi-curl-cron] curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } curl_easy_cleanup(curl); } static void uwsgi_opt_add_cron_curl(char *opt, char *value, void *foobar) { struct uwsgi_cron *uc = uwsgi_cron_add(value); uc->func = curl_cron_func; } #ifdef UWSGI_SSL static void uwsgi_opt_add_legion_cron_curl(char *opt, char *value, void *foobar) { char *space = strchr(value, ' '); if (!space) { uwsgi_log("invalid %s syntax, must be prefixed with a legion name\n", opt); exit(1); } char *legion = uwsgi_concat2n(value, space-value, "", 0); struct uwsgi_cron *uc = uwsgi_cron_add(space+1); uc->legion = legion; uc->func = curl_cron_func; } #endif static struct uwsgi_option curl_cron_options[] = { {"curl-cron", required_argument, 0, "add a cron task invoking the specified url via CURL", uwsgi_opt_add_cron_curl, NULL, UWSGI_OPT_MASTER}, {"cron-curl", required_argument, 0, "add a cron task invoking the specified url via CURL", uwsgi_opt_add_cron_curl, NULL, UWSGI_OPT_MASTER}, #ifdef UWSGI_SSL {"legion-curl-cron", required_argument, 0, "add a cron task invoking the specified url via CURL runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_legion_cron_curl, NULL, UWSGI_OPT_MASTER}, {"legion-cron-curl", required_argument, 0, "add a cron task invoking the specified url via CURL runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_legion_cron_curl, NULL, UWSGI_OPT_MASTER}, {"curl-cron-legion", required_argument, 0, "add a cron task invoking the specified url via CURL runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_legion_cron_curl, NULL, UWSGI_OPT_MASTER}, {"cron-curl-legion", required_argument, 0, "add a cron task invoking the specified url via CURL runnable only when the instance is a lord of the specified legion", uwsgi_opt_add_legion_cron_curl, NULL, UWSGI_OPT_MASTER}, #endif { 0, 0, 0, 0, 0, 0, 0}, }; struct uwsgi_plugin curl_cron_plugin = { .name = "curl_cron", .options = curl_cron_options, }; uwsgi-2.0.29/plugins/curl_cron/uwsgiplugin.py000066400000000000000000000001261477626554400213630ustar00rootroot00000000000000NAME='curl_cron' CFLAGS = [] LDFLAGS = [] LIBS = ['-lcurl'] GCC_LIST = ['curl_cron'] uwsgi-2.0.29/plugins/dumbloop/000077500000000000000000000000001477626554400162705ustar00rootroot00000000000000uwsgi-2.0.29/plugins/dumbloop/dumb.c000066400000000000000000000043421477626554400173660ustar00rootroot00000000000000#include "../../uwsgi.h" extern struct uwsgi_server uwsgi; // global variables for configuration static uint8_t dumbloop_modifier1 = 0; static char *dumbloop_code = ""; static char *dumbloop_function = "dumbloop"; struct uwsgi_option dumbloop_options[] = { {"dumbloop-modifier1", required_argument, 0, "set the modifier1 for the code_string", uwsgi_opt_set_int, &dumbloop_modifier1, 0}, {"dumbloop-code", required_argument, 0, "set the script to load for the code_string", uwsgi_opt_set_str, &dumbloop_code, 0}, {"dumbloop-function", required_argument, 0, "set the function to run for the code_string", uwsgi_opt_set_str, &dumbloop_function, 0}, {0, 0, 0, 0, 0, 0, 0}, }; // this function is executed for each thread static void *dumb_loop_run(void *arg1) { // get the core id (pthreads take a void pointer as argument, so we need this ugly trick) long core_id = (long) arg1; // complete threads setup (this is required for fixing things like UNIX signal handling) if (uwsgi.threads > 1) { // wsgi_request mapped to the core struct wsgi_request *wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[core_id].req; // fix it uwsgi_setup_thread_req(core_id, wsgi_req); } // this strign will be passed to the code_string function char *str_core = uwsgi_num2str(core_id); // ok we are ready, let's run custom code while (uwsgi.workers[uwsgi.mywid].manage_next_request) { if (uwsgi.p[dumbloop_modifier1]->code_string) { // "uwsgi_dumbloop" is the name of the module (will be used while importing the file, if needed) uwsgi.p[dumbloop_modifier1]->code_string("uwsgi_dumbloop", dumbloop_code, dumbloop_function, str_core, strlen(str_core)); } else { uwsgi_log("the requested plugin does not support code_string hook\n"); exit(1); } } return NULL; } static void dumb_loop() { // this run the dumb_loop_run in each thread (core) uwsgi_loop_cores_run(dumb_loop_run); } // register the new loop engine static void dumbloop_register() { uwsgi_register_loop( (char *) "dumb", dumb_loop); } struct uwsgi_plugin dumbloop_plugin = { .name = "dumbloop", .on_load = dumbloop_register, .options = dumbloop_options, }; uwsgi-2.0.29/plugins/dumbloop/uwsgiplugin.py000066400000000000000000000001101477626554400212070ustar00rootroot00000000000000NAME='dumbloop' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['dumb'] uwsgi-2.0.29/plugins/dummy/000077500000000000000000000000001477626554400156025ustar00rootroot00000000000000uwsgi-2.0.29/plugins/dummy/dummy.c000066400000000000000000000003761477626554400171070ustar00rootroot00000000000000#include static int dummy_request(struct wsgi_request *wsgi_req) { if (uwsgi_parse_vars(wsgi_req)) { return -1; } return UWSGI_OK; } struct uwsgi_plugin dummy_plugin = { .name = "dummy", .modifier1 = 0, .request = dummy_request, }; uwsgi-2.0.29/plugins/dummy/uwsgiplugin.py000066400000000000000000000001071477626554400205270ustar00rootroot00000000000000 NAME='dummy' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['dummy'] uwsgi-2.0.29/plugins/echo/000077500000000000000000000000001477626554400153655ustar00rootroot00000000000000uwsgi-2.0.29/plugins/echo/echo_plugin.c000066400000000000000000000005011477626554400200210ustar00rootroot00000000000000#include extern struct uwsgi_server uwsgi; static int uwsgi_echo_request(struct wsgi_request *wsgi_req) { return uwsgi_response_write_body_do(wsgi_req, wsgi_req->buffer, wsgi_req->uh->pktsize); } struct uwsgi_plugin echo_plugin = { .name = "echo", .modifier1 = 101, .request = uwsgi_echo_request, }; uwsgi-2.0.29/plugins/echo/uwsgiplugin.py000066400000000000000000000001131477626554400203070ustar00rootroot00000000000000NAME='echo' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['echo_plugin'] uwsgi-2.0.29/plugins/emperor_amqp/000077500000000000000000000000001477626554400171365ustar00rootroot00000000000000uwsgi-2.0.29/plugins/emperor_amqp/amqp.c000066400000000000000000000413701477626554400202450ustar00rootroot00000000000000#include "../../uwsgi.h" #define AMQP_CONNECTION_HEADER "AMQP\0\0\x09\x01" #define amqp_send(a, b, c) if (send(a, b, c, 0) < 0) { uwsgi_error("send()"); return -1; } struct amqp_frame_header { char type; uint16_t channel; uint32_t size; } __attribute__((__packed__)); struct amqp_frame_method { uint16_t class_id; uint16_t method_id; } __attribute__((__packed__)); static char *amqp_simple_get_frame(int, struct amqp_frame_header *); static char *amqp_get_method(int, uint16_t, uint16_t, uint32_t *); static char *amqp_get_str(char *ptr, char *watermark) { uint8_t str_size; // over engeneering... if (ptr+1 > watermark) return NULL; str_size = *ptr; if (ptr+1+str_size > watermark) return NULL; return ptr+1+str_size; } static char *amqp_get_short(char *ptr, char *watermark, uint16_t *sv) { uint16_t tmp_short; if (ptr+2 > watermark) return NULL; memcpy(&tmp_short, ptr, 2); *sv = ntohs(tmp_short); return ptr+2; } static char *amqp_get_long(char *ptr, char *watermark, uint32_t *lv) { uint32_t tmp_long; if (ptr+4 > watermark) return NULL; memcpy(&tmp_long, ptr, 4); *lv = ntohl(tmp_long); return ptr+4; } static char *amqp_get_longlong(char *ptr, char *watermark, uint64_t *llv) { if (ptr+8 > watermark) return NULL; *llv = uwsgi_be64(ptr); return ptr+8; } static int amqp_send_ack(int fd, uint64_t delivery_tag) { uint32_t size = 4 + 8 + 1; struct uwsgi_buffer *ub = uwsgi_buffer_new(64); // send type and channel if (uwsgi_buffer_append(ub, "\1\0\1", 3)) goto end; // send size if (uwsgi_buffer_u32be(ub, size)) goto end; // send class 60 method 80 if (uwsgi_buffer_append(ub, "\x00\x3C\x00\x50", 4)) goto end; // set delivery_tag if (uwsgi_buffer_u64be(ub, delivery_tag)) goto end; if (uwsgi_buffer_append(ub, "\0\xCE", 2)) goto end; // send buffer to socket if (write(fd, ub->buf, ub->pos) < 0) { uwsgi_error("amqp_send_ack()/write()"); goto end; } uwsgi_buffer_destroy(ub); return 0; end: uwsgi_buffer_destroy(ub); return -1; } char *uwsgi_amqp_consume(int fd, uint64_t *msgsize, char **routing_key) { uint32_t size; struct amqp_frame_header fh; uint64_t delivery_tag; uint64_t current_size = 0; char *ptr; char *watermark; uint16_t sv; char *frame = amqp_get_method(fd, 60, 60, &size); if (!frame) return NULL; ptr = frame+4; watermark = frame+size; // consumer_tag ptr = amqp_get_str(ptr, watermark); if (!ptr) goto clear; // delivery_tag (needed for ack) ptr = amqp_get_longlong(ptr, watermark, &delivery_tag); if (!ptr) goto clear; // redelivered if (ptr+1 > watermark) goto clear; ptr++; // exchange ptr = amqp_get_str(ptr, watermark); if (!ptr) goto clear; // routing_key if (ptr+1 > watermark) goto clear; uint8_t rk_size = (uint8_t) *ptr; ptr++; if (ptr+rk_size > watermark) goto clear; if (rk_size > 0) { char *rkey = uwsgi_concat2n(ptr, rk_size, "", 0); ptr+=rk_size; *routing_key = rkey; } else { *routing_key = NULL; } char *header = amqp_simple_get_frame(fd, &fh); if (!header) goto clear; if (fh.type != 2) goto clear2; ptr = header; watermark = ptr+fh.size; // header class_id ptr = amqp_get_short(ptr, watermark, &sv); if (!ptr) goto clear2; // header weight ptr = amqp_get_short(ptr, watermark, &sv); if (!ptr) goto clear2; // message size; ptr = amqp_get_longlong(ptr, watermark, msgsize); if (!ptr) goto clear2; free(frame); frame = NULL; free(header); header = NULL; char *fullbody = uwsgi_malloc(*msgsize); char *message; while(current_size < *msgsize) { message = amqp_simple_get_frame(fd, &fh); if (!message) goto clear; if (fh.type != 3) { free(message); goto clear3; } if (fh.size+current_size > *msgsize) { free(message); goto clear3; } memcpy(fullbody+current_size, message, fh.size); current_size+=fh.size; free(message); } if (amqp_send_ack(fd, delivery_tag) < 0) { goto clear3; } return fullbody; clear3: free(fullbody); return NULL; clear2: free(header); clear: free(frame); return NULL; } static int amqp_send_exchange_declare( int fd, char *exchange, char *exchange_type) { uint32_t size = 4 + 2 + (1 +strlen(exchange)) + (1 +strlen(exchange_type)) + 1 + 4; uint8_t shortsize = strlen(exchange) ; size = htonl(size); // send type and channel amqp_send(fd, "\1\0\1", 3); // send size amqp_send(fd, &size, 4); // send class 40 method 10 amqp_send(fd, "\x00\x28\x00\x0A", 4); // send empty reserved amqp_send(fd, "\0\0", 2); // set exchange name amqp_send(fd, &shortsize, 1); amqp_send(fd, exchange, shortsize); // set exchange type shortsize = strlen(exchange_type); amqp_send(fd, &shortsize, 1); amqp_send(fd, exchange_type, shortsize); // empty bits amqp_send(fd, "\0", 1); // empty table amqp_send(fd, "\0\0\0\0", 4); // send frame-end amqp_send(fd, "\xCE", 1); return 0; } static int amqp_send_queue_bind( int fd, char *queue, char *exchange) { uint32_t size = 4 + 2 + (1 +strlen(queue)) + (1 +strlen(exchange)) + 1 + 1 + 4; uint8_t shortsize = strlen(queue) ; size = htonl(size); // send type and channel amqp_send(fd, "\1\0\1", 3); // send size amqp_send(fd, &size, 4); // send class 50 method 20 amqp_send(fd, "\x00\x32\x00\x14", 4); // send empty reserved amqp_send(fd, "\0\0", 2); // set queue name amqp_send(fd, &shortsize, 1); amqp_send(fd, queue, shortsize); // set exchange name shortsize = strlen(exchange); amqp_send(fd, &shortsize, 1); amqp_send(fd, exchange, shortsize); // set empty routing-key amqp_send(fd, "\0", 1); // empty bits amqp_send(fd, "\0", 1); // empty table amqp_send(fd, "\0\0\0\0", 4); // send frame-end amqp_send(fd, "\xCE", 1); return 0; } static int amqp_send_queue_consume( int fd, char *queue) { uint32_t size = 4 + 2 + (1 +strlen(queue)) + 1 + 1 + 4; uint8_t shortsize = strlen(queue) ; size = htonl(size); // send type and channel amqp_send(fd, "\1\0\1", 3); // send size amqp_send(fd, &size, 4); // send class 60 method 20 amqp_send(fd, "\x00\x3C\x00\x14", 4); // send empty reserved amqp_send(fd, "\0\0", 2); // set queue name amqp_send(fd, &shortsize, 1); amqp_send(fd, queue, shortsize); // set tag name amqp_send(fd, "\0", 1); // empty bits amqp_send(fd, "\0", 1); // empty table amqp_send(fd, "\0\0\0\0", 4); // send frame-end amqp_send(fd, "\xCE", 1); return 0; } static int amqp_wait_connection_start(int fd) { uint32_t size; char *frame = amqp_get_method(fd, 10, 10, &size); if (frame) { free(frame); return 0; } return -1; } static int amqp_wait_exchange_declare_ok(int fd) { uint32_t size; char *frame = amqp_get_method(fd, 40, 11, &size); if (frame) { free(frame); return 0; } return -1; } static int amqp_wait_basic_consume_ok(int fd) { uint32_t size; char *frame = amqp_get_method(fd, 60, 21, &size); if (frame) { free(frame); return 0; } return -1; } static int amqp_wait_channel_open_ok(int fd) { uint32_t size; char *frame = amqp_get_method(fd, 20, 11, &size); if (frame) { free(frame); return 0; } return -1; } static int amqp_wait_queue_bind_ok(int fd) { uint32_t size; char *frame = amqp_get_method(fd, 50, 21, &size); if (frame) { free(frame); return 0; } return -1; } static char *amqp_wait_queue_declare_ok(int fd) { uint32_t size; char *frame = amqp_get_method(fd, 50, 11, &size); char *queue = NULL; char *ptr; char *watermark; if (frame) { ptr = frame+4; watermark = frame+size; ptr = amqp_get_str(ptr, watermark); if (!ptr) { free(frame); return NULL; } queue = uwsgi_concat2n(frame+5, *(frame+4), "", 0); free(frame); return queue; } return NULL; } static int amqp_wait_connection_open_ok(int fd) { uint32_t size; char *frame = amqp_get_method(fd, 10, 41, &size); if (frame) { free(frame); return 0; } return -1; } static int amqp_wait_connection_tune(int fd) { uint32_t size; char *frame = amqp_get_method(fd, 10, 30, &size); uint16_t sv; uint32_t lv; char *watermark ; char *ptr; if (frame) { ptr = frame+4; watermark = frame+size; ptr = amqp_get_short(ptr, watermark, &sv); if (!ptr) { free(frame); return -1; } uwsgi_log("AMQP max channels: %d\n", sv); ptr = amqp_get_long(ptr, watermark, &lv); if (!ptr) { free(frame); return -1; } uwsgi_log("AMQP max frame size: %d\n", lv); ptr = amqp_get_short(ptr, watermark, &sv); if (!ptr) { free(frame); return -1; } uwsgi_log("AMQP heartbeath: %d\n", sv); free(frame); return 0; } return -1; } static char *amqp_simple_get_frame(int fd, struct amqp_frame_header *fh) { char *ptr = (char *) fh; size_t len = 0; ssize_t rlen; while(len < 7) { rlen = recv(fd, ptr, 7-len, 0); if (rlen <= 0) { if (rlen < 0) uwsgi_error("recv()"); return NULL; } len += rlen; ptr += rlen; } fh->channel = ntohs(fh->channel); fh->size = ntohl(fh->size); len = 0; char *frame = uwsgi_malloc(fh->size+1); ptr = frame; while(len < fh->size+1) { rlen = recv(fd, ptr, (fh->size+1)-len, 0); if (rlen <= 0) { if (rlen < 0) uwsgi_error("recv()"); return NULL; } len += rlen; ptr += rlen; } return frame; } static char *amqp_get_method(int fd, uint16_t class_id, uint16_t method_id, uint32_t *size) { struct amqp_frame_header fh; struct amqp_frame_method *fm; char *frame = amqp_simple_get_frame(fd, &fh); if (!frame) return NULL; if (fh.type != 1) goto clear; fm = (struct amqp_frame_method *) frame; fm->class_id = ntohs(fm->class_id); fm->method_id = ntohs(fm->method_id); if (fm->class_id != class_id) goto clear; if (fm->method_id != method_id) goto clear; *size = fh.size; return frame; clear: free(frame); return NULL; } static int amqp_send_channel_open(int fd, uint16_t id) { uint32_t size = 4 + 1; size = htonl(size); // send type and channel amqp_send(fd, "\1\0\1", 3); // send size amqp_send(fd, &size, 4); // send class 20 method 10 amqp_send(fd, "\x00\x14\x00\x0A", 4); amqp_send(fd, "\0", 1); // send frame-end amqp_send(fd, "\xCE", 1); return 0; } int amqp_send_connection_open(int fd, char *vhost) { uint8_t shortsize = strlen(vhost); uint32_t size = 4 + 1 +strlen(vhost) + 2; size = htonl(size); // send type and channel amqp_send(fd, "\1\0\0", 3); // send size amqp_send(fd, &size, 4); // send class 10 method 28 amqp_send(fd, "\x00\x0A\x00\x28", 4); amqp_send(fd, &shortsize, 1); amqp_send(fd, vhost, strlen(vhost)); shortsize = 0; amqp_send(fd, &shortsize, 1); amqp_send(fd, &shortsize, 1); // send frame-end amqp_send(fd, "\xCE", 1); return 0; } int amqp_send_connection_tune_ok(int fd, uint16_t max_chan, uint32_t max_frame_size, uint16_t heartbeat) { uint32_t size = 4 + 2 + 4 + 2; size = htonl(size); max_chan = htons(max_chan); max_frame_size = htonl(max_frame_size); heartbeat = htons(heartbeat); // send type and channel amqp_send(fd, "\1\0\0", 3); // send size amqp_send(fd, &size, 4); // send class 10 method 15 amqp_send(fd, "\x00\x0A\x00\x1F", 4); amqp_send(fd, &max_chan, 2); amqp_send(fd, &max_frame_size, 4); amqp_send(fd, &heartbeat, 2); // send frame-end amqp_send(fd, "\xCE", 1); return 0; } static int amqp_send_queue_declare(int fd, char *queue) { uint32_t size = 4 + 2 + (1 +strlen(queue)) + 1 + 4; uint8_t shortsize = strlen(queue) ; size = htonl(size); // send type and channel amqp_send(fd, "\1\0\1", 3); // send size amqp_send(fd, &size, 4); // send class 50 method 10 amqp_send(fd, "\x00\x32\x00\x0A", 4); // send empty reserved amqp_send(fd, "\0\0", 2); // set queue name amqp_send(fd, &shortsize, 1); amqp_send(fd, queue, shortsize); // set auto-delete bit amqp_send(fd, "\x08", 1); // empty table amqp_send(fd, "\0\0\0\0", 4); // send frame-end amqp_send(fd, "\xCE", 1); return 0; } static char *amqp_get_queue(int fd, char *queue) { if (amqp_send_queue_declare(fd, queue) < 0) { return NULL; } return amqp_wait_queue_declare_ok(fd); } static int amqp_send_connection_start_ok(int fd, char *mech, char *sasl_response, int sasl_response_size, char *locale) { uint32_t size = 4 + 4 + (1 +strlen(mech)) + (4 + sasl_response_size) + (1 + strlen(locale)); uint8_t shortsize ; size = htonl(size); // send type and channel amqp_send(fd, "\1\0\0", 3); // send size amqp_send(fd, &size, 4); // send class 10 method 11 amqp_send(fd, "\x00\x0A\x00\x0B", 4); // send empty client properties amqp_send(fd, "\0\0\0\0", 4); // send mechanism short string shortsize = strlen(mech); amqp_send(fd, &shortsize, 1); amqp_send(fd, mech, strlen(mech)); // send sasl response size = htonl(sasl_response_size); amqp_send(fd, &size, 4); amqp_send(fd, sasl_response, sasl_response_size); // send locale shortsize = strlen(locale); amqp_send(fd, &shortsize, 1); amqp_send(fd, locale, strlen(locale)); // send frame-end amqp_send(fd, "\xCE", 1); return 0; } int uwsgi_amqp_consume_queue(int fd, char *vhost, char *username, char *password, char *queue, char *exchange, char *exchange_type) { char *auth = uwsgi_concat4n("\0",1, username, strlen(username), "\0",1, password, strlen(password)); if (send(fd, AMQP_CONNECTION_HEADER, 8, 0) < 0) { uwsgi_error("send()"); return -1; } if (amqp_wait_connection_start(fd) < 0) { uwsgi_log("AMQP error waiting for Connection.start\n"); return -1; } uwsgi_log("sending Connection.start-ok\n"); if (amqp_send_connection_start_ok(fd, "PLAIN", auth, strlen(username)+strlen(password)+2, "en_US") < 0) { free(auth); uwsgi_log("AMQP error sending Connection.start-ok\n"); return -1; } free(auth); if (amqp_wait_connection_tune(fd) < 0) { uwsgi_log("AMQP error waiting for Connection.tune\n"); return -1; } uwsgi_log("sending Connection.tune-ok\n"); if (amqp_send_connection_tune_ok(fd, 0, 0xffff, 0) < 0) { uwsgi_log("AMQP error sending Connection.tune-ok\n"); return -1; } uwsgi_log("sending Connection.open\n"); if (amqp_send_connection_open(fd, vhost) < 0) { uwsgi_log("AMQP error sending Connection.open\n"); return -1; } if (amqp_wait_connection_open_ok(fd) < 0) { uwsgi_log("AMQP error waiting for Connection.open-ok\n"); return -1; } uwsgi_log("sending Channel.open\n"); if (amqp_send_channel_open(fd, 1) < 0) { uwsgi_log("AMQP error sending Channel.open\n"); return -1; } if (amqp_wait_channel_open_ok(fd) < 0) { uwsgi_log("AMQP error waiting for Channel.open-ok\n"); return -1; } queue = amqp_get_queue(fd, queue); if (!queue) { uwsgi_log("AMQP error sending Queue.declare\n"); return -1; } if (exchange) { if (amqp_send_exchange_declare(fd, exchange, exchange_type) < 0) { uwsgi_log("AMQP error sending Exchange.declare\n"); free(queue); return -1; } if (amqp_wait_exchange_declare_ok(fd) < 0) { uwsgi_log("AMQP error waiting for Exchange.declare-ok\n"); free(queue); return -1; } if (amqp_send_queue_bind(fd, queue, exchange) < 0) { uwsgi_log("AMQP error sending Queue.bind\n"); free(queue); return -1; } if (amqp_wait_queue_bind_ok(fd) < 0) { uwsgi_log("AMQP error waiting for Queue.bind-ok\n"); free(queue); return -1; } } if (amqp_send_queue_consume(fd, queue) < 0) { uwsgi_log("AMQP error sending Basic.consume\n"); free(queue); return -1; } if (amqp_wait_basic_consume_ok(fd) < 0) { uwsgi_log("AMQP error waiting for Basic.consume-ok\n"); free(queue); return -1; } free(queue); uwsgi_log("AMQP subscription done, waiting for events...\n"); return 0; } uwsgi-2.0.29/plugins/emperor_amqp/emperor_amqp.c000066400000000000000000000062471477626554400220020ustar00rootroot00000000000000/* Emperor AMQP monitor syntax: amqp://[username:password@]host[/vhost] */ #include "../../uwsgi.h" extern struct uwsgi_server uwsgi; void uwsgi_imperial_monitor_amqp_init(struct uwsgi_emperor_scanner *); void uwsgi_imperial_monitor_amqp_event(struct uwsgi_emperor_scanner *ues) { uint64_t msgsize; char *amqp_routing_key = NULL; struct uwsgi_instance *ui_current; struct stat st; char *config = uwsgi_amqp_consume(ues->fd, &msgsize, &amqp_routing_key); if (!config) { uwsgi_log("problem with RabbitMQ server, trying reconnection...\n"); close(ues->fd); ues->fd = -1; return; } // having a routing key means the body will be mapped to a config chunk if (amqp_routing_key) { uwsgi_log("AMQP routing_key = %s\n", amqp_routing_key); ui_current = emperor_get(amqp_routing_key); if (ui_current) { // make a new config free(ui_current->config); ui_current->config = config; ui_current->config_len = msgsize; if (!msgsize) { emperor_stop(ui_current); } else { emperor_respawn(ui_current, uwsgi_now()); } goto end0; } if (msgsize > 0) { emperor_add(ues, amqp_routing_key, uwsgi_now(), config, msgsize, 0, 0, NULL); } end0: free(config); free(amqp_routing_key); return; } // no routing key means the body contains a path to a config file if (msgsize >= 0xff || !msgsize) goto end; char *config_file = uwsgi_concat2n(config, msgsize, "", 0); ui_current = emperor_get(config_file); // if non-http check for file existance if (strncmp(config_file, "http://", 7)) { if (stat(config_file, &st)) { free(config_file); if (ui_current) emperor_stop(ui_current); goto end; } if (!S_ISREG(st.st_mode)) { free(config_file); if (ui_current) emperor_stop(ui_current); goto end; } } if (ui_current) { emperor_respawn(ui_current, uwsgi_now()); } else { emperor_add(ues, config_file, uwsgi_now(), NULL, 0, 0, 0, NULL); } free(config_file); end: free(config); } void uwsgi_imperial_monitor_amqp_init(struct uwsgi_emperor_scanner *ues) { char *vhost = "/"; char *username = "guest"; char *password = "guest"; ues->fd = uwsgi_connect(ues->arg+7, -1, 0); if (ues->fd < 0) { uwsgi_log("unable to connect to AMQP server\n"); return; } if (uwsgi_amqp_consume_queue(ues->fd, vhost, username, password, "", "uwsgi.emperor", "fanout") < 0) { close(ues->fd); ues->fd = -1; uwsgi_log("unable to subscribe to AMQP queue\n"); return; } ues->event_func = uwsgi_imperial_monitor_amqp_event; event_queue_add_fd_read(uwsgi.emperor_queue, ues->fd); } void uwsgi_imperial_monitor_amqp(struct uwsgi_emperor_scanner *ues) { // try a reconnection if (ues->fd == -1) { uwsgi_imperial_monitor_amqp_init(ues); } return; } void emperor_amqp_init(void) { uwsgi_register_imperial_monitor("amqp", uwsgi_imperial_monitor_amqp_init, uwsgi_imperial_monitor_amqp); } struct uwsgi_plugin emperor_amqp_plugin = { .name = "emperor_amqp", .on_load = emperor_amqp_init, }; uwsgi-2.0.29/plugins/emperor_amqp/uwsgiplugin.py000066400000000000000000000001341477626554400220630ustar00rootroot00000000000000 NAME='emperor_amqp' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['amqp','emperor_amqp'] uwsgi-2.0.29/plugins/emperor_mongodb/000077500000000000000000000000001477626554400176255ustar00rootroot00000000000000uwsgi-2.0.29/plugins/emperor_mongodb/emperor_mongodb.cc000066400000000000000000000124431477626554400233160ustar00rootroot00000000000000#include #include "client/dbclient.h" extern struct uwsgi_server uwsgi; extern struct uwsgi_instance *ui; // one for each mongodb imperial monitor struct uwsgi_emperor_mongodb_state { char *address; char *collection; char *json; char *database; char *username; char *password; char *predigest; }; extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues) { struct uwsgi_emperor_mongodb_state *uems = (struct uwsgi_emperor_mongodb_state *) ues->data; try { // requested fields mongo::BSONObj p = BSON( "name" << 1 << "config" << 1 << "ts" << 1 << "uid" << 1 << "gid" << 1 << "socket" << 1 ); mongo::BSONObj q = mongo::fromjson(uems->json); // the connection object (will be automatically destroyed at each cycle) mongo::DBClientConnection c; // set the socket timeout c.setSoTimeout(uwsgi.socket_timeout); // connect c.connect(uems->address); if (uems->database && uems->username && uems->password) { std::string err; if (c.auth(uems->database, uems->username, uems->password, err, uems->predigest ? false : true) == false) { uwsgi_log_verbose("[emperor-mongodb] unable to authenticate to db %s: %s\n", uems->database, err.c_str()); return; } } // run the query std::auto_ptr cursor = c.query(uems->collection, q, 0, 0, &p); while(cursor.get() && cursor->more() ) { mongo::BSONObj p = cursor->next(); // checking for an empty string is not required, but we reduce the load // in case of badly strctured databases const char *name = p.getStringField("name"); if (strlen(name) == 0) continue; const char *config = p.getStringField("config"); if (strlen(config) == 0) config = NULL; time_t vassal_ts = 0; // ts must be a Date object !!! mongo::BSONElement ts = p.getField("ts"); if (ts.type() == mongo::Date) { vassal_ts = ts.date(); } uid_t vassal_uid = 0; gid_t vassal_gid = 0; // check for tyrant mode if (uwsgi.emperor_tyrant) { int tmp_uid = p.getIntField("uid"); int tmp_gid = p.getIntField("gid"); if (tmp_uid < 0) tmp_uid = 0; if (tmp_gid < 0) tmp_gid = 0; vassal_uid = tmp_uid; vassal_gid = tmp_gid; } const char *socket_name = p.getStringField("socket"); if (strlen(socket_name) == 0) socket_name = NULL; uwsgi_emperor_simple_do(ues, (char *) name, (char *) config, vassal_ts/1000, vassal_uid, vassal_gid, (char *) socket_name); } // now check for removed instances struct uwsgi_instance *c_ui = ui->ui_next; while (c_ui) { if (c_ui->scanner == ues) { mongo::BSONObjBuilder b; b.appendElements(q); b.append("name", c_ui->name); mongo::BSONObj q2 = b.obj(); cursor = c.query(uems->collection, q2, 0, 0, &p); if (!cursor.get()) return; #ifdef UWSGI_DEBUG uwsgi_log("JSON: %s\n", q2.toString().c_str()); #endif if (!cursor->more()) { emperor_stop(c_ui); } } c_ui = c_ui->ui_next; } } catch ( mongo::DBException &e ) { uwsgi_log("[emperor-mongodb] ERROR(%s/%s): %s\n", uems->address, uems->collection, e.what()); } } // setup a new mongodb imperial monitor extern "C" void uwsgi_imperial_monitor_mongodb_init(struct uwsgi_emperor_scanner *ues) { // allocate a new state ues->data = uwsgi_calloc(sizeof(struct uwsgi_emperor_mongodb_state)); size_t arg_len = strlen(ues->arg); struct uwsgi_emperor_mongodb_state *uems = (struct uwsgi_emperor_mongodb_state *) ues->data; // parse args/ set defaults uems->address = (char *) "127.0.0.1:27017"; uems->collection = (char *) "uwsgi.emperor.vassals"; uems->json = (char *) ""; if (arg_len > 10) { uems->address = uwsgi_str(ues->arg+10); char *comma = strchr(uems->address, ','); if (!comma) goto done; *comma = 0; uems->collection = comma+1; comma = strchr(uems->collection, ','); if (!comma) goto done; *comma = 0; uems->json = comma+1; } done: uwsgi_log("[emperor] enabled emperor MongoDB monitor for %s on collection %s\n", uems->address, uems->collection); } // setup a new mongodb imperial monitor (keyval based) extern "C" void uwsgi_imperial_monitor_mongodb_init2(struct uwsgi_emperor_scanner *ues) { // allocate a new state ues->data = uwsgi_calloc(sizeof(struct uwsgi_emperor_mongodb_state)); size_t arg_len = strlen(ues->arg); struct uwsgi_emperor_mongodb_state *uems = (struct uwsgi_emperor_mongodb_state *) ues->data; // parse args/ set defaults uems->address = (char *) "127.0.0.1:27017"; uems->collection = (char *) "uwsgi.emperor.vassals"; uems->json = (char *) ""; char *args = NULL; if (arg_len <= 11) goto done; args = ues->arg+11; if (uwsgi_kvlist_parse(args, strlen(args), ',', '=', "addr", &uems->address, "address", &uems->address, "server", &uems->address, "collection", &uems->collection, "coll", &uems->collection, "json", &uems->json, "database", &uems->database, "db", &uems->database, "username", &uems->username, "password", &uems->password, "predigest", &uems->predigest, NULL)) { uwsgi_log("[emperor-mongodb] invalid keyval syntax !\n"); exit(1); } done: uwsgi_log("[emperor] enabled emperor MongoDB monitor for %s on collection %s\n", uems->address, uems->collection); } uwsgi-2.0.29/plugins/emperor_mongodb/plugin.c000066400000000000000000000011531477626554400212670ustar00rootroot00000000000000#include void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *); void uwsgi_imperial_monitor_mongodb_init(struct uwsgi_emperor_scanner *); void uwsgi_imperial_monitor_mongodb_init2(struct uwsgi_emperor_scanner *); void emperor_mongodb_init(void) { uwsgi_register_imperial_monitor("mongodb", uwsgi_imperial_monitor_mongodb_init, uwsgi_imperial_monitor_mongodb); uwsgi_register_imperial_monitor("mongodb2", uwsgi_imperial_monitor_mongodb_init2, uwsgi_imperial_monitor_mongodb); } struct uwsgi_plugin emperor_mongodb_plugin = { .name = "emperor_mongodb", .on_load = emperor_mongodb_init, }; uwsgi-2.0.29/plugins/emperor_mongodb/uwsgiplugin.py000066400000000000000000000004741477626554400225610ustar00rootroot00000000000000import os NAME='emperor_mongodb' CFLAGS = ['-I/usr/include/mongo','-I/usr/local/include/mongo'] LDFLAGS = [] LIBS = [] if not 'UWSGI_MONGODB_NOLIB' in os.environ: LIBS.append('-lmongoclient') LIBS.append('-lboost_thread') LIBS.append('-lboost_filesystem') GCC_LIST = ['plugin', 'emperor_mongodb.cc'] uwsgi-2.0.29/plugins/emperor_pg/000077500000000000000000000000001477626554400166065ustar00rootroot00000000000000uwsgi-2.0.29/plugins/emperor_pg/emperor_pg.c000066400000000000000000000055201477626554400211130ustar00rootroot00000000000000#include "../../uwsgi.h" #include extern struct uwsgi_server uwsgi; extern struct uwsgi_instance *ui; void uwsgi_imperial_monitor_pg_init(struct uwsgi_emperor_scanner *); void uwsgi_imperial_monitor_pg(struct uwsgi_emperor_scanner *); void emperor_pg_init(void); void emperor_pg_init(void) { uwsgi_register_imperial_monitor("pg", uwsgi_imperial_monitor_pg_init, uwsgi_imperial_monitor_pg); } void uwsgi_imperial_monitor_pg_init(struct uwsgi_emperor_scanner *ues) { uwsgi_log("[emperor] enabled emperor PostgreSQL monitor\n"); } void uwsgi_imperial_monitor_pg(struct uwsgi_emperor_scanner *ues) { PGconn *conn = NULL; PGresult *res = NULL; const char *query = "SELECT name,config,EXTRACT(epoch FROM ts) FROM vassals"; char *conn_string = uwsgi_str(ues->arg + 5); char *semicolon = strchr(conn_string, ';'); if (semicolon) { query = semicolon + 1; *semicolon = '\0'; } #ifdef UWSGI_DEBUG uwsgi_log("connecting to PgSQL %s\n", conn_string); #endif conn = PQconnectdb(conn_string); if (!conn || PQstatus(conn) != CONNECTION_OK) { uwsgi_log("libpq-error: %s", PQerrorMessage(conn)); goto end; } res = PQexec(conn, query); if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) { uwsgi_log("libpq-error: %s\n", PQerrorMessage(conn)); goto end; } int i; for (i = 0; i < PQntuples(res); i++) { if (PQnfields(res) >= 3) { char *name = PQgetvalue(res, i, 0); char *config = PQgetvalue(res, i, 1); char *ts = PQgetvalue(res, i, 2); int len = strlen(ts); char *dot = strchr(ts, '.'); if (dot) { len = dot - ts; } uid_t vassal_uid = 0; gid_t vassal_gid = 0; if (uwsgi.emperor_tyrant) { if (PQnfields(res) < 5) { uwsgi_log("[emperor-pg] missing uid and gid for vassal %s\n", name); continue; } char *q_uid = PQgetvalue(res, i, 3); char *q_gid = PQgetvalue(res, i, 4); vassal_uid = uwsgi_str_num(q_uid, strlen(q_uid)); vassal_gid = uwsgi_str_num(q_gid, strlen(q_gid)); } char *socket_name = NULL; if (PQnfields(res) > 5) { socket_name = PQgetvalue(res, i, 5); } uwsgi_emperor_simple_do(ues, name, config, uwsgi_str_num(ts, len), vassal_uid, vassal_gid, socket_name); } } // now check for removed instances struct uwsgi_instance *c_ui = ui->ui_next; while (c_ui) { if (c_ui->scanner == ues) { int found = 0; for (i = 0; i < PQntuples(res); i++) { if (PQnfields(res) >= 3) { if (!strcmp(PQgetvalue(res, i, 0), c_ui->name)) { found = 1; break; } } } if (!found) { emperor_stop(c_ui); } } c_ui = c_ui->ui_next; } end: free(conn_string); if (res) PQclear(res); if (conn) PQfinish(conn); } struct uwsgi_plugin emperor_pg_plugin = { .name = "emperor_pg", .on_load = emperor_pg_init, }; uwsgi-2.0.29/plugins/emperor_pg/uwsgiplugin.py000066400000000000000000000003361477626554400215370ustar00rootroot00000000000000import os NAME = 'emperor_pg' CFLAGS = ['-I' + os.popen('pg_config --includedir').read().rstrip()] LDFLAGS = [] LIBS = [ '-L' + os.popen('pg_config --libdir').read().rstrip(), '-lpq' ] GCC_LIST = ['emperor_pg'] uwsgi-2.0.29/plugins/emperor_zeromq/000077500000000000000000000000001477626554400175155ustar00rootroot00000000000000uwsgi-2.0.29/plugins/emperor_zeromq/emperor_zeromq.c000066400000000000000000000135121477626554400227310ustar00rootroot00000000000000/* Emperor zeromq monitor syntax: zmq://endpoint The socket is of type ZMQ_PULL The zeromq support must enabled in the core Howto: connect a PUSH zmq socket to the emperor zmq PULL socket. Start sending multipart messages to govern vassals. Each message need at least 2 parts: command name where command is the action to trigger and name is the name of the instance 3 optional parts can be specified config (a string containing the vassal config) uid (the user id to drop priviliges to in case of tyrant mode) gid (the group id to drop priviliges to in case of tyrant mode) There are 2 kind of commands (for now): touch destroy The first one is used for creating and reloading instances while the second is for destroying. If you do not specify a config string, the Emperor will assume you are referring to a static file available in the Emperor current directory. A python example: uwsgi --plugin emperor_zeromq --emperor zmq://tcp://127.0.0.1:5252 import zmq c = zmq.Context() s = zmq.Socket(c, zmq.PUSH) s.connect('tcp://127.0.0.1:5252') s.send_multipart(['touch','foo.ini',"[uwsgi]\nsocket=:4142"]) */ #include #include extern struct uwsgi_server uwsgi; // this is the command manager static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues) { int64_t more = 0; size_t more_size = sizeof(more); int i; zmq_msg_t msg[6]; zmq_msg_init(&msg[0]); zmq_msg_init(&msg[1]); zmq_msg_init(&msg[2]); zmq_msg_init(&msg[3]); zmq_msg_init(&msg[4]); zmq_msg_init(&msg[5]); for(i=0;i<6;i++) { #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) zmq_recvmsg(ues->data, &msg[i], ZMQ_DONTWAIT); #else zmq_recv(ues->data, &msg[i], ZMQ_NOBLOCK); #endif if (zmq_getsockopt(ues->data, ZMQ_RCVMORE, &more, &more_size)) { uwsgi_error("zmq_getsockopt()"); break; } if (!more && i < 4) break; } if (i < 1) { uwsgi_log("[emperor-zeromq] bad message received (command and instance name required)\n"); return; } char *ez_cmd = zmq_msg_data(&msg[0]); size_t ez_cmd_len = zmq_msg_size(&msg[0]); char *ez_name = zmq_msg_data(&msg[1]); size_t ez_name_len = zmq_msg_size(&msg[1]); char *ez_config = NULL; size_t ez_config_len = 0; char *ez_uid = NULL; size_t ez_uid_len = 0; char *ez_gid = NULL; size_t ez_gid_len = 0; char *ez_socket_name = NULL; size_t ez_socket_name_len = 0; char *socket_name = NULL; // config if (i > 1) { ez_config = zmq_msg_data(&msg[2]); ez_config_len = zmq_msg_size(&msg[2]); } // uid if (i > 2) { ez_uid = zmq_msg_data(&msg[3]); ez_uid_len = zmq_msg_size(&msg[3]); } // gid if (i > 3) { ez_gid = zmq_msg_data(&msg[4]); ez_gid_len = zmq_msg_size(&msg[4]); } // gid if (i > 4) { ez_socket_name = zmq_msg_data(&msg[5]); ez_socket_name_len = zmq_msg_size(&msg[5]); } char *name = uwsgi_concat2n(ez_name, ez_name_len, "", 0); // ok let's start checking commands if (!uwsgi_strncmp(ez_cmd, ez_cmd_len, "touch", 5)) { char *config = NULL; if (ez_config_len > 0) { config = uwsgi_concat2n(ez_config, ez_config_len, "", 0); } uid_t vassal_uid = 0; gid_t vassal_gid = 0; if (ez_uid_len > 0) { vassal_uid = uwsgi_str_num(ez_uid, ez_uid_len); } if (ez_gid_len > 0) { vassal_gid = uwsgi_str_num(ez_gid, ez_gid_len); } if (ez_socket_name) { socket_name = uwsgi_concat2n(ez_socket_name, ez_socket_name_len, "", 0); } uwsgi_emperor_simple_do(ues, name, config, uwsgi_now(), vassal_uid, vassal_gid, socket_name); if (config) { free(config); } if (socket_name) { free(socket_name); } } // destroy an instance else if (!uwsgi_strncmp(ez_cmd, ez_cmd_len, "destroy", 7)) { struct uwsgi_instance *ui = emperor_get(name); if (!ui) { uwsgi_log("[emperor-zeromq] unknown instance \"%s\"\n", name); } else { emperor_stop(ui); } } else { uwsgi_log("[emperor-zeromq] unknown command \"%.*s\"\n", (int)ez_cmd_len, ez_cmd); } free(name); zmq_msg_close(&msg[0]); zmq_msg_close(&msg[1]); zmq_msg_close(&msg[2]); zmq_msg_close(&msg[3]); zmq_msg_close(&msg[4]); zmq_msg_close(&msg[5]); } // this is the event manager static void uwsgi_imperial_monitor_zeromq_event(struct uwsgi_emperor_scanner *ues) { for(;;) { uint32_t zmq_events = 0; size_t opt_len = sizeof(uint32_t); int ret = zmq_getsockopt(ues->data, ZMQ_EVENTS, &zmq_events, &opt_len); if (ret < 0) { uwsgi_error("zmq_getsockopt()"); return; } if (zmq_events & ZMQ_POLLIN) { uwsgi_imperial_monitor_zeromq_cmd(ues); continue; } break; } } // initialize the zmq PULL socket static void uwsgi_imperial_monitor_zeromq_init(struct uwsgi_emperor_scanner *ues) { void *context = zmq_init(1); if (!context) { uwsgi_error("uwsgi_imperial_monitor_zeromq_init()/zmq_init()"); exit(1); } ues->data = zmq_socket(context, ZMQ_PULL); if (!ues->data) { uwsgi_error("zmq_socket()"); exit(1); } if (zmq_bind(ues->data, ues->arg+6)) { uwsgi_error("zmq_socket()"); exit(1); } size_t zmq_socket_len = sizeof(int); if (zmq_getsockopt(ues->data, ZMQ_FD, &ues->fd, &zmq_socket_len) < 0) { uwsgi_error("zmq_getsockopt()"); exit(1); } ues->event_func = uwsgi_imperial_monitor_zeromq_event; event_queue_add_fd_read(uwsgi.emperor_queue, ues->fd); } // noop static void uwsgi_imperial_monitor_zeromq(struct uwsgi_emperor_scanner *ues) { return; } void emperor_zeromq_init(void) { uwsgi_register_imperial_monitor("zmq", uwsgi_imperial_monitor_zeromq_init, uwsgi_imperial_monitor_zeromq); } struct uwsgi_plugin emperor_zeromq_plugin = { .name = "emperor_zeromq", .on_load = emperor_zeromq_init, }; uwsgi-2.0.29/plugins/emperor_zeromq/uwsgiplugin.py000066400000000000000000000001401477626554400224370ustar00rootroot00000000000000 NAME='emperor_zeromq' CFLAGS = [] LDFLAGS = [] LIBS = ['-lzmq'] GCC_LIST = ['emperor_zeromq'] uwsgi-2.0.29/plugins/example/000077500000000000000000000000001477626554400161025ustar00rootroot00000000000000uwsgi-2.0.29/plugins/example/example_plugin.c000066400000000000000000000014731477626554400212640ustar00rootroot00000000000000#include extern struct uwsgi_server uwsgi; static int uwsgi_example_init(){ uwsgi_log("i am the example plugin initialization function\n"); return 0; } static int uwsgi_example_request(struct wsgi_request *wsgi_req) { uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6); uwsgi_response_add_header(wsgi_req, "Content-type", 12, "text/html", 9); uwsgi_response_write_body_do(wsgi_req, "

Hello World

", 20); return UWSGI_OK; } static void uwsgi_example_after_request(struct wsgi_request *wsgi_req) { uwsgi_log("i am the example plugin after request function\n"); } struct uwsgi_plugin example_plugin = { .name = "example", .modifier1 = 250, .init = uwsgi_example_init, .request = uwsgi_example_request, .after_request = uwsgi_example_after_request, }; uwsgi-2.0.29/plugins/example/uwsgiplugin.py000066400000000000000000000001211477626554400210230ustar00rootroot00000000000000NAME='example' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['example_plugin'] uwsgi-2.0.29/plugins/exception_log/000077500000000000000000000000001477626554400173065ustar00rootroot00000000000000uwsgi-2.0.29/plugins/exception_log/exception_log.c000066400000000000000000000066331477626554400223210ustar00rootroot00000000000000#include /* This is an example exception handler logging a dump of the exception packet It is not built by default, to discourage its usage, as it is non-thread-safe (log lines will be clobbered). You can use it as a debugger when developing true exception handlers */ static void uwsgi_exception_handler_log_parser_vars(char *key, uint16_t keylen, char *value, uint16_t vallen, void *data) { uwsgi_log("\t%.*s=%.*s\n", keylen, key, vallen, value); } static void uwsgi_exception_handler_log_parser_backtrace(uint16_t pos, char *value, uint16_t vallen, void *data) { uint16_t item = 0; if (pos > 0) { item = pos % 5; } switch(item) { // filename case 0: uwsgi_log("\tfilename: \"%.*s\" ", vallen, value); break; // lineno case 1: uwsgi_log("line: %.*s ", vallen, value); break; // function case 2: uwsgi_log("function: \"%.*s\" ", vallen, value); break; // text case 3: if (vallen > 0) { uwsgi_log("text/code: \"%.*s\" ", vallen, value); } break; // custom case 4: if (vallen > 0) { uwsgi_log("custom: \"%.*s\"", vallen, value); } uwsgi_log("\n"); break; default: break; } } static void uwsgi_exception_handler_log_parser(char *key, uint16_t keylen, char *value, uint16_t vallen, void *data) { if (!uwsgi_strncmp(key, keylen, "vars", 4)) { uwsgi_log("vars:\n"); uwsgi_hooked_parse(value, vallen, uwsgi_exception_handler_log_parser_vars, NULL); uwsgi_log("\n"); return; } if (!uwsgi_strncmp(key, keylen, "backtrace", 9)) { uwsgi_log("backtrace:\n"); uwsgi_hooked_parse_array(value, vallen, uwsgi_exception_handler_log_parser_backtrace, NULL); uwsgi_log("\n"); return; } if (!uwsgi_strncmp(key, keylen, "class", 5)) { uwsgi_log("class: %.*s\n", vallen, value); return; } if (!uwsgi_strncmp(key, keylen, "msg", 3)) { uwsgi_log("msg: %.*s\n", vallen, value); return; } if (!uwsgi_strncmp(key, keylen, "repr", 4)) { uwsgi_log("repr: %.*s\n", vallen, value); return; } if (!uwsgi_strncmp(key, keylen, "unix", 4)) { uwsgi_log("unix: %.*s\n", vallen, value); return; } if (!uwsgi_strncmp(key, keylen, "wid", 3)) { uwsgi_log("wid: %.*s\n", vallen, value); return; } if (!uwsgi_strncmp(key, keylen, "pid", 3)) { uwsgi_log("pid: %.*s\n", vallen, value); return; } if (!uwsgi_strncmp(key, keylen, "core", 4)) { uwsgi_log("core: %.*s\n", vallen, value); return; } if (!uwsgi_strncmp(key, keylen, "node", 4)) { uwsgi_log("node: %.*s\n", vallen, value); return; } } static int uwsgi_exception_handler_log(struct uwsgi_exception_handler_instance *uehi, char *buf, size_t len) { uwsgi_log("\n!!! \"log\" exception handler !!!\n\n"); uwsgi_hooked_parse(buf, len, uwsgi_exception_handler_log_parser, NULL); uwsgi_log("\n!!! end of \"log\" exception handler output !!!\n\n"); return 0; } static void register_exception_log() { uwsgi_register_exception_handler("log", uwsgi_exception_handler_log); } struct uwsgi_plugin exception_log_plugin = { .name = "exception_log", .on_load = register_exception_log, }; uwsgi-2.0.29/plugins/exception_log/uwsgiplugin.py000066400000000000000000000001261477626554400222340ustar00rootroot00000000000000NAME='exception_log' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['exception_log'] uwsgi-2.0.29/plugins/fastrouter/000077500000000000000000000000001477626554400166455ustar00rootroot00000000000000uwsgi-2.0.29/plugins/fastrouter/fastrouter.c000066400000000000000000000353271477626554400212210ustar00rootroot00000000000000/* uWSGI fastrouter */ #include #include "../corerouter/cr.h" static struct uwsgi_fastrouter { struct uwsgi_corerouter cr; } ufr; extern struct uwsgi_server uwsgi; struct fastrouter_session { struct corerouter_session session; int has_key; uint64_t content_length; uint64_t buffered; }; static struct uwsgi_option fastrouter_options[] = { {"fastrouter", required_argument, 0, "run the fastrouter on the specified port", uwsgi_opt_corerouter, &ufr, 0}, {"fastrouter-processes", required_argument, 0, "prefork the specified number of fastrouter processes", uwsgi_opt_set_int, &ufr.cr.processes, 0}, {"fastrouter-workers", required_argument, 0, "prefork the specified number of fastrouter processes", uwsgi_opt_set_int, &ufr.cr.processes, 0}, {"fastrouter-zerg", required_argument, 0, "attach the fastrouter to a zerg server", uwsgi_opt_corerouter_zerg, &ufr, 0}, {"fastrouter-use-cache", optional_argument, 0, "use uWSGI cache as hostname->server mapper for the fastrouter", uwsgi_opt_set_str, &ufr.cr.use_cache, 0}, {"fastrouter-use-pattern", required_argument, 0, "use a pattern for fastrouter hostname->server mapping", uwsgi_opt_corerouter_use_pattern, &ufr, 0}, {"fastrouter-use-base", required_argument, 0, "use a base dir for fastrouter hostname->server mapping", uwsgi_opt_corerouter_use_base, &ufr, 0}, {"fastrouter-fallback", required_argument, 0, "fallback to the specified node in case of error", uwsgi_opt_add_string_list, &ufr.cr.fallback, 0}, {"fastrouter-use-code-string", required_argument, 0, "use code string as hostname->server mapper for the fastrouter", uwsgi_opt_corerouter_cs, &ufr, 0}, {"fastrouter-use-socket", optional_argument, 0, "forward request to the specified uwsgi socket", uwsgi_opt_corerouter_use_socket, &ufr, 0}, {"fastrouter-to", required_argument, 0, "forward requests to the specified uwsgi server (you can specify it multiple times for load balancing)", uwsgi_opt_add_string_list, &ufr.cr.static_nodes, 0}, {"fastrouter-gracetime", required_argument, 0, "retry connections to dead static nodes after the specified amount of seconds", uwsgi_opt_set_int, &ufr.cr.static_node_gracetime, 0}, {"fastrouter-events", required_argument, 0, "set the maximum number of concurrent events", uwsgi_opt_set_int, &ufr.cr.nevents, 0}, {"fastrouter-quiet", required_argument, 0, "do not report failed connections to instances", uwsgi_opt_true, &ufr.cr.quiet, 0}, {"fastrouter-cheap", no_argument, 0, "run the fastrouter in cheap mode", uwsgi_opt_true, &ufr.cr.cheap, 0}, {"fastrouter-subscription-server", required_argument, 0, "run the fastrouter subscription server on the specified address", uwsgi_opt_corerouter_ss, &ufr, 0}, {"fastrouter-subscription-slot", required_argument, 0, "*** deprecated ***", uwsgi_opt_deprecated, (void *) "useless thanks to the new implementation", 0}, {"fastrouter-timeout", required_argument, 0, "set fastrouter timeout", uwsgi_opt_set_int, &ufr.cr.socket_timeout, 0}, {"fastrouter-post-buffering", required_argument, 0, "enable fastrouter post buffering", uwsgi_opt_set_64bit, &ufr.cr.post_buffering, 0}, {"fastrouter-post-buffering-dir", required_argument, 0, "put fastrouter buffered files to the specified directory (noop, use TMPDIR env)", uwsgi_opt_set_str, &ufr.cr.pb_base_dir, 0}, {"fastrouter-stats", required_argument, 0, "run the fastrouter stats server", uwsgi_opt_set_str, &ufr.cr.stats_server, 0}, {"fastrouter-stats-server", required_argument, 0, "run the fastrouter stats server", uwsgi_opt_set_str, &ufr.cr.stats_server, 0}, {"fastrouter-ss", required_argument, 0, "run the fastrouter stats server", uwsgi_opt_set_str, &ufr.cr.stats_server, 0}, {"fastrouter-harakiri", required_argument, 0, "enable fastrouter harakiri", uwsgi_opt_set_int, &ufr.cr.harakiri, 0}, {"fastrouter-uid", required_argument, 0, "drop fastrouter privileges to the specified uid", uwsgi_opt_uid, &ufr.cr.uid, 0 }, {"fastrouter-gid", required_argument, 0, "drop fastrouter privileges to the specified gid", uwsgi_opt_gid, &ufr.cr.gid, 0 }, {"fastrouter-resubscribe", required_argument, 0, "forward subscriptions to the specified subscription server", uwsgi_opt_add_string_list, &ufr.cr.resubscribe, 0}, {"fastrouter-resubscribe-bind", required_argument, 0, "bind to the specified address when re-subscribing", uwsgi_opt_set_str, &ufr.cr.resubscribe_bind, 0}, {"fastrouter-buffer-size", required_argument, 0, "set internal buffer size (default: page size)", uwsgi_opt_set_64bit, &ufr.cr.buffer_size, 0}, {"fastrouter-fallback-on-no-key", no_argument, 0, "move to fallback node even if a subscription key is not found", uwsgi_opt_true, &ufr.cr.fallback_on_no_key, 0}, {"fastrouter-subscription-fallback-key", required_argument, 0, "key to use for fallback fastrouter", uwsgi_opt_corerouter_fallback_key, &ufr.cr, 0}, UWSGI_END_OF_OPTIONS }; static void fr_get_hostname(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) { struct corerouter_peer *peer = (struct corerouter_peer *) data; struct fastrouter_session *fr = (struct fastrouter_session *) peer->session; //uwsgi_log("%.*s = %.*s\n", keylen, key, vallen, val); if (!uwsgi_strncmp("SERVER_NAME", 11, key, keylen) && !peer->key_len) { if (vallen <= 0xff) { memcpy(peer->key, val, vallen); peer->key_len = vallen; } return; } if (!uwsgi_strncmp("HTTP_HOST", 9, key, keylen) && !fr->has_key) { if (vallen <= 0xff) { memcpy(peer->key, val, vallen); peer->key_len = vallen; } return; } if (!uwsgi_strncmp("UWSGI_FASTROUTER_KEY", 20, key, keylen)) { if (vallen <= 0xff) { fr->has_key = 1; memcpy(peer->key, val, vallen); peer->key_len = vallen; } return; } if (!uwsgi_strncmp("REMOTE_ADDR", 11, key, keylen)) { if (vallen < sizeof(peer->session->client_address)) { strncpy(peer->session->client_address, val, vallen); } return; } if (!uwsgi_strncmp("REMOTE_PORT", 11, key, keylen)) { if (vallen < sizeof(peer->session->client_port)) { strncpy(peer->session->client_port, val, vallen); } return; } if (ufr.cr.post_buffering > 0) { if (!uwsgi_strncmp("CONTENT_LENGTH", 14, key, keylen)) { fr->content_length = uwsgi_str_num(val, vallen); } } } // writing client body to the instance static ssize_t fr_instance_write_body(struct corerouter_peer *peer) { ssize_t len = cr_write(peer, "fr_instance_write_body()"); // end on empty write if (!len) return 0; // the chunk has been sent, start (again) reading from client and instances if (cr_write_complete(peer)) { // reset the original read buffer peer->out->pos = 0; cr_reset_hooks(peer); } return len; } // read client body static ssize_t fr_read_body(struct corerouter_peer *main_peer) { ssize_t len = cr_read(main_peer, "fr_read_body()"); if (!len) return 0; main_peer->session->peers->out = main_peer->in; main_peer->session->peers->out_pos = 0; cr_write_to_backend(main_peer->session->peers, fr_instance_write_body); return len; } // write to the client static ssize_t fr_write(struct corerouter_peer *main_peer) { ssize_t len = cr_write(main_peer, "fr_write()"); // end on empty write if (!len) return 0; // ok this response chunk is sent, let's start reading again if (cr_write_complete(main_peer)) { // reset the original read buffer main_peer->out->pos = 0; cr_reset_hooks(main_peer); } return len; } // data from instance static ssize_t fr_instance_read(struct corerouter_peer *peer) { ssize_t len = cr_read(peer, "fr_instance_read()"); if (!len) return 0; // set the input buffer as the main output one peer->session->main_peer->out = peer->in; peer->session->main_peer->out_pos = 0; cr_write_to_main(peer, fr_write); return len; } static ssize_t fr_instance_sendfile(struct corerouter_peer *peer) { struct fastrouter_session *fr = (struct fastrouter_session *) peer->session; ssize_t len = uwsgi_sendfile_do(peer->fd, peer->session->main_peer->buffering_fd, fr->buffered, fr->content_length - fr->buffered); if (len < 0) { cr_try_again; uwsgi_cr_error(peer, "fr_instance_sendfile()/sendfile()"); return -1; } if (len == 0) return 0; fr->buffered += len; if (peer != peer->session->main_peer && peer->un) peer->un->rx+=len; if (fr->buffered >= fr->content_length) { cr_reset_hooks(peer); } return len; } // send the uwsgi request header and vars static ssize_t fr_instance_send_request(struct corerouter_peer *peer) { ssize_t len = cr_write(peer, "fr_instance_send_request()"); // end on empty write if (!len) return 0; // the chunk has been sent, start (again) reading from client and instances if (cr_write_complete(peer)) { // reset the original read buffer peer->out->pos = 0; if (!peer->session->main_peer->is_buffering) { // start waiting for body peer->session->main_peer->last_hook_read = fr_read_body; cr_reset_hooks(peer); } else { peer->hook_write = fr_instance_sendfile; // stop reading from the client peer->session->main_peer->last_hook_read = NULL; } } return len; } // instance is connected static ssize_t fr_instance_connected(struct corerouter_peer *peer) { cr_peer_connected(peer, "fr_instance_connected()"); // we are connected, we cannot retry anymore peer->can_retry = 0; // fix modifiers peer->session->main_peer->in->buf[0] = peer->modifier1; peer->session->main_peer->in->buf[3] = peer->modifier2; // prepare to write the uwsgi packet peer->out = peer->session->main_peer->in; peer->out_pos = 0; peer->last_hook_write = fr_instance_send_request; return fr_instance_send_request(peer); } // called after receaving the uwsgi header (read vars) static ssize_t fr_recv_uwsgi_vars(struct corerouter_peer *main_peer) { struct fastrouter_session *fr = (struct fastrouter_session *) main_peer->session; struct corerouter_peer *new_peer = NULL; ssize_t len = 0; struct uwsgi_header *uh = (struct uwsgi_header *) main_peer->in->buf; // better to store it as the original buf address could change uint16_t pktsize = uh->pktsize; // are we buffering ? if (main_peer->is_buffering) { // memory or disk ? if (fr->content_length <= ufr.cr.post_buffering) { // increase buffer if needed if (uwsgi_buffer_fix(main_peer->in, pktsize+4+fr->content_length)) return -1; len = cr_read_exact(main_peer, pktsize+4+fr->content_length, "fr_recv_uwsgi_vars()"); if (!len) return 0; // whole body read ? if (main_peer->in->pos == (size_t)(pktsize+4+fr->content_length)) { main_peer->is_buffering = 0; goto done; } return len; } // first round ? if (main_peer->buffering_fd == -1) { main_peer->buffering_fd = uwsgi_tmpfd(); if (main_peer->buffering_fd < 0) return -1; } char buf[32768]; size_t remains = fr->content_length - fr->buffered; ssize_t rlen = read(main_peer->fd, buf, UMIN(32768, remains)); if (rlen < 0) { cr_try_again; uwsgi_cr_error(main_peer, "fr_recv_uwsgi_vars()/read()"); return -1; } if (rlen == 0) return 0; fr->buffered += rlen; if (write(main_peer->buffering_fd, buf, rlen) != rlen) { uwsgi_cr_error(main_peer, "fr_recv_uwsgi_vars()/write()"); return -1; } // have we done ? if (fr->buffered >= fr->content_length) { fr->buffered = 0; len = rlen; goto done; } return rlen; } // increase buffer if needed if (uwsgi_buffer_fix(main_peer->in, pktsize+4)) return -1; len = cr_read_exact(main_peer, pktsize+4, "fr_recv_uwsgi_vars()"); if (!len) return 0; // headers received, ready to choose the instance if (main_peer->in->pos == (size_t)(pktsize+4)) { struct uwsgi_corerouter *ucr = main_peer->session->corerouter; new_peer = uwsgi_cr_peer_add(main_peer->session); new_peer->last_hook_read = fr_instance_read; // find the hostname if (uwsgi_hooked_parse(main_peer->in->buf+4, pktsize, fr_get_hostname, (void *) new_peer)) { return -1; } // check the hostname; if (new_peer->key_len == 0) return -1; // find an instance using the key if (ucr->mapper(ucr, new_peer)) return -1; // check instance if (new_peer->instance_address_len == 0) { if (ufr.cr.fallback_on_no_key) { new_peer->failed = 1; new_peer->can_retry = 1; corerouter_close_peer(&ufr.cr, new_peer); return len; } return -1; } // buffering ? if (ufr.cr.post_buffering > 0 && fr->content_length > 0) { main_peer->is_buffering = 1; main_peer->buffering_fd = -1; return len; } done: if (!new_peer) { new_peer = main_peer->session->peers; } new_peer->can_retry = 1; cr_connect(new_peer, fr_instance_connected); } return len; } // called soon after accept() static ssize_t fr_recv_uwsgi_header(struct corerouter_peer *main_peer) { ssize_t len = cr_read_exact(main_peer, 4, "fr_recv_uwsgi_header()"); if (!len) return 0; // header ready if (main_peer->in->pos == 4) { // change the reading default and current hook (simulate a reset hook but without syscall) // this is a special case for the fastrouter as it changes its hook without changing the event mapping main_peer->last_hook_read = fr_recv_uwsgi_vars; main_peer->hook_read = fr_recv_uwsgi_vars; return fr_recv_uwsgi_vars(main_peer); } return len; } // retry connection to the backend static int fr_retry(struct corerouter_peer *peer) { struct uwsgi_corerouter *ucr = peer->session->corerouter; if (peer->instance_address_len > 0) goto retry; if (ucr->mapper(ucr, peer)) { return -1; } if (peer->instance_address_len == 0) { return -1; } retry: // start async connect (again) cr_connect(peer, fr_instance_connected); return 0; } // called when a new session is created static int fastrouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket *ugs, struct corerouter_session *cs, struct sockaddr *sa, socklen_t s_len) { // set the retry hook cs->retry = fr_retry; // wait for requests... if (uwsgi_cr_set_hooks(cs->main_peer, fr_recv_uwsgi_header, NULL)) return -1; return 0; } static int fastrouter_init() { ufr.cr.session_size = sizeof(struct fastrouter_session); ufr.cr.alloc_session = fastrouter_alloc_session; uwsgi_corerouter_init((struct uwsgi_corerouter *) &ufr); return 0; } static void fastrouter_setup() { ufr.cr.name = uwsgi_str("uWSGI fastrouter"); ufr.cr.short_name = uwsgi_str("fastrouter"); } struct uwsgi_plugin fastrouter_plugin = { .name = "fastrouter", .options = fastrouter_options, .init = fastrouter_init, .on_load = fastrouter_setup }; uwsgi-2.0.29/plugins/fastrouter/uwsgiplugin.py000066400000000000000000000001541477626554400215740ustar00rootroot00000000000000 NAME='fastrouter' CFLAGS = [] LDFLAGS = [] LIBS = [] REQUIRES = ['corerouter'] GCC_LIST = ['fastrouter'] uwsgi-2.0.29/plugins/fiber/000077500000000000000000000000001477626554400155365ustar00rootroot00000000000000uwsgi-2.0.29/plugins/fiber/fiber.c000066400000000000000000000050201477626554400167660ustar00rootroot00000000000000#include "../rack/uwsgi_rack.h" extern struct uwsgi_server uwsgi; extern struct uwsgi_rack ur; static struct uwsgi_plugin *rack_plugin; struct ufib { int enabled; VALUE *fib; } ufiber; struct uwsgi_option fiber_options[] = { {"fiber", no_argument, 0, "enable ruby fiber as suspend engine", uwsgi_opt_true, &ufiber.enabled, 0}, { 0, 0, 0, 0, 0, 0, 0 } }; VALUE uwsgi_fiber_request(RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)) { async_schedule_to_req_green(); return Qnil; } VALUE rb_fiber_schedule_to_req(VALUE v) { int id = uwsgi.wsgi_req->async_id; if (!uwsgi.wsgi_req->suspended) { ufiber.fib[id] = rb_fiber_new(uwsgi_fiber_request, Qnil); rb_gc_register_address(&ufiber.fib[id]); uwsgi.wsgi_req->suspended = 1; } rb_fiber_resume(ufiber.fib[id], 0, NULL); return Qnil; } static void fiber_schedule_to_req() { int id = uwsgi.wsgi_req->async_id; uint8_t modifier1 = uwsgi.wsgi_req->uh->modifier1; // call it in the main core if (uwsgi.p[modifier1]->suspend) { uwsgi.p[modifier1]->suspend(NULL); } int error = 0; rb_protect(rb_fiber_schedule_to_req, 0, &error); // call it in the main core if (uwsgi.p[modifier1]->resume) { uwsgi.p[modifier1]->resume(NULL); } if (error) { rack_plugin->exception_log(NULL); rb_gc_unregister_address(&ufiber.fib[id]); } } static void fiber_schedule_to_main(struct wsgi_request *wsgi_req) { if (uwsgi.p[wsgi_req->uh->modifier1]->suspend) { uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req); } rb_fiber_yield(0, NULL); if (uwsgi.p[wsgi_req->uh->modifier1]->resume) { uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req); } uwsgi.wsgi_req = wsgi_req; } static int fiber_init() { rack_plugin = uwsgi_plugin_get("rack"); if (!rack_plugin) { uwsgi_log("[ruby-fiber] rack plugin is not loaded !!!\n"); exit(1); } return 0; } static void fiber_init_apps(void) { if (!ufiber.enabled) return; if (uwsgi.async <= 1) { uwsgi_log("the fiber loop engine requires async mode\n"); exit(1); } ufiber.fib = uwsgi_malloc( sizeof(VALUE) * uwsgi.async ); uwsgi.schedule_to_main = fiber_schedule_to_main; uwsgi.schedule_to_req = fiber_schedule_to_req; ur.unprotected = 1; uwsgi_log("*** fiber suspend engine enabled ***\n"); } struct uwsgi_plugin fiber_plugin = { .name = "fiber", .init = fiber_init, .init_apps = fiber_init_apps, .options = fiber_options, }; uwsgi-2.0.29/plugins/fiber/uwsgiplugin.py000066400000000000000000000023471477626554400204730ustar00rootroot00000000000000import os NAME='fiber' try: RUBYPATH = os.environ['UWSGICONFIG_RUBYPATH'] except: RUBYPATH = 'ruby' CFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print RbConfig::CONFIG['CFLAGS']\"").read().rstrip().split() CFLAGS.append('-DRUBY19') CFLAGS.append('-Wno-unused-parameter') rbconfig = 'RbConfig' includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['rubyhdrdir']\"" % rbconfig).read().rstrip() if includedir == 'nil': includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['archdir']\"" % rbconfig).read().rstrip() CFLAGS.append('-I' + includedir) else: CFLAGS.append('-I' + includedir) archdir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['archdir']\"" % rbconfig).read().rstrip() arch = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['arch']\"" % rbconfig).read().rstrip() CFLAGS.append('-I' + archdir) CFLAGS.append('-I' + archdir + '/' + arch) CFLAGS.append('-I' + includedir + '/' + arch) archdir2 = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['rubyarchhdrdir']\"" % rbconfig).read().rstrip() if archdir2: CFLAGS.append('-I' + archdir2) LDFLAGS = [] LIBS = [] GCC_LIST = ['fiber'] uwsgi-2.0.29/plugins/forkptyrouter/000077500000000000000000000000001477626554400174065ustar00rootroot00000000000000uwsgi-2.0.29/plugins/forkptyrouter/forkptyrouter.c000066400000000000000000000231511477626554400225130ustar00rootroot00000000000000/* uWSGI forkpty-router can use the uwsgi protocol, modifier2 means: 0 -> stdin 1-99 -> UNIX signal 100 -> window rows (pktsize is the window size) 101 -> window cols (pktsize is the window size) */ #include #include "../corerouter/cr.h" extern struct uwsgi_server uwsgi; #if defined(__linux__) || defined(__GNU_kFreeBSD__) || defined(__HURD__) #include #elif defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__) #include #elif defined(__FreeBSD__) || defined(__DragonFly__) #include #endif #if !defined(__FreeBSD__) && !defined(__DragonFly__) #include #endif static struct uwsgi_forkptyrouter { struct uwsgi_corerouter cr; char *cmd; uint16_t win_rows; uint16_t win_cols; } ufpty; extern struct uwsgi_server uwsgi; struct forkptyrouter_session { struct corerouter_session session; // use the uwsgi protocol ? int uwsgi; size_t restore_size; struct winsize w; pid_t pid; }; static void uwsgi_opt_forkpty_urouter(char *opt, char *value, void *cr) { struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) cr; struct uwsgi_gateway_socket *ugs = uwsgi_new_gateway_socket(value, ucr->name); ugs->no_defer = 1; ugs->mode = 1; ucr->has_sockets++; } static struct uwsgi_option forkptyrouter_options[] = { {"forkptyrouter", required_argument, 0, "run the forkptyrouter on the specified address", uwsgi_opt_undeferred_corerouter, &ufpty, 0}, {"forkpty-router", required_argument, 0, "run the forkptyrouter on the specified address", uwsgi_opt_undeferred_corerouter, &ufpty, 0}, {"forkptyurouter", required_argument, 0, "run the forkptyrouter on the specified address", uwsgi_opt_forkpty_urouter, &ufpty, 0}, {"forkpty-urouter", required_argument, 0, "run the forkptyrouter on the specified address", uwsgi_opt_forkpty_urouter, &ufpty, 0}, {"forkptyrouter-command", required_argument, 0, "run the specified command on every connection (default: /bin/sh)", uwsgi_opt_set_str, &ufpty.cmd, 0}, {"forkpty-router-command", required_argument, 0, "run the specified command on every connection (default: /bin/sh)", uwsgi_opt_set_str, &ufpty.cmd, 0}, {"forkptyrouter-cmd", required_argument, 0, "run the specified command on every connection (default: /bin/sh)", uwsgi_opt_set_str, &ufpty.cmd, 0}, {"forkpty-router-cmd", required_argument, 0, "run the specified command on every connection (default: /bin/sh)", uwsgi_opt_set_str, &ufpty.cmd, 0}, {"forkptyrouter-rows", required_argument, 0, "set forkptyrouter default pty window rows", uwsgi_opt_set_16bit, &ufpty.win_rows, 0}, {"forkptyrouter-cols", required_argument, 0, "set forkptyrouter default pty window cols", uwsgi_opt_set_16bit, &ufpty.win_cols, 0}, {"forkptyrouter-processes", required_argument, 0, "prefork the specified number of forkptyrouter processes", uwsgi_opt_set_int, &ufpty.cr.processes, 0}, {"forkptyrouter-workers", required_argument, 0, "prefork the specified number of forkptyrouter processes", uwsgi_opt_set_int, &ufpty.cr.processes, 0}, {"forkptyrouter-zerg", required_argument, 0, "attach the forkptyrouter to a zerg server", uwsgi_opt_corerouter_zerg, &ufpty, 0}, {"forkptyrouter-fallback", required_argument, 0, "fallback to the specified node in case of error", uwsgi_opt_add_string_list, &ufpty.cr.fallback, 0}, {"forkptyrouter-events", required_argument, 0, "set the maximum number of concufptyent events", uwsgi_opt_set_int, &ufpty.cr.nevents, 0}, {"forkptyrouter-cheap", no_argument, 0, "run the forkptyrouter in cheap mode", uwsgi_opt_true, &ufpty.cr.cheap, 0}, {"forkptyrouter-timeout", required_argument, 0, "set forkptyrouter timeout", uwsgi_opt_set_int, &ufpty.cr.socket_timeout, 0}, {"forkptyrouter-stats", required_argument, 0, "run the forkptyrouter stats server", uwsgi_opt_set_str, &ufpty.cr.stats_server, 0}, {"forkptyrouter-stats-server", required_argument, 0, "run the forkptyrouter stats server", uwsgi_opt_set_str, &ufpty.cr.stats_server, 0}, {"forkptyrouter-ss", required_argument, 0, "run the forkptyrouter stats server", uwsgi_opt_set_str, &ufpty.cr.stats_server, 0}, {"forkptyrouter-harakiri", required_argument, 0, "enable forkptyrouter harakiri", uwsgi_opt_set_int, &ufpty.cr.harakiri, 0}, {0, 0, 0, 0, 0, 0, 0}, }; // write to backend static ssize_t fpty_instance_write(struct corerouter_peer *peer) { struct forkptyrouter_session *fpty_session = (struct forkptyrouter_session *) peer->session; ssize_t len = cr_write(peer, "fpty_instance_write()"); // end on empty write if (!len) return 0; // the chunk has been sent, start (again) reading from client and instances if (cr_write_complete(peer)) { // reset the buffer if (fpty_session->uwsgi) { if (uwsgi_buffer_decapitate(peer->out, peer->out->pos)) return -1; peer->out->pos = fpty_session->restore_size; } else { peer->out->pos = 0; } cr_reset_hooks(peer); } return len; } // write to client static ssize_t fpty_write(struct corerouter_peer *main_peer) { ssize_t len = cr_write(main_peer, "fpty_write()"); // end on empty write if (!len) return 0; // ok this response chunk is sent, let's start reading again if (cr_write_complete(main_peer)) { // reset the buffer main_peer->out->pos = 0; cr_reset_hooks(main_peer); } return len; } static ssize_t fpty_parse_uwsgi(struct corerouter_peer *peer) { struct forkptyrouter_session *fpty_session = (struct forkptyrouter_session *) peer->session; for(;;) { if (peer->in->pos < 4) return 0; struct uwsgi_header *uh = (struct uwsgi_header *) peer->in->buf; uint16_t pktsize = uh->pktsize; switch(uh->modifier2) { case 0: // stdin if ((size_t) (pktsize+4) > peer->in->pos) return 0; if (uwsgi_buffer_decapitate(peer->in, 4)) return -1; return pktsize; case 100: if (uwsgi_buffer_decapitate(peer->in, 4)) return -1; fpty_session->w.ws_row = pktsize; ioctl(peer->session->peers->fd, TIOCSWINSZ, &fpty_session->w); // rows break; case 101: if (uwsgi_buffer_decapitate(peer->in, 4)) return -1; fpty_session->w.ws_col = pktsize; ioctl(peer->session->peers->fd, TIOCSWINSZ, &fpty_session->w); // cols break; default: if (uwsgi_buffer_decapitate(peer->in, 4)) return -1; // send signal kill(fpty_session->pid, uh->modifier2); break; } } return 0; } // read from backend static ssize_t fpty_instance_read(struct corerouter_peer *peer) { ssize_t len = cr_read(peer, "fpty_instance_read()"); if (!len) return 0; // set the input buffer as the main output one peer->session->main_peer->out = peer->in; peer->session->main_peer->out_pos = 0; cr_write_to_main(peer, fpty_write); return len; } // read from client static ssize_t fpty_read(struct corerouter_peer *main_peer) { struct forkptyrouter_session *fpty_session = (struct forkptyrouter_session *) main_peer->session; ssize_t len = cr_read(main_peer, "fpty_read()"); if (!len) return 0; if (fpty_session->uwsgi) { ssize_t rlen = fpty_parse_uwsgi(main_peer); if (rlen < 0) return -1; if (rlen == 0) return 1; fpty_session->restore_size = main_peer->in->pos - rlen; main_peer->session->peers->out = main_peer->in; main_peer->session->peers->out->pos = rlen; } else { main_peer->session->peers->out = main_peer->in; } main_peer->session->peers->out_pos = 0; cr_write_to_backend(main_peer->session->peers, fpty_instance_write); return len; } static void fpty_session_close(struct corerouter_session *cs) { struct forkptyrouter_session *fpty_session = (struct forkptyrouter_session *) cs; if (fpty_session->pid > 0) { int waitpid_status = 0; if (waitpid(fpty_session->pid, &waitpid_status, WNOHANG) < 0) { uwsgi_error("fpty_session_close()/waitpid()"); } } } // allocate a new session static int forkptyrouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket *ugs, struct corerouter_session *cs, struct sockaddr *sa, socklen_t s_len) { // set default read hook cs->main_peer->last_hook_read = fpty_read; // wait4() on close cs->close = fpty_session_close; struct forkptyrouter_session *fpty_session = (struct forkptyrouter_session *) cs; if (ugs->mode == 1) { fpty_session->uwsgi = 1; } // default terminal size fpty_session->w.ws_row = ufpty.win_rows ? ufpty.win_rows : 24; fpty_session->w.ws_col = ufpty.win_cols ? ufpty.win_cols : 80; // add a new peer struct corerouter_peer *peer = uwsgi_cr_peer_add(cs); // on new connection generate a new pty fpty_session->pid = forkpty(&peer->fd, NULL, NULL, &fpty_session->w); if (fpty_session->pid < 0) { uwsgi_error("forkpty()"); return -1; } else if (fpty_session->pid == 0) { if (ufpty.cmd) { char *space = strchr(ufpty.cmd, ' '); if (space) { char *argv[4]; argv[0] = uwsgi_binsh(); argv[1] = "-c"; argv[2] = ufpty.cmd; argv[3] = NULL; execv(argv[0], argv); } else { char *argv[2]; argv[0] = ufpty.cmd; argv[1] = NULL; execv(argv[0], argv); } } else { char *argv[2]; argv[0] = "/bin/sh"; argv[1] = NULL; execv(argv[0], argv); } // never here; uwsgi_error("forkptyrouter_alloc_session()/execv()"); exit(1); } ucr->cr_table[peer->fd] = peer; cr_reset_hooks_and_read(peer, fpty_instance_read); return 0; } static int forkptyrouter_init() { ufpty.cr.session_size = sizeof(struct forkptyrouter_session); ufpty.cr.alloc_session = forkptyrouter_alloc_session; uwsgi_corerouter_init((struct uwsgi_corerouter *) &ufpty); return 0; } static void forkptyrouter_setup() { ufpty.cr.name = uwsgi_str("uWSGI forkptyrouter"); ufpty.cr.short_name = uwsgi_str("forkptyrouter"); } struct uwsgi_plugin forkptyrouter_plugin = { .name = "forkptyrouter", .options = forkptyrouter_options, .init = forkptyrouter_init, .on_load = forkptyrouter_setup }; uwsgi-2.0.29/plugins/forkptyrouter/uwsgiplugin.py000066400000000000000000000003701477626554400223350ustar00rootroot00000000000000import os uwsgi_os = os.uname()[0] NAME='forkptyrouter' CFLAGS = [] LDFLAGS = [] if uwsgi_os in ('Linux', 'FreeBSD', 'GNU', 'NetBSD', 'DragonFly'): LIBS = ['-lutil'] else: LIBS = [] REQUIRES = ['corerouter'] GCC_LIST = ['forkptyrouter'] uwsgi-2.0.29/plugins/gccgo/000077500000000000000000000000001477626554400155315ustar00rootroot00000000000000uwsgi-2.0.29/plugins/gccgo/gccgo_plugin.c000066400000000000000000000327771477626554400203550ustar00rootroot00000000000000#include /* Soon before official Go 1.1, we understood supporting Go in a fork() heavy environment was not blessed by the Go community. Instead of completely dropping support for Go, we studied how the gccgo project works and we decided it was a better approach for uWSGI. This new plugin works by initializing a new "go runtime" after each fork(). The runtime calls the Go main function (developed by the user), and pass the whole uWSGI control to it. the uwsgi.Run() go function directly calls the uwsgi_takeover() function (it automatically manages mules, spoolers and workers) The plugin implements goroutines too. On startup a goroutine is created for each socket and signals file descriptors. For every request a new goroutine is created too. The wsgi_request * structure is attached to the "closure" field of the goroutine (PAY ATTENTION) even if the loop engine makes use of the async mode, pthreads could be spawned all over the place. For such a reason a mutex is created avoiding the global wsgi_req structures to be clobbered Contrary to the standard way Go apps are deployed, the plugin supports loading shared libraries. While this is a common approach in other environments, the Go community prefers monolithic binaries. As always, choose the model that best suite for you. Eventually building a single uWSGI binary with your Go app embedded is pretty easy: CFLAGS=-DUWSGI_GCCGO_MONOLITHIC UWSGI_ADDITIONAL_SOURCES=t/go/uploadtest.go UWSGI_PROFILE=gccgo make or you can add the following two directives in a build profile: cflags = -DUWSGI_GCCGO_MONOLITHIC additional_sources = t/go/uploadtest.go */ extern struct uwsgi_server uwsgi; struct uwsgi_plugin gccgo_plugin; struct uwsgi_gccgo{ // 1 if a main is loaded int initialized; struct uwsgi_string_list *libs; char *args; pthread_mutex_t wsgi_req_lock; } ugccgo; /* shortcut for enabling the "goroutines" loop engine */ static void uwsgi_opt_setup_goroutines(char *opt, char *value, void *foobar) { // set async mode uwsgi_opt_set_int(opt, value, &uwsgi.async); // set loop engine uwsgi.loop = "goroutines"; } struct uwsgi_option uwsgi_gccgo_options[] = { {"go-load", required_argument, 0, "load a go shared library in the process address space, eventually patching main.main and __go_init_main", uwsgi_opt_add_string_list, &ugccgo.libs, 0}, {"gccgo-load", required_argument, 0, "load a go shared library in the process address space, eventually patching main.main and __go_init_main", uwsgi_opt_add_string_list, &ugccgo.libs, 0}, {"go-args", required_argument, 0, "set go commandline arguments", uwsgi_opt_set_str, &ugccgo.args, 0}, {"gccgo-args", required_argument, 0, "set go commandline arguments", uwsgi_opt_set_str, &ugccgo.args, 0}, {"goroutines", required_argument, 0, "a shortcut setting optimal options for goroutine-based apps, takes the number of max goroutines to spawn as argument", uwsgi_opt_setup_goroutines, NULL, UWSGI_OPT_THREADS}, {0, 0, 0, 0, 0, 0, 0}, }; // no_split_stack is the key to avoid crashing !!! void* runtime_m(void) __attribute__ ((noinline, no_split_stack)); // initialize runtime void runtime_check(void); void runtime_args(int, char **); void runtime_osinit(void); void runtime_schedinit(void); void runtime_main(void); void runtime_mstart(void *); // spawn a goroutine void *__go_go(void *, void *); // api functions exposed extern void uwsgigo_request(void *, void *) __asm__ ("go.uwsgi.RequestHandler"); extern void* uwsgigo_env(void *) __asm__ ("go.uwsgi.Env"); extern void* uwsgigo_env_add(void *, void *, uint16_t, void *, uint16_t) __asm__ ("go.uwsgi.EnvAdd"); extern void uwsgigo_signal_handler(void *, uint8_t) __asm__ ("go.uwsgi.SignalHandler"); // for goroutines void runtime_netpollinit(void); void runtime_starttheworld(void); void *runtime_pollOpen(int) __asm__ ("net.runtime_pollOpen"); void runtime_pollClose(void *) __asm__ ("net.runtime_pollClose"); void runtime_pollUnblock(void *) __asm__ ("net.runtime_pollUnblock"); int runtime_pollWait(void *, int) __asm__ ("net.runtime_pollWait"); void runtime_pollSetDeadline(void *, int64_t, int) __asm__ ("net.runtime_pollSetDeadline"); void runtime_gosched(void); // the current goroutine void *runtime_g(void); // we use the closure field to store the wsgi_req structure void __go_set_closure(void *); void *__go_get_closure(void); static void mainstart(void *arg __attribute__((unused))) { runtime_main(); } #ifndef UWSGI_GCCGO_MONOLITHIC void uwsgigo_main_main(void) __asm__ ("main.main"); void uwsgigo_main_init(void) __asm__ ("__go_init_main"); #endif void (*uwsgigo_hook_init)(void); void (*uwsgigo_hook_main)(void); void uwsgigo_main_init(void) { uwsgigo_hook_init(); } void uwsgigo_main_main(void) { uwsgigo_hook_main(); } int uwsgi_gccgo_helper_request_body_read(struct wsgi_request *wsgi_req, char *p, uint64_t len) { ssize_t rlen = 0; char *buf = uwsgi_request_body_read(wsgi_req, len, &rlen); if (buf == uwsgi.empty) { return 0; } else if (buf == NULL) { return -1; } memcpy(p, buf, rlen); return (int) rlen; } int uwsgi_gccgo_helper_register_signal(uint8_t signum, char *receiver, void *handler) { return uwsgi_register_signal(signum, receiver, handler, gccgo_plugin.modifier1); } static void uwsgi_gccgo_initialize() { if (uwsgi.threads > 1) { uwsgi_log("!!! the Go runtime cannot work in multithreaded modes !!!\n"); exit(1); } #ifdef UWSGI_GCCGO_MONOLITHIC uwsgigo_hook_init = dlsym(RTLD_DEFAULT, "__go_init_main"); uwsgigo_hook_main = dlsym(RTLD_DEFAULT, "main.main"); #endif struct uwsgi_string_list *usl = ugccgo.libs; while(usl) { void *handle = dlopen(usl->value, RTLD_NOW | RTLD_GLOBAL); if (!handle) { uwsgi_log("unable to open go shared library: %s\n", dlerror()); exit(1); } void *g_init = dlsym(handle, "__go_init_main"); void *g_main = dlsym(handle, "main.main"); if (g_init && g_main) { uwsgigo_hook_init = g_init; uwsgigo_hook_main = g_main; uwsgi_log("[uwsgi-gccgo] loaded %s as main\n", usl->value); } else { uwsgi_log("[uwsgi-gccgo] loaded %s\n", usl->value); } usl = usl->next; } if (!uwsgigo_hook_init || !uwsgigo_hook_main) { return; } ugccgo.initialized = 1; // Go runtime initialization int argc = 0; if (ugccgo.args) { char *argv_list = uwsgi_str(ugccgo.args); char *p, *ctx = NULL; uwsgi_foreach_token(argv_list, " ", p, ctx) { argc++; } free(argv_list); } runtime_check(); if (argc > 0) { char **argv = uwsgi_calloc(sizeof(char *) * (argc + 2)); char *argv_list = uwsgi_str(ugccgo.args); char *p, *ctx = NULL; int n = 0; uwsgi_foreach_token(argv_list, " ", p, ctx) { argv[n] = p; n++; } runtime_args(argc, argv); } else { char *argv[2] = {0,0}; runtime_args(0, argv); } runtime_osinit(); runtime_schedinit(); __go_go(mainstart, NULL); runtime_mstart(runtime_m()); // never here } static int uwsgi_gccgo_request(struct wsgi_request *wsgi_req) { if (!ugccgo.initialized) { uwsgi_log("!!! Go runtime not initialized !!!\n"); goto end; } /* Standard GO request */ if (!wsgi_req->uh->pktsize) { uwsgi_log("Empty GO request. skip.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } wsgi_req->async_environ = uwsgigo_env(wsgi_req); int i; for(i=0;ivar_cnt;i+=2) { uwsgigo_env_add(wsgi_req->async_environ, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len); } uwsgigo_request(wsgi_req->async_environ, wsgi_req); end: return UWSGI_OK; } static void uwsgi_gccgo_after_request(struct wsgi_request *wsgi_req) { log_request(wsgi_req); } static int uwsgi_gccgo_signal_handler(uint8_t signum, void *handler) { if (!ugccgo.initialized) return -1; uwsgigo_signal_handler(handler, signum); return 0; } #define free_req_queue pthread_mutex_lock(&ugccgo.wsgi_req_lock);uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = wsgi_req; pthread_mutex_unlock(&ugccgo.wsgi_req_lock) static void uwsgi_gccgo_request_goroutine(void *arg) { struct wsgi_request *wsgi_req = (struct wsgi_request *) arg; // map wsgi_req to the goroutine __go_set_closure(wsgi_req); int ret,status; for(;;) { ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.socket_timeout); wsgi_req->switches++; if (ret <= 0) { goto end; } retry: status = wsgi_req->socket->proto(wsgi_req); if (status < 0) { goto end; } else if (status == 0) { break; } if (uwsgi_is_again()) continue; goto retry; } #ifdef UWSGI_ROUTING if (uwsgi_apply_routes(wsgi_req) == UWSGI_ROUTE_BREAK) { goto end; } #endif for(;;) { if (uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req) <= UWSGI_OK) { goto end; } wsgi_req->switches++; // yield runtime_gosched(); } end: uwsgi_close_request(wsgi_req); free_req_queue; } static struct wsgi_request *uwsgi_gccgo_current_wsgi_req(void) { return (struct wsgi_request *) __go_get_closure(); } static int uwsgi_gccgo_wait_read_hook(int fd, int timeout) { void *pdesc = runtime_pollOpen(fd); int64_t t = (uwsgi_micros() * 1000LL) + (((int64_t)timeout) * 1000LL * 1000LL * 1000LL); runtime_pollSetDeadline(pdesc, t, 'r'); int ret = runtime_pollWait(pdesc, 'r'); runtime_pollUnblock(pdesc); runtime_pollClose(pdesc); if (ret == 0) return 1; // timeout if (ret == 2) return 0; return -1; } static int uwsgi_gccgo_wait_write_hook(int fd, int timeout) { void *pdesc = runtime_pollOpen(fd); int64_t t = (uwsgi_micros() * 1000LL) + (((int64_t)timeout) * 1000LL * 1000LL * 1000LL); runtime_pollSetDeadline(pdesc, t, 'w'); int ret = runtime_pollWait(pdesc, 'w'); runtime_pollUnblock(pdesc); runtime_pollClose(pdesc); if (ret == 0) return 1; // timeout if (ret == 2) return 0; return -1; } /* this goroutine manages signals */ static void uwsgi_gccgo_signal_goroutine(void *arg) { int *fd = (int *) arg; void *pdesc = runtime_pollOpen(*fd); for(;;) { runtime_pollWait(pdesc, 'r'); retry: uwsgi_receive_signal(*fd, "worker", uwsgi.mywid); if (uwsgi_is_again()) continue; goto retry; } } static void uwsgi_gccgo_socket_goroutine(void *arg) { struct uwsgi_socket *uwsgi_sock = (struct uwsgi_socket *) arg; struct wsgi_request *wsgi_req = NULL; void *pdesc = runtime_pollOpen(uwsgi_sock->fd); // wait for connection for(;;) { runtime_pollWait(pdesc, 'r'); retry: pthread_mutex_lock(&ugccgo.wsgi_req_lock); wsgi_req = find_first_available_wsgi_req(); pthread_mutex_unlock(&ugccgo.wsgi_req_lock); if (wsgi_req == NULL) { uwsgi_async_queue_is_full(uwsgi_now()); // try rescheduling... // we do not use runtime_gosched() as we want to call the netpoll loop too runtime_pollUnblock(pdesc); runtime_pollClose(pdesc); pdesc = runtime_pollOpen(uwsgi_sock->fd); continue; } // fill wsgi_request structure wsgi_req_setup(wsgi_req, wsgi_req->async_id, uwsgi_sock ); // mark core as used uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 1; // accept the connection (since uWSGI 1.5 all of the sockets are non-blocking) if (wsgi_req_simple_accept(wsgi_req, uwsgi_sock->fd)) { uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 0; free_req_queue; if (uwsgi_is_again()) continue; goto retry; } wsgi_req->start_of_request = uwsgi_micros(); wsgi_req->start_of_request_in_sec = wsgi_req->start_of_request/1000000; // enter harakiri mode if (uwsgi.harakiri_options.workers > 0) { set_harakiri(uwsgi.harakiri_options.workers); } // spawn the new goroutine __go_go(uwsgi_gccgo_request_goroutine, wsgi_req); goto retry; } } static void uwsgi_gccgo_loop() { if (!ugccgo.initialized) { uwsgi_log("no go.main code loaded !!!\n"); exit(1); } // initialize the log protecting the wsgi_req structures pthread_mutex_init(&ugccgo.wsgi_req_lock, NULL); // hooks uwsgi.current_wsgi_req = uwsgi_gccgo_current_wsgi_req; uwsgi.wait_write_hook = uwsgi_gccgo_wait_write_hook; uwsgi.wait_read_hook = uwsgi_gccgo_wait_read_hook; // ininitialize Go I/O loop runtime_netpollinit(); if (uwsgi.signal_socket > -1) { __go_go(uwsgi_gccgo_signal_goroutine, &uwsgi.signal_socket); __go_go(uwsgi_gccgo_signal_goroutine, &uwsgi.my_signal_socket); } // start a goroutine for each socket struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while(uwsgi_sock) { if (!uwsgi_sock->next) { uwsgi_gccgo_socket_goroutine(uwsgi_sock); } else { __go_go(uwsgi_gccgo_socket_goroutine, uwsgi_sock); } uwsgi_sock = uwsgi_sock->next; } // never here } static void uwsgi_gccgo_on_load() { uwsgi_register_loop( (char *) "go", uwsgi_gccgo_loop); uwsgi_register_loop( (char *) "goroutine", uwsgi_gccgo_loop); uwsgi_register_loop( (char *) "goroutines", uwsgi_gccgo_loop); } struct uwsgi_plugin gccgo_plugin = { .name = "gccgo", .modifier1 = 11, .options = uwsgi_gccgo_options, .on_load = uwsgi_gccgo_on_load, .request = uwsgi_gccgo_request, .after_request = uwsgi_gccgo_after_request, .post_fork = uwsgi_gccgo_initialize, .signal_handler = uwsgi_gccgo_signal_handler, }; uwsgi-2.0.29/plugins/gccgo/uwsgi.go000066400000000000000000000103601477626554400172160ustar00rootroot00000000000000package uwsgi /* this is a very low-level module, full of performance hacks do not take it as a good example of go coding... */ import ( "strings" "net/http" "net/http/cgi" "io" ) //extern uwsgi_takeover func uwsgi_takeover() //extern uwsgi_response_write_body_do func uwsgi_response_write_body_do(*interface{}, *byte, uint64) int //extern uwsgi_response_prepare_headers_int func uwsgi_response_prepare_headers_int(*interface{}, int) int //extern uwsgi_response_add_header func uwsgi_response_add_header(*interface{}, *byte, uint16, *byte, uint16) int //extern uwsgi_gccgo_helper_request_body_read func uwsgi_request_body_read(*interface{}, *byte, uint64) int //extern uwsgi_gccgo_helper_register_signal func uwsgi_register_signal(uint8, *byte, func(uint8)) int //extern uwsgi_cache_magic_get func uwsgi_cache_magic_get(*byte, uint16, *uint64, *uint64, *byte) *byte; //extern __go_byte_array_to_string func __go_byte_array_to_string(*byte, int) string //extern free func free(* byte) var uwsgi_signals_gc [256]func(uint8) var uwsgi_env_gc map[interface{}]interface{} func Env(wsgi_req *interface{}) *map[string]string { var env map[string]string env = make(map[string]string) uwsgi_env_gc[wsgi_req] = &env return &env } func EnvAdd(env *map[string]string, k *byte, kl uint16, v *byte, vl uint16) { s_k := __go_byte_array_to_string(k, int(kl)) s_v := __go_byte_array_to_string(v, int(vl)) (*env)[ s_k ] = s_v } type ResponseWriter struct { r *http.Request wsgi_req *interface{} headers http.Header wroteHeader bool } func (w *ResponseWriter) Write(p []byte) (n int, err error) { if !w.wroteHeader { w.WriteHeader(http.StatusOK) } uwsgi_response_write_body_do(w.wsgi_req, &p[0], uint64(len(p))) return len(p), err } func (w *ResponseWriter) WriteHeader(status int) { uwsgi_response_prepare_headers_int(w.wsgi_req, status ) if w.headers.Get("Content-Type") == "" { w.headers.Set("Content-Type", "text/html; charset=utf-8") } for k := range w.headers { for _, v := range w.headers[k] { v = strings.NewReplacer("\n", " ", "\r", " ").Replace(v) v = strings.TrimSpace(v) kb := []byte(k) vb := []byte(v) uwsgi_response_add_header(w.wsgi_req, &kb[0], uint16(len(k)), &vb[0], uint16(len(v))) } } w.wroteHeader = true } func (w *ResponseWriter) Header() http.Header { return w.headers } type BodyReader struct { wsgi_req *interface{} } // there is no close in request body func (br *BodyReader) Close() error { return nil } func (br *BodyReader) Read(p []byte) (n int, err error) { var rlen int = uwsgi_request_body_read(br.wsgi_req, &p[0], uint64(len(p))) if (rlen == 0) { err = io.EOF; return 0, err } else if (rlen == -1) { err = io.ErrUnexpectedEOF return 0, err } return rlen, err } func RequestHandler(env *map[string]string, wsgi_req *interface{}) { httpReq, err := cgi.RequestFromMap(*env) if err == nil { httpReq.Body = &BodyReader{wsgi_req} w := ResponseWriter{httpReq, wsgi_req,http.Header{},false} http.DefaultServeMux.ServeHTTP(&w, httpReq) } delete(uwsgi_env_gc, wsgi_req) } func RegisterSignal(signum uint8, receiver string, handler func(uint8)) bool { if (receiver == "") { receiver = "worker" } var b []byte = []byte(receiver) if (uwsgi_register_signal(signum, &b[0], handler) < 0) { return false } uwsgi_signals_gc[signum] = handler return true } // get an item from the cache func CacheGet(key string, cache string) string { var b_key []byte = []byte(key) var v_len uint64 = 0 var expires uint64 = 0 var value *byte if (cache == "") { value = uwsgi_cache_magic_get(&b_key[0], uint16(len(b_key)), &v_len, &expires, nil) } else { b_cache := []byte(cache) value = uwsgi_cache_magic_get(&b_key[0], uint16(len(b_key)), &v_len, &expires, &b_cache[0]) } ret := __go_byte_array_to_string(value, int(v_len)) free(value) return ret } func SignalHandler(handler func(uint8), signum uint8) { handler(signum) } func Run() { uwsgi_env_gc = make(map[interface{}]interface{}) uwsgi_takeover() } uwsgi-2.0.29/plugins/gccgo/uwsgiplugin.py000066400000000000000000000006541477626554400204650ustar00rootroot00000000000000import os import subprocess NAME = 'gccgo' CFLAGS = ['-g'] LDFLAGS = [] LIBS = ['-lgo'] GCC_LIST = ['gccgo_plugin', 'uwsgi.go'] def post_build(config): if os.path.exists('plugins/gccgo/uwsgi.go.o'): if subprocess.call("objcopy -j .go_export plugins/gccgo/uwsgi.go.o plugins/gccgo/uwsgi.gox", shell=True) != 0: os._exit(1) print("*** uwsgi.gox available in %s/plugins/gccgo ***" % os.getcwd()) uwsgi-2.0.29/plugins/geoip/000077500000000000000000000000001477626554400155525ustar00rootroot00000000000000uwsgi-2.0.29/plugins/geoip/geoip.c000066400000000000000000000100551477626554400170220ustar00rootroot00000000000000#include #include #include struct uwsgi_geoip { char *country_db; char *city_db; GeoIP *country; GeoIP *city; int use_disk; } ugeoip; struct uwsgi_option uwsgi_geoip_options[] = { {"geoip-country", required_argument, 0, "load the specified geoip country database", uwsgi_opt_set_str, &ugeoip.country_db, 0}, {"geoip-city", required_argument, 0, "load the specified geoip city database", uwsgi_opt_set_str, &ugeoip.city_db, 0}, {"geoip-use-disk", no_argument, 0, "do not cache geoip databases in memory", uwsgi_opt_true, &ugeoip.use_disk, 0}, UWSGI_END_OF_OPTIONS }; static int uwsgi_geoip_init() { if (ugeoip.country_db) { ugeoip.country = GeoIP_open(ugeoip.country_db, ugeoip.use_disk ? GEOIP_STANDARD : GEOIP_MEMORY_CACHE); if (!ugeoip.country) { uwsgi_log("unable to open GeoIP country database: %s\n", ugeoip.country_db); exit(1); } } if (ugeoip.city_db) { ugeoip.city = GeoIP_open(ugeoip.city_db, ugeoip.use_disk ? GEOIP_STANDARD : GEOIP_MEMORY_CACHE); if (!ugeoip.city) { uwsgi_log("unable to open GeoIP city database: %s\n", ugeoip.city_db); exit(1); } } return 0; } static char *uwsgi_route_var_geoip(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) { uint32_t ip; char ip_str[16]; // should be enough for geo coords char lonlat[64]; memset(ip_str, 0, 16); memcpy(ip_str, wsgi_req->remote_addr, wsgi_req->remote_addr_len); if (inet_pton(AF_INET, ip_str, &ip) <= 0) { return NULL; } ip = htonl(ip); char *value = NULL; // always prefer the city database; GeoIP *g = ugeoip.city; if (!g) { g = ugeoip.country; if (g) { if (!uwsgi_strncmp(key, keylen, "country_code", 12)) { value = (char *) GeoIP_country_code_by_ipnum(g, ip); } else if (!uwsgi_strncmp(key, keylen, "country_code3", 13)) { value = (char *) GeoIP_country_code3_by_ipnum(g, ip); } else if (!uwsgi_strncmp(key, keylen, "country_name", 12)) { value = (char *) GeoIP_country_name_by_ipnum(g, ip); } if (value) { *vallen = strlen(value); return uwsgi_str(value); } } return NULL; } GeoIPRecord *gr = GeoIP_record_by_ipnum(g, ip); if (!gr) return NULL; // ok let's generate the output if (!uwsgi_strncmp(key, keylen, "continent", 9)) { value = gr->continent_code; } else if (!uwsgi_strncmp(key, keylen, "country_code", 12)) { value = gr->country_code; } else if (!uwsgi_strncmp(key, keylen, "country_code3", 13)) { value = gr->country_code3; } else if (!uwsgi_strncmp(key, keylen, "country_name", 12)) { value = gr->country_name; } else if (!uwsgi_strncmp(key, keylen, "region", 6)) { value = gr->region; } else if (!uwsgi_strncmp(key, keylen, "region_name", 11)) { value = (char *) GeoIP_region_name_by_code(gr->country_code, gr->region); } else if (!uwsgi_strncmp(key, keylen, "city", 4)) { value = gr->city; } else if (!uwsgi_strncmp(key, keylen, "postal_code", 11)) { value = gr->postal_code; } else if (!uwsgi_strncmp(key, keylen, "latitude", 8) || !uwsgi_strncmp(key, keylen, "lat", 3)) { snprintf(lonlat, 64, "%f", gr->latitude); value = lonlat; } else if (!uwsgi_strncmp(key, keylen, "longitude", 9) || !uwsgi_strncmp(key, keylen, "lon", 3)) { snprintf(lonlat, 64, "%f", gr->longitude); value = lonlat; } else if (!uwsgi_strncmp(key, keylen, "dma", 3)) { snprintf(lonlat, 64, "%d", gr->dma_code); value = lonlat; } else if (!uwsgi_strncmp(key, keylen, "area", 4)) { snprintf(lonlat, 64, "%d", gr->area_code); value = lonlat; } if (value) { *vallen = strlen(value); char *ret = uwsgi_str(value); GeoIPRecord_delete(gr); return ret; } GeoIPRecord_delete(gr); return NULL; } static void register_route_vars_geoip() { struct uwsgi_route_var *urv = uwsgi_register_route_var("geoip", uwsgi_route_var_geoip); urv->need_free = 1; } struct uwsgi_plugin geoip_plugin = { .name = "geoip", .options = uwsgi_geoip_options, .init = uwsgi_geoip_init, .on_load = register_route_vars_geoip, }; uwsgi-2.0.29/plugins/geoip/uwsgiplugin.py000066400000000000000000000001211477626554400204730ustar00rootroot00000000000000NAME='geoip' CFLAGS = [] LDFLAGS = [] LIBS = ['-lGeoIP'] GCC_LIST = ['geoip'] uwsgi-2.0.29/plugins/gevent/000077500000000000000000000000001477626554400157375ustar00rootroot00000000000000uwsgi-2.0.29/plugins/gevent/gevent.c000066400000000000000000000466131477626554400174050ustar00rootroot00000000000000#include "gevent.h" extern struct uwsgi_server uwsgi; extern struct uwsgi_python up; struct uwsgi_gevent ugevent; static void uwsgi_opt_setup_gevent(char *opt, char *value, void *null) { // set async mode uwsgi_opt_set_int(opt, value, &uwsgi.async); if (uwsgi.socket_timeout < 30) { uwsgi.socket_timeout = 30; } // set loop engine uwsgi.loop = "gevent"; } static struct uwsgi_option gevent_options[] = { {"gevent", required_argument, 0, "a shortcut enabling gevent loop engine with the specified number of async cores and optimal parameters", uwsgi_opt_setup_gevent, NULL, UWSGI_OPT_THREADS}, {"gevent-monkey-patch", no_argument, 0, "call gevent.monkey.patch_all() automatically on startup", uwsgi_opt_true, &ugevent.monkey, 0}, {"gevent-early-monkey-patch", no_argument, 0, "call gevent.monkey.patch_all() automatically before app loading", uwsgi_opt_true, &ugevent.early_monkey, 0}, {"gevent-wait-for-hub", no_argument, 0, "wait for gevent hub's death instead of the control greenlet", uwsgi_opt_true, &ugevent.wait_for_hub, 0}, {0, 0, 0, 0, 0, 0, 0}, }; /* Dumb greenlet used for controlling the shutdown (originally uWSGI only wait for the hub) */ PyObject *py_uwsgi_gevent_ctrl_gl(PyObject *self, PyObject *args) { for(;;) { PyObject *gevent_sleep_args = PyTuple_New(1); PyTuple_SetItem(gevent_sleep_args, 0, PyInt_FromLong(60)); PyObject *gswitch = PyObject_CallObject(ugevent.greenlet_switch, gevent_sleep_args); // could be NULL on exception if (!gswitch) { // just for being paranid if (PyErr_Occurred()) { PyErr_Clear(); break; } } Py_XDECREF(gswitch); Py_DECREF(gevent_sleep_args); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_gevent_graceful(PyObject *self, PyObject *args) { int running_cores = 0; int rounds = 0; uwsgi_log("Gracefully killing worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid); uwsgi.workers[uwsgi.mywid].manage_next_request = 0; if (uwsgi.signal_socket > -1) { uwsgi_log_verbose("stopping gevent signals watchers for worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid); PyObject_CallMethod(ugevent.my_signal_watcher, "stop", NULL); PyObject_CallMethod(ugevent.signal_watcher, "stop", NULL); } uwsgi_log_verbose("stopping gevent sockets watchers for worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid); int i,count = uwsgi_count_sockets(uwsgi.sockets); for(i=0;imethod_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri, wsgi_req->remote_addr_len, wsgi_req->remote_addr); } running_cores++; } } if (running_cores > 0) { uwsgi_log_verbose("waiting for %d running requests on worker %d (pid: %d)...\n", running_cores, uwsgi.mywid, uwsgi.mypid); PyObject *gevent_sleep_args = PyTuple_New(1); PyTuple_SetItem(gevent_sleep_args, 0, PyInt_FromLong(1)); PyObject *gswitch = python_call(ugevent.greenlet_switch, gevent_sleep_args, 0, NULL); Py_DECREF(gswitch); Py_DECREF(gevent_sleep_args); rounds++; goto retry; } if (!ugevent.wait_for_hub) { PyObject_CallMethod(ugevent.ctrl_gl, "kill", NULL); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_gevent_int(PyObject *self, PyObject *args) { uwsgi_log("Brutally killing worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid); uwsgi.workers[uwsgi.mywid].manage_next_request = 0; if (uwsgi.signal_socket > -1) { uwsgi_log_verbose("stopping gevent signals watchers for worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid); PyObject_CallMethod(ugevent.my_signal_watcher, "stop", NULL); PyObject_CallMethod(ugevent.signal_watcher, "stop", NULL); } uwsgi_log_verbose("stopping gevent sockets watchers for worker %d (pid: %d)...\n", uwsgi.mywid, uwsgi.mypid); int i,count = uwsgi_count_sockets(uwsgi.sockets); for(i=0;iasync_id, uwsgi_sock ); // mark core as used uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 1; // accept the connection (since uWSGI 1.5 all of the sockets are non-blocking) if (wsgi_req_simple_accept(wsgi_req, uwsgi_sock->fd)) { free_req_queue; if (uwsgi_sock->retry && uwsgi_sock->retry[wsgi_req->async_id]) { goto edge; } // in case of errors (or thundering herd, just rest it) uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 0; goto clear; } wsgi_req->start_of_request = uwsgi_micros(); wsgi_req->start_of_request_in_sec = wsgi_req->start_of_request/1000000; // enter harakiri mode if (uwsgi.harakiri_options.workers > 0) { set_harakiri(uwsgi.harakiri_options.workers); } // hack to easily pass wsgi_req pointer to the greenlet PyTuple_SetItem(ugevent.greenlet_args, 1, PyLong_FromLong((long)wsgi_req)); // spawn the request greenlet PyObject *new_gl = python_call(ugevent.spawn, ugevent.greenlet_args, 0, NULL); Py_DECREF(new_gl); if (uwsgi_sock->edge_trigger) { #ifdef UWSGI_DEBUG uwsgi_log("i am an edge triggered socket !!!\n"); #endif goto edge; } clear: Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_gevent_request(PyObject * self, PyObject * args) { PyObject *py_wsgi_req = PyTuple_GetItem(args, 0); struct wsgi_request *wsgi_req = (struct wsgi_request *) PyLong_AsLong(py_wsgi_req); PyObject *greenlet_switch = NULL; PyObject *current_greenlet = GET_CURRENT_GREENLET; // another hack to retrieve the current wsgi_req; PyObject_SetAttrString(current_greenlet, "uwsgi_wsgi_req", py_wsgi_req); // if in edge-triggered mode read from socket now !!! if (wsgi_req->socket->edge_trigger) { int status = wsgi_req->socket->proto(wsgi_req); if (status < 0) { goto end2; } goto request; } greenlet_switch = PyObject_GetAttrString(current_greenlet, "switch"); for(;;) { int ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.socket_timeout); wsgi_req->switches++; if (ret <= 0) { goto end; } int status = wsgi_req->socket->proto(wsgi_req); if (status < 0) { goto end; } else if (status == 0) { break; } } request: #ifdef UWSGI_ROUTING if (uwsgi_apply_routes(wsgi_req) == UWSGI_ROUTE_BREAK) { goto end; } #endif for(;;) { if (uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req) <= UWSGI_OK) { goto end; } wsgi_req->switches++; // switch after each yield GEVENT_SWITCH; } end: if (greenlet_switch) { Py_DECREF(greenlet_switch); } end2: Py_DECREF(current_greenlet); uwsgi_close_request(wsgi_req); free_req_queue; if (uwsgi.workers[uwsgi.mywid].manage_next_request == 0) { int running_cores = 0; int i; for(i=0;i)\n"); exit(1); } uwsgi.current_wsgi_req = uwsgi_gevent_current_wsgi_req; PyObject *gevent_dict = get_uwsgi_pydict("gevent"); if (!gevent_dict) uwsgi_pyexit; PyObject *gevent_version = PyDict_GetItemString(gevent_dict, "version_info"); if (!gevent_version) uwsgi_pyexit; if (PyInt_AsLong(PyTuple_GetItem(gevent_version, 0)) < 1) { uwsgi_log("uWSGI requires at least gevent 1.x version\n"); exit(1); } // call gevent.monkey.patch_all() if requested if (ugevent.monkey) { monkey_patch(); } ugevent.spawn = PyDict_GetItemString(gevent_dict, "spawn"); if (!ugevent.spawn) uwsgi_pyexit; ugevent.signal = PyDict_GetItemString(gevent_dict, "signal_handler"); if (!ugevent.signal) { // gevent.signal_handler appears in gevent 1.3. // On older gevent, fall back to the deprecated gevent.signal. ugevent.signal = PyDict_GetItemString(gevent_dict, "signal"); if (!ugevent.signal) uwsgi_pyexit; } ugevent.greenlet_switch = PyDict_GetItemString(gevent_dict, "sleep"); if (!ugevent.greenlet_switch) uwsgi_pyexit; ugevent.greenlet_switch_args = PyTuple_New(0); Py_INCREF(ugevent.greenlet_switch_args); PyObject *gevent_get_hub = PyDict_GetItemString(gevent_dict, "get_hub"); ugevent.hub = python_call(gevent_get_hub, PyTuple_New(0), 0, NULL); if (!ugevent.hub) uwsgi_pyexit; ugevent.get_current = PyDict_GetItemString(gevent_dict, "getcurrent"); if (!ugevent.get_current) uwsgi_pyexit; ugevent.get_current_args = PyTuple_New(0); Py_INCREF(ugevent.get_current_args); ugevent.hub_loop = PyObject_GetAttrString(ugevent.hub, "loop"); if (!ugevent.hub_loop) uwsgi_pyexit; // main greenlet waiting for connection (one greenlet per-socket) PyObject *uwsgi_gevent_main = PyCFunction_New(uwsgi_gevent_main_def, NULL); Py_INCREF(uwsgi_gevent_main); // greenlet to run at each request PyObject *uwsgi_request_greenlet = PyCFunction_New(uwsgi_gevent_request_def, NULL); Py_INCREF(uwsgi_request_greenlet); // pre-fill the greenlet args ugevent.greenlet_args = PyTuple_New(2); PyTuple_SetItem(ugevent.greenlet_args, 0, uwsgi_request_greenlet); if (uwsgi.signal_socket > -1) { // and these are the watcher for signal sockets ugevent.signal_watcher = PyObject_CallMethod(ugevent.hub_loop, "io", "ii", uwsgi.signal_socket, 1); if (!ugevent.signal_watcher) uwsgi_pyexit; ugevent.my_signal_watcher = PyObject_CallMethod(ugevent.hub_loop, "io", "ii", uwsgi.my_signal_socket, 1); if (!ugevent.my_signal_watcher) uwsgi_pyexit; PyObject *uwsgi_greenlet_signal = PyCFunction_New(uwsgi_gevent_signal_def, NULL); Py_INCREF(uwsgi_greenlet_signal); PyObject *uwsgi_greenlet_my_signal = PyCFunction_New(uwsgi_gevent_my_signal_def, NULL); Py_INCREF(uwsgi_greenlet_my_signal); PyObject *uwsgi_greenlet_signal_handler = PyCFunction_New(uwsgi_gevent_signal_handler_def, NULL); Py_INCREF(uwsgi_greenlet_signal_handler); ugevent.signal_args = PyTuple_New(2); PyTuple_SetItem(ugevent.signal_args, 0, uwsgi_greenlet_signal_handler); // start the two signal watchers if (!PyObject_CallMethod(ugevent.signal_watcher, "start", "O", uwsgi_greenlet_signal)) uwsgi_pyexit; if (!PyObject_CallMethod(ugevent.my_signal_watcher, "start", "O", uwsgi_greenlet_my_signal)) uwsgi_pyexit; } // start a greenlet for each socket ugevent.watchers = uwsgi_malloc(sizeof(PyObject *) * uwsgi_count_sockets(uwsgi.sockets)); int i = 0; while(uwsgi_sock) { // this is the watcher for server socket ugevent.watchers[i] = PyObject_CallMethod(ugevent.hub_loop, "io", "ii", uwsgi_sock->fd, 1); if (!ugevent.watchers[i]) uwsgi_pyexit; // start the main greenlet PyObject_CallMethod(ugevent.watchers[i], "start", "Ol", uwsgi_gevent_main,(long)uwsgi_sock); uwsgi_sock = uwsgi_sock->next; i++; } // patch goodbye_cruel_world uwsgi.gbcw_hook = uwsgi_gevent_gbcw; // map SIGHUP with gevent.signal PyObject *ge_signal_tuple = PyTuple_New(2); PyTuple_SetItem(ge_signal_tuple, 0, PyInt_FromLong(SIGHUP)); PyObject *uwsgi_gevent_unix_signal_handler = PyCFunction_New(uwsgi_gevent_unix_signal_handler_def, NULL); Py_INCREF(uwsgi_gevent_unix_signal_handler); PyTuple_SetItem(ge_signal_tuple, 1, uwsgi_gevent_unix_signal_handler); python_call(ugevent.signal, ge_signal_tuple, 0, NULL); // map SIGINT/SIGTERM with gevent.signal ge_signal_tuple = PyTuple_New(2); PyTuple_SetItem(ge_signal_tuple, 0, PyInt_FromLong(SIGINT)); PyObject *uwsgi_gevent_unix_signal_int_handler = PyCFunction_New(uwsgi_gevent_unix_signal_int_handler_def, NULL); Py_INCREF(uwsgi_gevent_unix_signal_int_handler); PyTuple_SetItem(ge_signal_tuple, 1, uwsgi_gevent_unix_signal_int_handler); python_call(ugevent.signal, ge_signal_tuple, 0, NULL); ge_signal_tuple = PyTuple_New(2); PyTuple_SetItem(ge_signal_tuple, 0, PyInt_FromLong(SIGTERM)); PyTuple_SetItem(ge_signal_tuple, 1, uwsgi_gevent_unix_signal_int_handler); python_call(ugevent.signal, ge_signal_tuple, 0, NULL); PyObject *wait_for_me = ugevent.hub; if (!ugevent.wait_for_hub) { // spawn the control greenlet PyObject *uwsgi_greenlet_ctrl_gl_handler = PyCFunction_New(uwsgi_gevent_ctrl_gl_def, NULL); Py_INCREF(uwsgi_greenlet_ctrl_gl_handler); PyObject *ctrl_gl_args = PyTuple_New(1); PyTuple_SetItem(ctrl_gl_args, 0, uwsgi_greenlet_ctrl_gl_handler); ugevent.ctrl_gl = python_call(ugevent.spawn, ctrl_gl_args, 0, NULL); Py_INCREF(ugevent.ctrl_gl); wait_for_me = ugevent.ctrl_gl; } for(;;) { if (!PyObject_CallMethod(wait_for_me, "join", NULL)) { PyErr_Print(); } else { break; } } // no need to worry about freeing memory PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi"); if (uwsgi_dict) { PyObject *ae = PyDict_GetItemString(uwsgi_dict, "atexit"); if (ae) { python_call(ae, PyTuple_New(0), 0, NULL); } } if (uwsgi.workers[uwsgi.mywid].manage_next_request == 0) { uwsgi_log("goodbye to the gevent Hub on worker %d (pid: %d)\n", uwsgi.mywid, uwsgi.mypid); if (ugevent.destroy) { exit(0); } exit(UWSGI_RELOAD_CODE); } uwsgi_log("the gevent Hub is no more :(\n"); } static void gevent_preinit_apps() { // call gevent.monkey.patch_all() if requested if (ugevent.early_monkey) { monkey_patch(); } } static void gevent_init() { uwsgi_register_loop( (char *) "gevent", gevent_loop); } struct uwsgi_plugin gevent_plugin = { .name = "gevent", .options = gevent_options, .preinit_apps = gevent_preinit_apps, .on_load = gevent_init, }; uwsgi-2.0.29/plugins/gevent/gevent.h000066400000000000000000000046111477626554400174020ustar00rootroot00000000000000#include "../python/uwsgi_python.h" int uwsgi_gevent_wait_write_hook(int, int); int uwsgi_gevent_wait_read_hook(int, int); int uwsgi_gevent_wait_milliseconds_hook(int); #define GEVENT_SWITCH PyObject *gswitch = python_call(ugevent.greenlet_switch, ugevent.greenlet_switch_args, 0, NULL); if (gswitch) { Py_DECREF(gswitch); } #define GET_CURRENT_GREENLET python_call(ugevent.get_current, ugevent.get_current_args, 0, NULL) #define free_req_queue uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = wsgi_req #define stop_the_watchers if (timer) { ret = PyObject_CallMethod(timer, "stop", NULL);\ if (ret) { Py_DECREF(ret); } }\ ret = PyObject_CallMethod(watcher, "stop", NULL);\ if (ret) { Py_DECREF(ret); } #define stop_the_watchers_and_clear stop_the_watchers\ Py_DECREF(current); Py_DECREF(current_greenlet);\ Py_DECREF(watcher);\ if (timer) {Py_DECREF(timer);} #define stop_the_io ret = PyObject_CallMethod(watcher, "stop", NULL);\ if (ret) { Py_DECREF(ret); } #define stop_the_io_and_clear stop_the_io;\ Py_DECREF(current); Py_DECREF(current_greenlet);\ Py_DECREF(watcher);\ #define stop_the_c_watchers if (c_watchers) { int j;\ for(j=0;j #include extern struct uwsgi_server uwsgi; /* Author: Roberto De Ioris --glusterfs-mount mountpoint=/foo,server=192.168.173.13:24007;192.168.173.17:0,volfile=foo.vol;volume=unbit001 */ struct uwsgi_plugin glusterfs_plugin; struct uwsgi_glusterfs { int timeout; struct uwsgi_string_list *mountpoints; } uglusterfs; static struct uwsgi_option uwsgi_glusterfs_options[] = { {"glusterfs-mount", required_argument, 0, "virtual mount the specified glusterfs volume in a uri", uwsgi_opt_add_string_list, &uglusterfs.mountpoints, UWSGI_OPT_MIME}, {"glusterfs-timeout", required_argument, 0, "timeout for glusterfs async mode", uwsgi_opt_set_int, &uglusterfs.timeout, 0}, {0, 0, 0, 0, 0, 0, 0}, }; static int uwsgi_glusterfs_read_sync(struct wsgi_request *wsgi_req, glfs_fd_t *fd, size_t remains) { while(remains > 0) { char buf[8192]; ssize_t rlen = glfs_read (fd, buf, UMIN(remains, 8192), 0); if (rlen <= 0) return -1; if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) return -1; remains -= rlen; } return 0; } /* async read of a resource the uwsgi_glusterfs_async_io structure is passed between threads the callback simply signal the main core about the availability of data */ struct uwsgi_glusterfs_async_io { int fd[2]; ssize_t rlen; }; static void uwsgi_glusterfs_read_async_cb(glfs_fd_t *fd, ssize_t rlen, struct glfs_stat *prestat, struct glfs_stat *poststat, void *data) { struct uwsgi_glusterfs_async_io *aio = (struct uwsgi_glusterfs_async_io *) data; #ifdef UWSGI_DEBUG uwsgi_log("[glusterfs-cb] rlen = %d\n", rlen); #endif aio->rlen = rlen; // signal the core if (write(aio->fd[1], "\1", 1) <= 0) { uwsgi_error("uwsgi_glusterfs_read_async_cb()/write()"); } } static int uwsgi_glusterfs_read_async(struct wsgi_request *wsgi_req, glfs_fd_t *fd, size_t remains) { char buf[8192]; struct uwsgi_glusterfs_async_io aio; int ret = -1; if (pipe(aio.fd)) { uwsgi_error("uwsgi_glusterfs_read_async()/pipe()"); return -1; } aio.rlen = -1; while(remains > 0) { // trigger an async read if (glfs_read_async(fd, buf, 8192, 0, uwsgi_glusterfs_read_async_cb, &aio)) goto end; // wait for the callback to be executed if (uwsgi.wait_read_hook(aio.fd[0], uglusterfs.timeout) <= 0) goto end; if (aio.rlen <= 0) goto end; if (uwsgi_response_write_body_do(wsgi_req, buf, aio.rlen)) goto end; remains -= aio.rlen; } ret = 0; end: close(aio.fd[0]); close(aio.fd[1]); return ret; } static int uwsgi_glusterfs_try(struct uwsgi_app *ua, char *node) { int ret = -1; char *colon = strchr(node, ':'); // unix socket if (!colon) { if (glfs_set_volfile_server((glfs_t *)ua->interpreter, "unix", node, 0)) { uwsgi_error("[glusterfs] glfs_set_volfile_server()"); return -1; } goto connect; } *colon = 0; if (glfs_set_volfile_server((glfs_t *)ua->interpreter, "tcp", node, atoi(colon+1))) { uwsgi_error("[glusterfs] glfs_set_volfile_server()"); return -1; } connect: ret = glfs_init((glfs_t *)ua->interpreter); if (ret) { uwsgi_error("[glusterfs] glfs_init()"); } else { if (colon) *colon = ':'; uwsgi_log("[glusterfs] worker %d connected to %s\n", uwsgi.mywid, node); } return ret; } static void uwsgi_glusterfs_connect_do(struct uwsgi_app *ua) { char *servers = uwsgi_str(ua->callable); char *p, *ctx = NULL; uwsgi_foreach_token(servers, ";", p, ctx) { uwsgi_log("[glusterfs] try connect to %s for mountpoint %.*s on worker %d ...\n", p, ua->mountpoint_len, ua->mountpoint, uwsgi.mywid); if (uwsgi_glusterfs_try(ua, p)) { goto end; } } end: free(servers); } static void uwsgi_glusterfs_connect() { int i; // search for all of the glusterfs apps and connect to the server-based ones for (i = 0; i < uwsgi_apps_cnt; i++) { if (uwsgi_apps[i].modifier1 != glusterfs_plugin.modifier1) continue; if (!uwsgi_apps[i].callable) { if (glfs_init((glfs_t *)uwsgi_apps[i].interpreter)) { uwsgi_error("[glusterfs] glfs_init()"); exit(1); } uwsgi_log("[glusterfs] worker %d connected using volfile\n", uwsgi.mywid); continue; } uwsgi_glusterfs_connect_do(&uwsgi_apps[i]); } } static void uwsgi_glusterfs_add_mountpoint(char *arg, size_t arg_len) { char *ugfs_mountpoint = NULL; char *ugfs_server = NULL; char *ugfs_volfile = NULL; char *ugfs_volume = NULL; if (uwsgi_kvlist_parse(arg, arg_len, ',', '=', "mountpoint", &ugfs_mountpoint, "server", &ugfs_server, "servers", &ugfs_server, "volfile", &ugfs_volfile, "volume", &ugfs_volume, NULL)) { uwsgi_log("unable to parse glusterfs mountpoint definition\n"); exit(1); } if (!ugfs_mountpoint || (!ugfs_server && !ugfs_volfile) || !ugfs_volume) { uwsgi_log("[glusterfs] mount requires a mountpoint, a volume and at least one server or volfile\n"); exit(1); } int id = uwsgi_apps_cnt; time_t now = uwsgi_now(); uwsgi_log("[glusterfs] mounting %s ...\n", ugfs_mountpoint); // this should fail only if memory is not available glfs_t *volume = glfs_new(ugfs_volume); if (!volume) { uwsgi_error("unable to initialize glusterfs mountpoint: glfs_new()"); exit(1); } if (ugfs_volfile) { if (glfs_set_volfile(volume, ugfs_volfile)) { uwsgi_error("unable to set glusterfs volfile: glfs_set_volfile\n"); exit(1); } } /* here we pass ugfs_server as the callable field. After fork() if this field is defined we will start trying to connect to each one of the configuratio nodes This is required to have fallback management */ struct uwsgi_app *ua = uwsgi_add_app(id, glusterfs_plugin.modifier1, ugfs_mountpoint, strlen(ugfs_mountpoint), volume, ugfs_server); if (!ua) { uwsgi_log("[glusterfs] unable to mount %s\n", ugfs_mountpoint); exit(1); } ua->started_at = now; ua->startup_time = uwsgi_now() - now; uwsgi_log("GlusterFS app/mountpoint %d (%s) loaded in %d seconds at %p\n", id, ugfs_mountpoint, (int) ua->startup_time, volume); } // we translate the string list to an app representation // this happens before fork() if not in lazy/lazy-apps mode static void uwsgi_glusterfs_setup() { if (!uglusterfs.timeout) { uglusterfs.timeout = uwsgi.socket_timeout; } struct uwsgi_string_list *usl = uglusterfs.mountpoints; while(usl) { uwsgi_glusterfs_add_mountpoint(usl->value, usl->len); usl = usl->next; } } static int uwsgi_glusterfs_request(struct wsgi_request *wsgi_req) { char filename[PATH_MAX+1]; /* Standard GlusterFS request */ if (!wsgi_req->uh->pktsize) { uwsgi_log( "Empty GlusterFS request. skip.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } // blocks empty paths if (wsgi_req->path_info_len == 0 || wsgi_req->path_info_len > PATH_MAX) { uwsgi_403(wsgi_req); return UWSGI_OK; } wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, glusterfs_plugin.modifier1); if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) { if (uwsgi_apps[uwsgi.default_app].modifier1 == glusterfs_plugin.modifier1) { wsgi_req->app_id = uwsgi.default_app; } } if (wsgi_req->app_id == -1) { uwsgi_404(wsgi_req); return UWSGI_OK; } struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id]; memcpy(filename, wsgi_req->path_info, wsgi_req->path_info_len); filename[wsgi_req->path_info_len] = 0; glfs_fd_t *fd = glfs_open((glfs_t *) ua->interpreter, filename, O_RDONLY); if (!fd) { uwsgi_404(wsgi_req); return UWSGI_OK; } struct stat st; if (glfs_fstat(fd, &st)) { uwsgi_403(wsgi_req); return UWSGI_OK; } if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end; size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(wsgi_req->path_info, wsgi_req->path_info_len, &mime_type_len); if (mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end; } if (uwsgi_response_add_last_modified(wsgi_req, (uint64_t) st.st_mtime)) goto end; if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end; // skip body on HEAD if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) { size_t remains = st.st_size; if (uwsgi.async > 1) { if (uwsgi_glusterfs_read_async(wsgi_req, fd, remains)) goto end; } else { if (uwsgi_glusterfs_read_sync(wsgi_req, fd, remains)) goto end; } } end: glfs_close(fd); return UWSGI_OK; } struct uwsgi_plugin glusterfs_plugin = { .name = "glusterfs", .modifier1 = 27, .options = uwsgi_glusterfs_options, .post_fork = uwsgi_glusterfs_setup, .fixup = uwsgi_glusterfs_connect, .request = uwsgi_glusterfs_request, .after_request = log_request, }; uwsgi-2.0.29/plugins/glusterfs/uwsgiplugin.py000066400000000000000000000003351477626554400214150ustar00rootroot00000000000000import os NAME='glusterfs' CFLAGS = os.popen('pkg-config --cflags glusterfs-api').read().rstrip().split() LDFLAGS = [] LIBS = os.popen('pkg-config --libs glusterfs-api').read().rstrip().split() GCC_LIST = ['glusterfs'] uwsgi-2.0.29/plugins/graylog2/000077500000000000000000000000001477626554400161755ustar00rootroot00000000000000uwsgi-2.0.29/plugins/graylog2/graylog2_plugin.c000066400000000000000000000046061477626554400214530ustar00rootroot00000000000000#include "../../uwsgi.h" #include extern struct uwsgi_server uwsgi; #define MAX_GELF 8192 struct graylog2_config { char *host; char json_buf[MAX_GELF]; char escaped_buf[MAX_GELF]; size_t escaped_len; } g2c; ssize_t uwsgi_graylog2_logger(struct uwsgi_logger *ul, char *message, size_t len) { size_t i; if (!ul->configured) { if (!ul->arg) { uwsgi_log_safe("invalid graylog2 syntax\n"); exit(1); } ul->fd = socket(AF_INET, SOCK_DGRAM, 0); if (ul->fd < 0) { uwsgi_error_safe("socket()"); exit(1); } uwsgi_socket_nb(ul->fd); char *comma = strchr(ul->arg, ','); if (!comma) { uwsgi_log_safe("invalid graylog2 syntax\n"); exit(1); } g2c.host = comma + 1; *comma = 0; char *colon = strchr(ul->arg, ':'); if (!colon) { uwsgi_log_safe("invalid graylog2 syntax\n"); exit(1); } ul->addr_len = socket_to_in_addr(ul->arg, colon, 0, &ul->addr.sa_in); *comma = ','; ul->buf = uwsgi_malloc(MAX_GELF); ul->configured = 1; } g2c.escaped_len = 0; int truncated = 0; char *ptr = g2c.escaped_buf; uLongf destLen = MAX_GELF; for(i=0;i 128) { truncated = 2; } } } if (truncated) truncated = 128 - (truncated-1); else (truncated = g2c.escaped_len); int rlen = snprintf(g2c.json_buf, MAX_GELF, "{ \"version\": \"1.0\", \"host\": \"%s\", \"short_message\": \"%.*s\", \"full_message\": \"%.*s\", \"timestamp\": %d, \"level\": 5, \"facility\": \"uWSGI-%s\" }", g2c.host, truncated, g2c.escaped_buf, (int)g2c.escaped_len, g2c.escaped_buf, (int) uwsgi_now(), UWSGI_VERSION); if (rlen > 0 && rlen < MAX_GELF) { if (compressBound((uLong) rlen) <= MAX_GELF) { if (compress((Bytef *) ul->buf, &destLen, (Bytef *) g2c.json_buf, (uLong) rlen) == Z_OK) { return sendto(ul->fd, ul->buf, destLen, 0, (const struct sockaddr *) &ul->addr, ul->addr_len); } } } return -1; } void uwsgi_graylog2_register() { uwsgi_register_logger("graylog2", uwsgi_graylog2_logger); } struct uwsgi_plugin graylog2_plugin = { .name = "graylog2", .on_load = uwsgi_graylog2_register, }; uwsgi-2.0.29/plugins/graylog2/uwsgiplugin.py000066400000000000000000000001301477626554400211160ustar00rootroot00000000000000NAME='graylog2' CFLAGS = [] LDFLAGS = [] LIBS = ['-lz'] GCC_LIST = ['graylog2_plugin'] uwsgi-2.0.29/plugins/greenlet/000077500000000000000000000000001477626554400162545ustar00rootroot00000000000000uwsgi-2.0.29/plugins/greenlet/greenlet.c000066400000000000000000000104401477626554400202240ustar00rootroot00000000000000#include "../python/uwsgi_python.h" #include extern struct uwsgi_server uwsgi; extern struct uwsgi_python up; #define is_not_python(x) strcmp(uwsgi.p[x]->name, "python") struct ugreenlet { int enabled; PyObject *callable; PyGreenlet *main; PyGreenlet **gl; } ugl; static struct uwsgi_option greenlet_options[] = { {"greenlet", no_argument, 0, "enable greenlet as suspend engine", uwsgi_opt_true, &ugl.enabled, 0}, { 0, 0, 0, 0, 0, 0, 0 } }; struct wsgi_request *uwsgi_greenlet_current_wsgi_req(void) { struct wsgi_request *wsgi_req = NULL; PyObject *current_greenlet = (PyObject *)PyGreenlet_GetCurrent(); PyObject *py_wsgi_req = PyObject_GetAttrString(current_greenlet, "uwsgi_wsgi_req"); // not in greenlet if (!py_wsgi_req) { uwsgi_log("[BUG] current_wsgi_req NOT FOUND !!!\n"); goto end; } wsgi_req = (struct wsgi_request*) PyLong_AsLong(py_wsgi_req); Py_DECREF(py_wsgi_req); end: Py_DECREF(current_greenlet); return wsgi_req; } static void gil_greenlet_get() { pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure()); } static void gil_greenlet_release() { PyGILState_Release((PyGILState_STATE) pthread_getspecific(up.upt_gil_key)); } static PyObject *py_uwsgi_greenlet_request(PyObject * self, PyObject *args) { struct wsgi_request *wsgi_req = uwsgi.wsgi_req; async_schedule_to_req_green(); Py_DECREF(ugl.gl[wsgi_req->async_id]); Py_INCREF(Py_None); return Py_None; } PyMethodDef uwsgi_greenlet_request_method[] = {{"uwsgi_greenlet_request", py_uwsgi_greenlet_request, METH_VARARGS, ""}}; static void greenlet_schedule_to_req() { int id = uwsgi.wsgi_req->async_id; uint8_t modifier1 = uwsgi.wsgi_req->uh->modifier1; // ensure gil UWSGI_GET_GIL if (!uwsgi.wsgi_req->suspended) { ugl.gl[id] = PyGreenlet_New(ugl.callable, NULL); PyObject_SetAttrString((PyObject *)ugl.gl[id], "uwsgi_wsgi_req", PyLong_FromLong((long) uwsgi.wsgi_req)); uwsgi.wsgi_req->suspended = 1; } // call it in the main core if (is_not_python(modifier1) && uwsgi.p[modifier1]->suspend) { uwsgi.p[modifier1]->suspend(NULL); } PyObject *ret = PyGreenlet_Switch(ugl.gl[id], NULL, NULL); if (!ret) { PyErr_Print(); uwsgi_log_verbose("[BUG] unable to switch greenlet !!!\n"); exit(1); } Py_DECREF(ret); if (is_not_python(modifier1) && uwsgi.p[modifier1]->resume) { uwsgi.p[modifier1]->resume(NULL); } } static void greenlet_schedule_to_main(struct wsgi_request *wsgi_req) { // ensure gil UWSGI_GET_GIL if (is_not_python(wsgi_req->uh->modifier1) && uwsgi.p[wsgi_req->uh->modifier1]->suspend) { uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req); } PyObject *ret = PyGreenlet_Switch(ugl.main, NULL, NULL); if (!ret) { PyErr_Print(); uwsgi_log_verbose("[BUG] unable to switch greenlet !!!\n"); exit(1); } Py_DECREF(ret); if (is_not_python(wsgi_req->uh->modifier1) && uwsgi.p[wsgi_req->uh->modifier1]->resume) { uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req); } uwsgi.wsgi_req = wsgi_req; } static void greenlet_init_apps(void) { if (!ugl.enabled) return; if (uwsgi.async <= 1) { uwsgi_log("the greenlet suspend engine requires async mode\n"); exit(1); } if (uwsgi.has_threads) { up.gil_get = gil_greenlet_get; up.gil_release = gil_greenlet_release; } // map wsgi_req to greenlet object uwsgi.current_wsgi_req = uwsgi_greenlet_current_wsgi_req; // blindly call it as the stackless gil engine is already set UWSGI_GET_GIL PyGreenlet_Import(); if (PyErr_Occurred()){ PyErr_Print(); exit(1); } ugl.gl = uwsgi_malloc( sizeof(PyGreenlet *) * uwsgi.async ); ugl.main = PyGreenlet_GetCurrent(); Py_INCREF(ugl.main); ugl.callable = PyCFunction_New(uwsgi_greenlet_request_method, NULL); Py_INCREF(ugl.callable); uwsgi_log("enabled greenlet engine\n"); uwsgi.schedule_to_main = greenlet_schedule_to_main; uwsgi.schedule_to_req = greenlet_schedule_to_req; } struct uwsgi_plugin greenlet_plugin = { .name = "greenlet", .init_apps = greenlet_init_apps, .options = greenlet_options, }; uwsgi-2.0.29/plugins/greenlet/uwsgiplugin.py000066400000000000000000000006231477626554400212040ustar00rootroot00000000000000try: from distutils import sysconfig paths = [ sysconfig.get_python_inc(), sysconfig.get_python_inc(plat_specific=True), ] except ImportError: import sysconfig paths = [ sysconfig.get_path('include'), sysconfig.get_path('platinclude'), ] NAME = 'greenlet' CFLAGS = ['-I' + path for path in paths] LDFLAGS = [] LIBS = [] GCC_LIST = ['greenlet'] uwsgi-2.0.29/plugins/gridfs/000077500000000000000000000000001477626554400157255ustar00rootroot00000000000000uwsgi-2.0.29/plugins/gridfs/gridfs.cc000066400000000000000000000222111477626554400175100ustar00rootroot00000000000000#include #include #include struct uwsgi_gridfs_mountpoint { char *mountpoint; uint16_t mountpoint_len; char *server; char *db; char *timeout_str; int timeout; char *no_mime; char *orig_filename; char *md5; char *etag; char *prefix; char *itemname; uint16_t itemname_len; char *skip_slash; uint16_t prefix_len; char *username; char *password; }; struct uwsgi_gridfs { int debug; struct uwsgi_string_list *mountpoints; } ugridfs; struct uwsgi_option uwsgi_gridfs_options[] = { {(char *)"gridfs-mount", required_argument, 0, (char *)"mount a gridfs db on the specified mountpoint", uwsgi_opt_add_string_list, &ugridfs.mountpoints, UWSGI_OPT_MIME}, {(char *)"gridfs-debug", no_argument, 0, (char *)"report gridfs mountpoint and itemname for each request (debug)", uwsgi_opt_true, &ugridfs.debug, UWSGI_OPT_MIME}, {0, 0, 0, 0, 0, 0, 0}, }; extern struct uwsgi_server uwsgi; extern struct uwsgi_plugin gridfs_plugin; static void uwsgi_gridfs_do(struct wsgi_request *wsgi_req, struct uwsgi_gridfs_mountpoint *ugm, char *itemname, int need_free) { try { mongo::scoped_ptr conn( mongo::ScopedDbConnection::getScopedDbConnection(ugm->server, ugm->timeout) ); try { if (ugm->username && ugm->password) { std::string errmsg; if ((*conn).conn().auth(ugm->db, ugm->username, ugm->password, errmsg)) { uwsgi_log("[uwsgi-gridfs]: %s\n", errmsg.c_str()); (*conn).done(); uwsgi_403(wsgi_req); return; } } mongo::GridFS gridfs((*conn).conn(), ugm->db); mongo::GridFile gfile = gridfs.findFile(itemname); if (need_free) { free(itemname); itemname = NULL; } if (!gfile.exists()) { (*conn).done(); uwsgi_404(wsgi_req); return; } uwsgi_response_prepare_headers(wsgi_req, (char *)"200 OK", 6); // first get the content_type (if possibile) std::string filename = gfile.getFilename(); if (!ugm->no_mime) { size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type((char *)filename.c_str(), filename.length(), &mime_type_len); if (mime_type) { uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len); } } if (ugm->orig_filename) { char *filename_header = uwsgi_concat3((char *)"inline; filename=\"", (char *)filename.c_str(), (char *)"\""); uwsgi_response_add_header(wsgi_req, (char *)"Content-Disposition", 19, filename_header, 19 + filename.length()); free(filename_header); } uwsgi_response_add_content_length(wsgi_req, gfile.getContentLength()); char http_last_modified[49]; time_t t = gfile.getUploadDate().toTimeT(); int size = uwsgi_http_date(t, http_last_modified); uwsgi_response_add_header(wsgi_req, (char *)"Last-Modified", 13, http_last_modified, size); if (ugm->etag) { std::string g_md5 = gfile.getMD5(); if (!g_md5.empty()) { char *etag = uwsgi_concat3((char *)"\"", (char *)g_md5.c_str(), (char *)"\""); uwsgi_response_add_header(wsgi_req, (char *)"ETag", 4, etag, 2+g_md5.length()); free(etag); } } if (ugm->md5) { std::string g_md5 = gfile.getMD5(); size_t base64_len = 0; char *base64 = uwsgi_base64_encode((char *)g_md5.c_str(), g_md5.length(), &base64_len); uwsgi_response_add_header(wsgi_req, (char *) "Content-MD5", 11, base64, base64_len); free(base64); } if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, (char *)"HEAD", 4)) { int nc = gfile.getNumChunks(); int i; for(i=0;iprefix, ugm->prefix_len, wsgi_req->path_info+1, wsgi_req->path_info_len-1); } else { itemname = uwsgi_concat2n(ugm->prefix, ugm->prefix_len, wsgi_req->path_info, wsgi_req->path_info_len); } if (ugridfs.debug) { uwsgi_log("[uwsgi-gridfs-debug] itemname = %s\n", itemname); } // itemname will be freed here uwsgi_gridfs_do(wsgi_req, ugm, itemname, 1); return UWSGI_OK; } extern "C" void uwsgi_gridfs_mount() { if (!uwsgi.skip_atexit) { uwsgi_log("*** WARNING libmongoclient could have a bug with atexit() hooks, if you get segfault on end/reload, add --skip-atexit ***\n"); } struct uwsgi_string_list *usl = ugridfs.mountpoints; while(usl) { if (uwsgi_apps_cnt >= uwsgi.max_apps) { uwsgi_log("ERROR: you cannot load more than %d apps in a worker\n", uwsgi.max_apps); exit(1); } int id = uwsgi_apps_cnt; struct uwsgi_gridfs_mountpoint *ugm = uwsgi_gridfs_add_mountpoint(uwsgi_str(usl->value), usl->len); if (!ugm) exit(1); uwsgi_add_app(id, gridfs_plugin.modifier1, ugm->mountpoint, ugm->mountpoint_len, ugm, ugm); uwsgi_emulate_cow_for_apps(id); uwsgi_log("GridFS mountpoint \"%.*s\" (%d) added: server=%s db=%s\n", ugm->mountpoint_len, ugm->mountpoint, id, ugm->server, ugm->db); usl = usl->next; } } #ifdef UWSGI_ROUTING static int uwsgi_routing_func_gridfs(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_gridfs_mountpoint *ugm = (struct uwsgi_gridfs_mountpoint *) ur->data2; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub_itemname = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ugm->itemname, ugm->itemname_len); if (!ub_itemname) return UWSGI_ROUTE_BREAK; if (ugridfs.debug) { uwsgi_log("[uwsgi-gridfs-debug] itemname = %s\n", ub_itemname->buf); } uwsgi_gridfs_do(wsgi_req, ugm, ub_itemname->buf, 0); uwsgi_buffer_destroy(ub_itemname); return UWSGI_ROUTE_BREAK; } extern "C" int uwsgi_router_gridfs(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_gridfs; ur->data = args; ur->data_len = strlen(args); ur->data2 = uwsgi_gridfs_add_mountpoint((char *)ur->data, ur->data_len); if (!ur->data2) { exit(1); } return 0; } #endif uwsgi-2.0.29/plugins/gridfs/plugin.c000066400000000000000000000013171477626554400173710ustar00rootroot00000000000000#include int uwsgi_gridfs_request(struct wsgi_request *); void uwsgi_gridfs_mount(); extern struct uwsgi_option uwsgi_gridfs_options[]; static void uwsgi_gridfs_log(struct wsgi_request *wsgi_req) { log_request(wsgi_req); } #ifdef UWSGI_ROUTING int uwsgi_router_gridfs(struct uwsgi_route *, char *); static void uwsgi_gridfs_register_router() { uwsgi_register_router("gridfs", uwsgi_router_gridfs); } #endif struct uwsgi_plugin gridfs_plugin = { .name = "gridfs", .modifier1 = 25, .init_apps = uwsgi_gridfs_mount, .options = uwsgi_gridfs_options, .request = uwsgi_gridfs_request, .after_request = uwsgi_gridfs_log, #ifdef UWSGI_ROUTING .on_load = uwsgi_gridfs_register_router, #endif }; uwsgi-2.0.29/plugins/gridfs/uwsgiplugin.py000066400000000000000000000005501477626554400206540ustar00rootroot00000000000000import os NAME='gridfs' CFLAGS = ['-I/usr/include/mongo','-I/usr/local/include/mongo'] LDFLAGS = [] LIBS = [] if not 'UWSGI_MONGODB_NOLIB' in os.environ: LIBS.append('-lmongoclient') LIBS.append('-lstdc++') LIBS.append('-lboost_thread') LIBS.append('-lboost_system') LIBS.append('-lboost_filesystem') GCC_LIST = ['plugin', 'gridfs.cc'] uwsgi-2.0.29/plugins/http/000077500000000000000000000000001477626554400154265ustar00rootroot00000000000000uwsgi-2.0.29/plugins/http/common.h000066400000000000000000000102611477626554400170670ustar00rootroot00000000000000#include "../../uwsgi.h" extern struct uwsgi_server uwsgi; #include "../corerouter/cr.h" #ifdef UWSGI_SSL #if !defined(OPENSSL_NO_NEXTPROTONEG) && defined(OPENSSL_NPN_UNSUPPORTED) #ifdef UWSGI_ZLIB #define UWSGI_SPDY #endif #endif #endif struct uwsgi_http { struct uwsgi_corerouter cr; uint8_t modifier1; uint8_t modifier2; struct uwsgi_string_list *http_vars; uint64_t manage_expect; int raw_body; int keepalive; int auto_chunked; int auto_gzip; int websockets; #ifdef UWSGI_SSL char *https_session_context; int https_export_cert; #endif struct uwsgi_string_list *stud_prefix; #ifdef UWSGI_SPDY int spdy_index; struct uwsgi_buffer *spdy3_settings; size_t spdy3_settings_size; #endif int server_name_as_http_host; int headers_timeout; int connect_timeout; int manage_source; int enable_proxy_protocol; int chunked_input; int manage_rtsp; }; struct http_session { struct corerouter_session session; // used for http parser int rnrn; size_t headers_size; size_t remains; size_t content_length; int raw_body; char *port; int port_len; char *request_uri; uint16_t request_uri_len; char *path_info; uint16_t path_info_len; int force_chunked; int websockets; char *websocket_key; uint16_t websocket_key_len; size_t received_body; #ifdef UWSGI_SSL SSL *ssl; X509 *ssl_client_cert; char *ssl_client_dn; BIO *ssl_bio; char *ssl_cc; int force_https; struct uwsgi_buffer *force_ssl_buf; #endif #ifdef UWSGI_SPDY int spdy; int spdy_initialized; int spdy_phase; uint32_t spdy_need; z_stream spdy_z_in; z_stream spdy_z_out; uint8_t spdy_frame_type; uint16_t spdy_control_version; uint16_t spdy_control_type; uint8_t spdy_control_flags; uint32_t spdy_control_length; uint32_t spdy_data_stream_id; uint8_t spdy_data_flags; uint32_t spdy_data_length; struct uwsgi_buffer *spdy_ping; uint32_t spdy_update_window; ssize_t (*spdy_hook)(struct corerouter_peer *); #endif #ifdef UWSGI_ZLIB int can_gzip; int has_gzip; int force_gzip; uint32_t gzip_crc32; uint32_t gzip_size; z_stream z; #endif int send_expect_100; // 1 (family) + 4/16 (addr) char stud_prefix[17]; size_t stud_prefix_remains; size_t stud_prefix_pos; struct uwsgi_buffer *last_chunked; ssize_t (*func_write)(struct corerouter_peer *); int is_rtsp; }; #ifdef UWSGI_SSL #define UWSGI_HTTP_NOSSL 0 #define UWSGI_HTTP_SSL 1 #define UWSGI_HTTP_FORCE_SSL 2 void uwsgi_opt_https(char *, char *, void *); void uwsgi_opt_https2(char *, char *, void *); void uwsgi_opt_http_to_https(char *, char *, void *); ssize_t hr_recv_http_ssl(struct corerouter_peer *); ssize_t hr_read_ssl_body(struct corerouter_peer *); ssize_t hr_write_ssl_response(struct corerouter_peer *); int hr_force_https(struct corerouter_peer *); void hr_session_ssl_close(struct corerouter_session *); ssize_t hr_ssl_read(struct corerouter_peer *); ssize_t hr_ssl_write(struct corerouter_peer *); int hr_https_add_vars(struct http_session *, struct corerouter_peer *, struct uwsgi_buffer *); void hr_setup_ssl(struct http_session *, struct uwsgi_gateway_socket *); #endif #ifdef UWSGI_SPDY int uwsgi_spdy_npn(SSL *ssl, const unsigned char **, unsigned int *, void *); void uwsgi_spdy_info_cb(SSL const *, int, int); ssize_t hr_recv_spdy_control_frame(struct corerouter_peer *); ssize_t spdy_parse(struct corerouter_peer *); void spdy_window_update(char *, uint32_t, uint32_t); #endif ssize_t hs_http_manage(struct corerouter_peer *, ssize_t); ssize_t hr_instance_connected(struct corerouter_peer *); ssize_t hr_instance_write(struct corerouter_peer *); ssize_t hr_instance_read_response(struct corerouter_peer *); ssize_t hr_read_body(struct corerouter_peer *); ssize_t hr_write_body(struct corerouter_peer *); void hr_session_close(struct corerouter_session *); ssize_t http_parse(struct corerouter_peer *); int http_response_parse(struct http_session *, struct uwsgi_buffer *, size_t); uwsgi-2.0.29/plugins/http/http.c000066400000000000000000001061341477626554400165560ustar00rootroot00000000000000/* uWSGI HTTP router */ #include "common.h" struct uwsgi_http uhttp; struct uwsgi_option http_options[] = { {"http", required_argument, 0, "add an http router/server on the specified address", uwsgi_opt_corerouter, &uhttp, 0}, {"httprouter", required_argument, 0, "add an http router/server on the specified address", uwsgi_opt_corerouter, &uhttp, 0}, #ifdef UWSGI_SSL {"https", required_argument, 0, "add an https router/server on the specified address with specified certificate and key", uwsgi_opt_https, &uhttp, 0}, {"https2", required_argument, 0, "add an https/spdy router/server using keyval options", uwsgi_opt_https2, &uhttp, 0}, {"https-export-cert", no_argument, 0, "export uwsgi variable HTTPS_CC containing the raw client certificate", uwsgi_opt_true, &uhttp.https_export_cert, 0}, {"https-session-context", required_argument, 0, "set the session id context to the specified value", uwsgi_opt_set_str, &uhttp.https_session_context, 0}, {"http-to-https", required_argument, 0, "add an http router/server on the specified address and redirect all of the requests to https", uwsgi_opt_http_to_https, &uhttp, 0}, #endif {"http-processes", required_argument, 0, "set the number of http processes to spawn", uwsgi_opt_set_int, &uhttp.cr.processes, 0}, {"http-workers", required_argument, 0, "set the number of http processes to spawn", uwsgi_opt_set_int, &uhttp.cr.processes, 0}, {"http-var", required_argument, 0, "add a key=value item to the generated uwsgi packet", uwsgi_opt_add_string_list, &uhttp.http_vars, 0}, {"http-to", required_argument, 0, "forward requests to the specified node (you can specify it multiple time for lb)", uwsgi_opt_add_string_list, &uhttp.cr.static_nodes, 0 }, {"http-zerg", required_argument, 0, "attach the http router to a zerg server", uwsgi_opt_corerouter_zerg, &uhttp, 0 }, {"http-fallback", required_argument, 0, "fallback to the specified node in case of error", uwsgi_opt_add_string_list, &uhttp.cr.fallback, 0}, {"http-modifier1", required_argument, 0, "set uwsgi protocol modifier1", uwsgi_opt_set_int, &uhttp.modifier1, 0}, {"http-modifier2", required_argument, 0, "set uwsgi protocol modifier2", uwsgi_opt_set_int, &uhttp.modifier2, 0}, {"http-use-cache", optional_argument, 0, "use uWSGI cache as key->value virtualhost mapper", uwsgi_opt_set_str, &uhttp.cr.use_cache, 0}, {"http-use-pattern", required_argument, 0, "use the specified pattern for mapping requests to unix sockets", uwsgi_opt_corerouter_use_pattern, &uhttp, 0}, {"http-use-base", required_argument, 0, "use the specified base for mapping requests to unix sockets", uwsgi_opt_corerouter_use_base, &uhttp, 0}, {"http-events", required_argument, 0, "set the number of concurrent http async events", uwsgi_opt_set_int, &uhttp.cr.nevents, 0}, {"http-subscription-server", required_argument, 0, "enable the subscription server", uwsgi_opt_corerouter_ss, &uhttp, 0}, {"http-subscription-fallback-key", required_argument, 0, "key to use for fallback http handler", uwsgi_opt_corerouter_fallback_key, &uhttp.cr, 0}, {"http-timeout", required_argument, 0, "set internal http socket timeout (default: 60 seconds)", uwsgi_opt_set_int, &uhttp.cr.socket_timeout, 0}, {"http-manage-expect", optional_argument, 0, "manage the Expect HTTP request header (optionally checking for Content-Length)", uwsgi_opt_set_64bit, &uhttp.manage_expect, 0}, {"http-keepalive", optional_argument, 0, "HTTP 1.1 keepalive support (non-pipelined) requests", uwsgi_opt_set_int, &uhttp.keepalive, 0}, {"http-auto-chunked", no_argument, 0, "automatically transform output to chunked encoding during HTTP 1.1 keepalive (if needed)", uwsgi_opt_true, &uhttp.auto_chunked, 0}, #ifdef UWSGI_ZLIB {"http-auto-gzip", no_argument, 0, "automatically gzip content if uWSGI-Encoding header is set to gzip, but content size (Content-Length/Transfer-Encoding) and Content-Encoding are not specified", uwsgi_opt_true, &uhttp.auto_gzip, 0}, #endif {"http-raw-body", no_argument, 0, "blindly send HTTP body to backends (required for WebSockets and Icecast support in backends)", uwsgi_opt_true, &uhttp.raw_body, 0}, {"http-websockets", no_argument, 0, "automatically detect websockets connections and put the session in raw mode", uwsgi_opt_true, &uhttp.websockets, 0}, {"http-chunked-input", no_argument, 0, "automatically detect chunked input requests and put the session in raw mode", uwsgi_opt_true, &uhttp.chunked_input, 0}, {"http-use-code-string", required_argument, 0, "use code string as hostname->server mapper for the http router", uwsgi_opt_corerouter_cs, &uhttp, 0}, {"http-use-socket", optional_argument, 0, "forward request to the specified uwsgi socket", uwsgi_opt_corerouter_use_socket, &uhttp, 0}, {"http-gracetime", required_argument, 0, "retry connections to dead static nodes after the specified amount of seconds", uwsgi_opt_set_int, &uhttp.cr.static_node_gracetime, 0}, {"http-quiet", required_argument, 0, "do not report failed connections to instances", uwsgi_opt_true, &uhttp.cr.quiet, 0}, {"http-cheap", no_argument, 0, "run the http router in cheap mode", uwsgi_opt_true, &uhttp.cr.cheap, 0}, {"http-stats", required_argument, 0, "run the http router stats server", uwsgi_opt_set_str, &uhttp.cr.stats_server, 0}, {"http-stats-server", required_argument, 0, "run the http router stats server", uwsgi_opt_set_str, &uhttp.cr.stats_server, 0}, {"http-ss", required_argument, 0, "run the http router stats server", uwsgi_opt_set_str, &uhttp.cr.stats_server, 0}, {"http-harakiri", required_argument, 0, "enable http router harakiri", uwsgi_opt_set_int, &uhttp.cr.harakiri, 0}, {"http-stud-prefix", required_argument, 0, "expect a stud prefix (1byte family + 4/16 bytes address) on connections from the specified address", uwsgi_opt_add_addr_list, &uhttp.stud_prefix, 0}, {"http-uid", required_argument, 0, "drop http router privileges to the specified uid", uwsgi_opt_uid, &uhttp.cr.uid, 0 }, {"http-gid", required_argument, 0, "drop http router privileges to the specified gid", uwsgi_opt_gid, &uhttp.cr.gid, 0 }, {"http-resubscribe", required_argument, 0, "forward subscriptions to the specified subscription server", uwsgi_opt_add_string_list, &uhttp.cr.resubscribe, 0}, {"http-buffer-size", required_argument, 0, "set internal buffer size (default: page size)", uwsgi_opt_set_64bit, &uhttp.cr.buffer_size, 0}, {"http-server-name-as-http-host", required_argument, 0, "force SERVER_NAME to HTTP_HOST", uwsgi_opt_true, &uhttp.server_name_as_http_host, 0}, {"http-headers-timeout", required_argument, 0, "set internal http socket timeout for headers", uwsgi_opt_set_int, &uhttp.headers_timeout, 0}, {"http-connect-timeout", required_argument, 0, "set internal http socket timeout for backend connections", uwsgi_opt_set_int, &uhttp.connect_timeout, 0}, {"http-manage-source", no_argument, 0, "manage the SOURCE HTTP method placing the session in raw mode", uwsgi_opt_true, &uhttp.manage_source, 0}, {"http-manage-rtsp", no_argument, 0, "manage RTSP sessions", uwsgi_opt_true, &uhttp.manage_rtsp, 0}, {"http-enable-proxy-protocol", optional_argument, 0, "manage PROXY protocol requests", uwsgi_opt_true, &uhttp.enable_proxy_protocol, 0}, {0, 0, 0, 0, 0, 0, 0}, }; static void http_set_timeout(struct corerouter_peer *peer, int timeout) { if (peer->current_timeout == timeout) return; peer->current_timeout = timeout; peer->timeout = corerouter_reset_timeout(peer->session->corerouter, peer); } static char * http_header_to_cgi(char *hh, size_t hhlen, size_t *keylen, size_t *vallen, int *has_prefix) { size_t i; char *val = hh; int status = 0; for (i = 0; i < hhlen; i++) { if (!status) { hh[i] = toupper((int) hh[i]); if (hh[i] == '-') hh[i] = '_'; if (hh[i] == ':') { status = 1; *keylen = i; } } else if (status == 1 && hh[i] != ' ') { status = 2; val += i; *vallen+=1; } else if (status == 2) { *vallen+=1; } } if (!(*keylen)) return NULL; if (uwsgi_strncmp("CONTENT_LENGTH", 14, hh, *keylen) && uwsgi_strncmp("CONTENT_TYPE", 12, hh, *keylen)) { *has_prefix = 0x02; } return val; } static int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, size_t keylen, char *val, size_t vallen, int prefix) { struct uwsgi_buffer *out = peer->out; struct http_session *hr = (struct http_session *) peer->session; if (hr->websockets) { if (!uwsgi_strncmp("UPGRADE", 7, hh, keylen)) { if (!uwsgi_strnicmp(val, vallen, "websocket", 9)) { hr->websockets++; } goto done; } else if (!uwsgi_strncmp("CONNECTION", 10, hh, keylen)) { if (!uwsgi_strnicmp(val, vallen, "Upgrade", 7)) { hr->websockets++; } goto done; } else if (!uwsgi_strncmp("SEC_WEBSOCKET_VERSION", 21, hh, keylen)) { hr->websockets++; goto done; } else if (!uwsgi_strncmp("SEC_WEBSOCKET_KEY", 17, hh, keylen)) { hr->websocket_key = val; hr->websocket_key_len = vallen; goto done; } } if (!uwsgi_strncmp("HOST", 4, hh, keylen)) { if (vallen <= 0xff) { memcpy(peer->key, val, vallen); peer->key_len = vallen; if (uhttp.server_name_as_http_host && uwsgi_buffer_append_keyval(out, "SERVER_NAME", 11, peer->key, peer->key_len)) return -1; } else { return -1; } } else if (!uwsgi_strncmp("CONTENT_LENGTH", 14, hh, keylen)) { hr->content_length = uwsgi_str_num(val, vallen); } // in the future we could support chunked requests... else if (!uwsgi_strncmp("TRANSFER_ENCODING", 17, hh, keylen)) { hr->session.can_keepalive = 0; if (uhttp.chunked_input) { if (!uwsgi_strnicmp(val, vallen, "chunked", 7)) { hr->raw_body = 1; } } } else if (!uwsgi_strncmp("CONNECTION", 10, hh, keylen)) { if (!uwsgi_strnicmp(val, vallen, "close", 5) || !uwsgi_strnicmp(val, vallen, "upgrade", 7)) { hr->session.can_keepalive = 0; } } else if (peer->key == uwsgi.hostname && hr->raw_body && !uwsgi_strncmp("ICE_URL", 7, hh, keylen)) { if (vallen <= 0xff) { memcpy(peer->key, val, vallen); peer->key_len = vallen; } } #ifdef UWSGI_ZLIB else if (uhttp.auto_gzip && !uwsgi_strncmp("ACCEPT_ENCODING", 15, hh, keylen)) { if ( uwsgi_contains_n(val, vallen, "gzip", 4) ) { hr->can_gzip = 1; } } #endif done: if (prefix) keylen += 5; if (uwsgi_buffer_u16le(out, keylen)) return -1; if (prefix) { if (uwsgi_buffer_append(out, "HTTP_", 5)) return -1; } if (uwsgi_buffer_append(out, hh, keylen - (prefix ? 5 : 0))) return -1; if (uwsgi_buffer_u16le(out, vallen)) return -1; if (uwsgi_buffer_append(out, val, vallen)) return -1; return 0; } int http_headers_parse(struct corerouter_peer *peer) { struct http_session *hr = (struct http_session *) peer->session; char *ptr = peer->session->main_peer->in->buf; char *watermark = ptr + hr->headers_size; char *base = ptr; char *query_string = NULL; char *proxy_src = NULL; char *proxy_dst = NULL; char *proxy_src_port = NULL; char *proxy_dst_port = NULL; uint16_t proxy_src_len = 0; uint16_t proxy_dst_len = 0; uint16_t proxy_src_port_len = 0; uint16_t proxy_dst_port_len = 0; peer->out = uwsgi_buffer_new(uwsgi.page_size); // force this buffer to be destroyed as soon as possibile peer->out_need_free = 1; peer->out->limit = UMAX16; // leave space for the uwsgi header peer->out->pos = 4; peer->out_pos = 0; struct uwsgi_buffer *out = peer->out; int found = 0; if (uwsgi.enable_proxy_protocol || uhttp.enable_proxy_protocol) { ptr = proxy1_parse(ptr, watermark, &proxy_src, &proxy_src_len, &proxy_dst, &proxy_dst_len, &proxy_src_port, &proxy_src_port_len, &proxy_dst_port, &proxy_dst_port_len); base = ptr; } // REQUEST_METHOD while (ptr < watermark) { if (*ptr == ' ') { if (uwsgi_buffer_append_keyval(out, "REQUEST_METHOD", 14, base, ptr - base)) return -1; // on SOURCE METHOD, force raw body if (uhttp.manage_source && !uwsgi_strncmp(base, ptr - base, "SOURCE", 6)) { hr->raw_body = 1; } ptr++; found = 1; break; } else if (*ptr == '\r' || *ptr == '\n') break; ptr++; } // ensure we have a method if (!found) { return -1; } // REQUEST_URI / PATH_INFO / QUERY_STRING base = ptr; found = 0; while (ptr < watermark) { if (*ptr == '?' && !query_string) { // PATH_INFO must be url-decoded !!! if (!hr->path_info) { hr->path_info_len = ptr - base; hr->path_info = uwsgi_malloc(hr->path_info_len); } else { size_t new_path_info = ptr - base; if (new_path_info > hr->path_info_len) { char *tmp_buf = realloc(hr->path_info, new_path_info); if (!tmp_buf) return -1; hr->path_info = tmp_buf; } hr->path_info_len = new_path_info; } http_url_decode(base, &hr->path_info_len, hr->path_info); if (uwsgi_buffer_append_keyval(out, "PATH_INFO", 9, hr->path_info, hr->path_info_len)) return -1; query_string = ptr + 1; } else if (*ptr == ' ') { hr->request_uri = base; hr->request_uri_len = ptr - base; if (uwsgi_buffer_append_keyval(out, "REQUEST_URI", 11, base, ptr - base)) return -1; if (!query_string) { // PATH_INFO must be url-decoded !!! if (!hr->path_info) { hr->path_info_len = ptr - base; hr->path_info = uwsgi_malloc(hr->path_info_len); } else { size_t new_path_info = ptr - base; if (new_path_info > hr->path_info_len) { char *tmp_buf = realloc(hr->path_info, new_path_info); if (!tmp_buf) return -1; hr->path_info = tmp_buf; } hr->path_info_len = new_path_info; } http_url_decode(base, &hr->path_info_len, hr->path_info); if (uwsgi_buffer_append_keyval(out, "PATH_INFO", 9, hr->path_info, hr->path_info_len)) return -1; if (uwsgi_buffer_append_keyval(out, "QUERY_STRING", 12, "", 0)) return -1; } else { if (uwsgi_buffer_append_keyval(out, "QUERY_STRING", 12, query_string, ptr - query_string)) return -1; } ptr++; found = 1; break; } ptr++; } // ensure we have a URI if (!found) { return -1; } // SERVER_PROTOCOL base = ptr; found = 0; while (ptr < watermark) { if (*ptr == '\r') { if (ptr + 1 >= watermark) return 0; if (*(ptr + 1) != '\n') return 0; if (uwsgi_buffer_append_keyval(out, "SERVER_PROTOCOL", 15, base, ptr - base)) return -1; if (uhttp.keepalive && !uwsgi_strncmp("HTTP/1.1", 8, base, ptr-base)) { hr->session.can_keepalive = 1; } if (uhttp.manage_rtsp && !uwsgi_strncmp("RTSP/1.0", 8, base, ptr-base)) { hr->raw_body = 1; hr->is_rtsp = 1; } ptr += 2; found = 1; break; } ptr++; } // ensure we have a protocol if (!found) { return -1; } // SCRIPT_NAME if (uwsgi_buffer_append_keyval(out, "SCRIPT_NAME", 11, "", 0)) return -1; // SERVER_NAME if (!uhttp.server_name_as_http_host && uwsgi_buffer_append_keyval(out, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len)) return -1; memcpy(peer->key, uwsgi.hostname, uwsgi.hostname_len); peer->key_len = uwsgi.hostname_len; // SERVER_PORT if (uwsgi_buffer_append_keyval(out, "SERVER_PORT", 11, hr->port, hr->port_len)) return -1; // UWSGI_ROUTER if (uwsgi_buffer_append_keyval(out, "UWSGI_ROUTER", 12, "http", 4)) return -1; // stud HTTPS if (hr->stud_prefix_pos > 0) { if (uwsgi_buffer_append_keyval(out, "HTTPS", 5, "on", 2)) return -1; } #ifdef UWSGI_SSL if (hr_https_add_vars(hr, peer, out)) return -1; #endif // REMOTE_ADDR if (proxy_src) { if (uwsgi_buffer_append_keyval(out, "REMOTE_ADDR", 11, proxy_src, proxy_src_len)) return -1; if (proxy_src_port) { if (uwsgi_buffer_append_keyval(out, "REMOTE_PORT", 11, proxy_src_port, proxy_src_port_len)) return -1; } } else { if (uwsgi_buffer_append_keyval(out, "REMOTE_ADDR", 11, peer->session->client_address, strlen(peer->session->client_address))) return -1; if (uwsgi_buffer_append_keyval(out, "REMOTE_PORT", 11, peer->session->client_port, strlen(peer->session->client_port))) return -1; } //HEADERS base = ptr; struct uwsgi_string_list *headers = NULL, *usl = NULL; while (ptr < watermark) { if (*ptr == '\r') { if (ptr + 1 >= watermark) break; if (*(ptr + 1) != '\n') break; // multiline header ? if (ptr + 2 < watermark) { if (*(ptr + 2) == ' ' || *(ptr + 2) == '\t') { ptr += 2; continue; } } // this is an hack with dumb/wrong/useless error checking if (uhttp.manage_expect) { if (!uwsgi_strncmp("Expect: 100-continue", 20, base, ptr - base)) { hr->send_expect_100 = 1; } } size_t key_len = 0, value_len = 0; int has_prefix = 0; // last line, do not waste time if (ptr - base == 0) break; char *value = http_header_to_cgi(base, ptr - base, &key_len, &value_len, &has_prefix); if (!value) goto clear; usl = uwsgi_string_list_has_item(headers, base, key_len); // there is already a HTTP header with the same name, let's merge them if (usl) { char *old_value = usl->custom_ptr; usl->custom_ptr = uwsgi_concat3n(old_value, (size_t) usl->custom, ", ", 2, value, value_len); usl->custom += 2 + value_len; if (usl->custom2 & 0x01) free(old_value); usl->custom2 |= 0x01; } else { // add an entry usl = uwsgi_string_new_list(&headers, NULL); usl->value = base; usl->len = key_len; usl->custom_ptr = value; usl->custom = value_len; usl->custom2 = has_prefix; } ptr++; base = ptr + 1; } ptr++; } usl = headers; int broken = 0; while(usl) { if (!broken) { if (http_add_uwsgi_header(peer, usl->value, usl->len, usl->custom_ptr, (size_t) usl->custom, usl->custom2 & 0x02)) broken = 1; } if (usl->custom2 & 0x01) { free(usl->custom_ptr); } struct uwsgi_string_list *tmp_usl = usl; usl = usl->next; free(tmp_usl); } if (broken) return -1; struct uwsgi_string_list *hv = uhttp.http_vars; while (hv) { char *equal = strchr(hv->value, '='); if (equal) { if (uwsgi_buffer_append_keyval(out, hv->value, equal - hv->value, equal + 1, strlen(equal + 1))) return -1; } hv = hv->next; } if (hr->is_rtsp) { if (uwsgi_starts_with("rtsp://", 7, hr->path_info, hr->path_info_len)) { char *slash = memchr(hr->path_info + 7, '/', hr->path_info_len - 7); if (!slash) return -1; if (slash - (hr->path_info + 7) <= 0xff) { peer->key_len = slash - (hr->path_info + 7); memcpy(peer->key, hr->path_info + 7, peer->key_len); // override PATH_INFO if (uwsgi_buffer_append_keyval(out, "PATH_INFO", 9, slash, hr->path_info_len - (7 + peer->key_len))) return -1; } } } return 0; clear: usl = headers; while(usl) { if (usl->custom2 & 0x01) { free(usl->custom_ptr); } struct uwsgi_string_list *tmp_usl = usl; usl = usl->next; free(tmp_usl); } return -1; } int hr_manage_expect_continue(struct corerouter_peer *peer) { struct corerouter_session *cs = peer->session; struct http_session *hr = (struct http_session *) cs; if (uhttp.manage_expect > 1) { if (hr->content_length > uhttp.manage_expect) { if (uwsgi_buffer_append(peer->in, "HTTP/1.1 413 Request Entity Too Large\r\n\r\n", 41)) return -1; hr->session.wait_full_write = 1; goto ready; } } if (uwsgi_buffer_append(peer->in, "HTTP/1.1 100 Continue\r\n\r\n", 25)) return -1; hr->session.connect_peer_after_write = peer; ready: peer->session->main_peer->out = peer->in; peer->session->main_peer->out_pos = 0; cr_write_to_main(peer, hr->func_write); return 0; } ssize_t hr_instance_write(struct corerouter_peer *peer) { ssize_t len = cr_write(peer, "hr_instance_write()"); // end on empty write if (!len) { peer->session->can_keepalive = 0; return 0; } // the chunk has been sent, start (again) reading from client and instances if (cr_write_complete(peer)) { // destroy the buffer used for the uwsgi packet if (peer->out_need_free == 1) { uwsgi_buffer_destroy(peer->out); peer->out_need_free = 0; peer->out = NULL; // reset the main_peer input stream peer->session->main_peer->in->pos = 0; } // reset the stream (main_peer->in = peer->out) else { peer->out->pos = 0; } cr_reset_hooks(peer); #ifdef UWSGI_SPDY struct http_session *hr = (struct http_session *) peer->session; if (hr->spdy) { if (hr->spdy_update_window) { if (uwsgi_buffer_fix(peer->in, 16)) return -1; peer->in->pos = 16; spdy_window_update(peer->in->buf, hr->spdy_update_window, 8192); peer->session->main_peer->out = peer->in; peer->session->main_peer->out_pos = 0; hr->spdy_update_window = 0; cr_write_to_main(peer, hr->func_write); return 1; } return spdy_parse(peer->session->main_peer); } #endif } return len; } // write to the client ssize_t hr_write(struct corerouter_peer *main_peer) { ssize_t len = cr_write(main_peer, "hr_write()"); // end on empty write if (!len) return 0; // ok this response chunk is sent, let's start reading again if (cr_write_complete(main_peer)) { // reset the original read buffer main_peer->out->pos = 0; if (main_peer->session->wait_full_write) { main_peer->session->wait_full_write = 0; return 0; } if (main_peer->session->connect_peer_after_write) { http_set_timeout(main_peer->session->connect_peer_after_write, uhttp.connect_timeout); cr_connect(main_peer->session->connect_peer_after_write, hr_instance_connected); main_peer->session->connect_peer_after_write = NULL; return len; } cr_reset_hooks(main_peer); } return len; } ssize_t hr_instance_connected(struct corerouter_peer* peer) { cr_peer_connected(peer, "hr_instance_connected()"); // set the default timeout http_set_timeout(peer, uhttp.cr.socket_timeout); // we are connected, we cannot retry anymore peer->can_retry = 0; // prepare for write peer->out_pos = 0; // change the write hook (we are already monitoring for write) peer->hook_write = hr_instance_write; // and directly call it (optimistic approach...) return hr_instance_write(peer); } // check if the response allows for keepalive int hr_check_response_keepalive(struct corerouter_peer *peer) { struct http_session *hr = (struct http_session *) peer->session; struct uwsgi_buffer *ub = peer->in; size_t i; for(i=0;ipos;i++) { char c = ub->buf[i]; if (c == '\r' && (peer->r_parser_status == 0 || peer->r_parser_status == 2)) { peer->r_parser_status++; } else if (c == '\r') { peer->r_parser_status = 1; } else if (c == '\n' && peer->r_parser_status == 1) { peer->r_parser_status = 2; } // parsing done else if (c == '\n' && peer->r_parser_status == 3) { // end of headers peer->r_parser_status = 4; if (http_response_parse(hr, ub, i+1)) { return -1; } return 0; } else { peer->r_parser_status = 0; } } return 1; } // data from instance ssize_t hr_instance_read(struct corerouter_peer *peer) { peer->in->limit = UMAX16; if (uwsgi_buffer_ensure(peer->in, uwsgi.page_size)) return -1; struct http_session *hr = (struct http_session *) peer->session; ssize_t len = cr_read(peer, "hr_instance_read()"); if (!len) { // disable keepalive on unread body if (hr->content_length) hr->session.can_keepalive = 0; if (hr->session.can_keepalive) { peer->session->main_peer->disabled = 0; hr->rnrn = 0; #ifdef UWSGI_ZLIB hr->can_gzip = 0; hr->has_gzip = 0; #endif if (uhttp.keepalive > 1) { http_set_timeout(peer->session->main_peer, uhttp.keepalive); } } #ifdef UWSGI_ZLIB if (hr->force_chunked || hr->force_gzip) { #else if (hr->force_chunked) { #endif hr->force_chunked = 0; if (!hr->last_chunked) { hr->last_chunked = uwsgi_buffer_new(5); } #ifdef UWSGI_ZLIB if (hr->force_gzip) { hr->force_gzip = 0; size_t zlen = 0; char *gzipped = uwsgi_deflate(&hr->z, NULL, 0, &zlen); if (!gzipped) return -1; if (uwsgi_buffer_append_chunked(hr->last_chunked, zlen)) {free(gzipped) ; return -1;} if (uwsgi_buffer_append(hr->last_chunked, gzipped, zlen)) {free(gzipped) ; return -1;} free(gzipped); if (uwsgi_buffer_append(hr->last_chunked, "\r\n", 2)) return -1; if (uwsgi_buffer_append_chunked(hr->last_chunked, 8)) return -1; if (uwsgi_buffer_u32le(hr->last_chunked, hr->gzip_crc32)) return -1; if (uwsgi_buffer_u32le(hr->last_chunked, hr->gzip_size)) return -1; if (uwsgi_buffer_append(hr->last_chunked, "\r\n", 2)) return -1; } #endif if (uwsgi_buffer_append(hr->last_chunked, "0\r\n\r\n", 5)) return -1; peer->session->main_peer->out = hr->last_chunked; peer->session->main_peer->out_pos = 0; cr_write_to_main(peer, hr->func_write); if (!hr->session.can_keepalive) { hr->session.wait_full_write = 1; } } else { cr_reset_hooks(peer); } return 0; } // need to parse response headers #ifdef UWSGI_ZLIB if (hr->session.can_keepalive || hr->can_gzip) { #else if (hr->session.can_keepalive) { #endif if (peer->r_parser_status != 4) { int ret = hr_check_response_keepalive(peer); if (ret < 0) return -1; if (ret > 0) { return 1; } } #ifdef UWSGI_ZLIB else if (hr->force_gzip) { size_t zlen = 0; char *gzipped = uwsgi_deflate(&hr->z, peer->in->buf, peer->in->pos, &zlen); if (!gzipped) return -1; hr->gzip_size += peer->in->pos; uwsgi_crc32(&hr->gzip_crc32, peer->in->buf, peer->in->pos); peer->in->pos = 0; if (uwsgi_buffer_insert_chunked(peer->in, 0, zlen)) {free(gzipped); return -1;} if (uwsgi_buffer_append(peer->in, gzipped, zlen)) { free(gzipped); return -1; } free(gzipped); if (uwsgi_buffer_append(peer->in, "\r\n", 2)) return -1; } #endif else if (hr->force_chunked) { peer->in->limit = 0; if (uwsgi_buffer_insert_chunked(peer->in, 0, len)) return -1; if (uwsgi_buffer_append(peer->in, "\r\n", 2)) return -1; peer->in->len = UMIN(peer->in->len, UMAX16); } } // set the input buffer as the main output one peer->session->main_peer->out = peer->in; peer->session->main_peer->out_pos = 0; // set the default hook in case of blocking writes (optimistic approach) cr_write_to_main(peer, hr->func_write); return 1; } ssize_t http_parse(struct corerouter_peer *main_peer) { struct corerouter_session *cs = main_peer->session; struct http_session *hr = (struct http_session *) cs; // is it http body ? if (hr->rnrn == 4) { // something bad happened in keepalive mode... if (!main_peer->session->peers) return -1; if (hr->content_length == 0 && !hr->raw_body) { // ignore data... main_peer->in->pos = 0; return 1; } else { if (hr->content_length) { if (main_peer->in->pos > hr->content_length) { main_peer->in->pos = hr->content_length; hr->content_length = 0; // on pipeline attempt, disable keepalive hr->session.can_keepalive = 0; } else { hr->content_length -= main_peer->in->pos; if (hr->content_length == 0) { main_peer->disabled = 1; // stop reading from the client if (uwsgi_cr_set_hooks(main_peer, NULL, NULL)) return -1; } } } } main_peer->session->peers->out = main_peer->in; main_peer->session->peers->out_pos = 0; cr_write_to_backend(main_peer->session->peers, hr_instance_write); return 1; } // ensure the headers timeout is honoured http_set_timeout(main_peer, uhttp.headers_timeout); // read until \r\n\r\n is found size_t j; size_t len = main_peer->in->pos; char *ptr = main_peer->in->buf; hr->rnrn = 0; for (j = 0; j < len; j++) { if (*ptr == '\r' && (hr->rnrn == 0 || hr->rnrn == 2)) { hr->rnrn++; } else if (*ptr == '\r') { hr->rnrn = 1; } else if (*ptr == '\n' && hr->rnrn == 1) { hr->rnrn = 2; } else if (*ptr == '\n' && hr->rnrn == 3) { hr->rnrn = 4; hr->headers_size = j; // for security if ((j+1) <= len) { hr->remains = len - (j+1); } struct uwsgi_corerouter *ucr = main_peer->session->corerouter; // create a new peer struct corerouter_peer *new_peer = uwsgi_cr_peer_add(main_peer->session); // default hook new_peer->last_hook_read = hr_instance_read; // parse HTTP request if (http_headers_parse(new_peer)) return -1; // check for a valid hostname if (new_peer->key_len == 0) return -1; #ifdef UWSGI_SSL if (hr->force_https) { if (hr_force_https(new_peer)) return -1; break; } #endif // find an instance using the key if (ucr->mapper(ucr, new_peer)) return -1; // check instance if (new_peer->instance_address_len == 0) return -1; // fix modifiers if (uhttp.modifier1) new_peer->modifier1 = uhttp.modifier1; if (uhttp.modifier2) new_peer->modifier2 = uhttp.modifier2; uint16_t pktsize = new_peer->out->pos-4; // fix modifiers new_peer->out->buf[0] = new_peer->modifier1; new_peer->out->buf[3] = new_peer->modifier2; // fix pktsize new_peer->out->buf[1] = (uint8_t) (pktsize & 0xff); new_peer->out->buf[2] = (uint8_t) ((pktsize >> 8) & 0xff); if (hr->remains > 0) { if (hr->content_length < hr->remains) { if (hr->content_length > 0 || !hr->raw_body) hr->remains = hr->content_length; hr->content_length = 0; // we need to avoid problems with pipelined requests hr->session.can_keepalive = 0; } else { hr->content_length -= hr->remains; } if (uwsgi_buffer_append(new_peer->out, main_peer->in->buf + hr->headers_size + 1, hr->remains)) return -1; } if (new_peer->modifier1 == 123) { // reset modifier1 to 0 new_peer->out->buf[0] = 0; hr->raw_body = 1; } if (hr->websockets > 2 && hr->websocket_key_len > 0) { hr->raw_body = 1; } // on raw body, ensure keepalive is disabled if (hr->raw_body) hr->session.can_keepalive = 0; if (hr->session.can_keepalive && hr->content_length == 0) { main_peer->disabled = 1; // stop reading from the client if (uwsgi_cr_set_hooks(main_peer, NULL, NULL)) return -1; } if (hr->send_expect_100) { if (hr_manage_expect_continue(new_peer)) return -1; break; } new_peer->can_retry = 1; // reset main timeout http_set_timeout(main_peer, uhttp.cr.socket_timeout); // set peer timeout http_set_timeout(new_peer, uhttp.connect_timeout); cr_connect(new_peer, hr_instance_connected); break; } else { hr->rnrn = 0; } ptr++; } return 1; } // read from client ssize_t hr_read(struct corerouter_peer *main_peer) { // try to always leave 4k available (this will dinamically increase the buffer...) if (uwsgi_buffer_ensure(main_peer->in, uwsgi.page_size)) return -1; ssize_t len = cr_read(main_peer, "hr_read()"); if (!len) return 0; return http_parse(main_peer); } void hr_session_close(struct corerouter_session *cs) { struct http_session *hr = (struct http_session *) cs; if (hr->path_info) { free(hr->path_info); } if (hr->last_chunked) { uwsgi_buffer_destroy(hr->last_chunked); } #ifdef UWSGI_ZLIB if (hr->z.next_in) { deflateEnd(&hr->z); } #endif } ssize_t hr_recv_stud4(struct corerouter_peer * main_peer) { struct http_session *hr = (struct http_session *) main_peer->session; ssize_t len = read(main_peer->fd, hr->stud_prefix + hr->stud_prefix_pos, hr->stud_prefix_remains - hr->stud_prefix_pos); if (len < 0) { cr_try_again; uwsgi_cr_error(main_peer, "hr_recv_stud4()"); return -1; } hr->stud_prefix_pos += len; if (hr->stud_prefix_pos == hr->stud_prefix_remains) { if (hr->stud_prefix[0] != AF_INET) { uwsgi_cr_log(main_peer, "invalid stud prefix for address family %d\n", hr->stud_prefix[0]); return -1; } // set the passed ip address memcpy(&main_peer->session->client_sockaddr.sa_in.sin_addr, hr->stud_prefix + 1, 4); // optimistic approach main_peer->hook_read = hr_read; return hr_read(main_peer); } return len; } // retry connection to the backend static int hr_retry(struct corerouter_peer *peer) { struct uwsgi_corerouter *ucr = peer->session->corerouter; if (peer->instance_address_len > 0) goto retry; if (ucr->mapper(ucr, peer)) { return -1; } if (peer->instance_address_len == 0) { return -1; } retry: // start async connect (again) http_set_timeout(peer, uhttp.connect_timeout); cr_connect(peer, hr_instance_connected); return 0; } int http_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket *ugs, struct corerouter_session *cs, struct sockaddr *sa, socklen_t s_len) { if (!uhttp.headers_timeout) uhttp.headers_timeout = uhttp.cr.socket_timeout; if (!uhttp.connect_timeout) uhttp.connect_timeout = uhttp.cr.socket_timeout; // set the retry hook cs->retry = hr_retry; struct http_session *hr = (struct http_session *) cs; // default hook cs->main_peer->last_hook_read = hr_read; // headers timeout cs->main_peer->current_timeout = uhttp.headers_timeout; if (uhttp.raw_body) { hr->raw_body = 1; } if (uhttp.websockets) { hr->websockets = 1; } hr->func_write = hr_write; // be sure buffer does not grow over 64k cs->main_peer->in->limit = UMAX16; if (sa && sa->sa_family == AF_INET) { struct uwsgi_string_list *usl = uhttp.stud_prefix; while(usl) { if (!memcmp(&cs->client_sockaddr.sa_in.sin_addr, usl->value, 4)) { hr->stud_prefix_remains = 5; cs->main_peer->last_hook_read = hr_recv_stud4; break; } usl = usl->next; } } hr->port = ugs->port; hr->port_len = ugs->port_len; switch(ugs->mode) { #ifdef UWSGI_SSL case UWSGI_HTTP_SSL: hr_setup_ssl(hr, ugs); break; #endif default: if (uwsgi_cr_set_hooks(cs->main_peer, cs->main_peer->last_hook_read, NULL)) return -1; cs->close = hr_session_close; break; } return 0; } void http_setup() { uhttp.cr.name = uwsgi_str("uWSGI http"); uhttp.cr.short_name = uwsgi_str("http"); } int http_init() { uhttp.cr.session_size = sizeof(struct http_session); uhttp.cr.alloc_session = http_alloc_session; if (uhttp.cr.has_sockets && !uwsgi_corerouter_has_backends(&uhttp.cr)) { if (!uwsgi.sockets) { uwsgi_new_socket(uwsgi_concat2("127.0.0.1:0", "")); } uhttp.cr.use_socket = 1; uhttp.cr.socket_num = 0; } uwsgi_corerouter_init((struct uwsgi_corerouter *) &uhttp); return 0; } struct uwsgi_plugin http_plugin = { .name = "http", .options = http_options, .init = http_init, .on_load = http_setup, }; uwsgi-2.0.29/plugins/http/https.c000066400000000000000000000352661477626554400167500ustar00rootroot00000000000000/* uWSGI HTTPS router */ #include "common.h" #ifdef UWSGI_SSL extern struct uwsgi_http uhttp; // taken from nginx static void hr_ssl_clear_errors() { while (ERR_peek_error()) { (void) ERR_get_error(); } ERR_clear_error(); } void uwsgi_opt_https(char *opt, char *value, void *cr) { struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) cr; char *client_ca = NULL; // build socket, certificate and key file char *sock = uwsgi_str(value); char *crt = strchr(sock, ','); if (!crt) { uwsgi_log("invalid https syntax must be socket,crt,key\n"); exit(1); } *crt = '\0'; crt++; char *key = strchr(crt, ','); if (!key) { uwsgi_log("invalid https syntax must be socket,crt,key\n"); exit(1); } *key = '\0'; key++; char *ciphers = strchr(key, ','); if (ciphers) { *ciphers = '\0'; ciphers++; client_ca = strchr(ciphers, ','); if (client_ca) { *client_ca = '\0'; client_ca++; } } struct uwsgi_gateway_socket *ugs = uwsgi_new_gateway_socket(sock, ucr->name); // ok we have the socket, initialize ssl if required if (!uwsgi.ssl_initialized) { uwsgi_ssl_init(); } // initialize ssl context char *name = uhttp.https_session_context; if (!name) { name = uwsgi_concat3(ucr->short_name, "-", ugs->name); } ugs->ctx = uwsgi_ssl_new_server_context(name, crt, key, ciphers, client_ca); if (!ugs->ctx) { exit(1); } // set the ssl mode ugs->mode = UWSGI_HTTP_SSL; ucr->has_sockets++; } void uwsgi_opt_https2(char *opt, char *value, void *cr) { struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) cr; char *s2_addr = NULL; char *s2_cert = NULL; char *s2_key = NULL; char *s2_ciphers = NULL; char *s2_clientca = NULL; char *s2_spdy = NULL; if (uwsgi_kvlist_parse(value, strlen(value), ',', '=', "addr", &s2_addr, "cert", &s2_cert, "crt", &s2_cert, "key", &s2_key, "ciphers", &s2_ciphers, "clientca", &s2_clientca, "client_ca", &s2_clientca, "spdy", &s2_spdy, NULL)) { uwsgi_log("error parsing --https2 option\n"); exit(1); } if (!s2_addr || !s2_cert || !s2_key) { uwsgi_log("--https2 option needs addr, cert and key items\n"); exit(1); } struct uwsgi_gateway_socket *ugs = uwsgi_new_gateway_socket(s2_addr, ucr->name); // ok we have the socket, initialize ssl if required if (!uwsgi.ssl_initialized) { uwsgi_ssl_init(); } // initialize ssl context char *name = uhttp.https_session_context; if (!name) { name = uwsgi_concat3(ucr->short_name, "-", ugs->name); } #ifdef UWSGI_SPDY if (s2_spdy) { uhttp.spdy_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL); uhttp.spdy3_settings = uwsgi_buffer_new(uwsgi.page_size); if (uwsgi_buffer_append(uhttp.spdy3_settings, "\x80\x03\x00\x04\x01", 5)) goto spdyerror; if (uwsgi_buffer_u24be(uhttp.spdy3_settings, (8 * 2) + 4)) goto spdyerror; if (uwsgi_buffer_u32be(uhttp.spdy3_settings, 2)) goto spdyerror; // SETTINGS_ROUND_TRIP_TIME if (uwsgi_buffer_append(uhttp.spdy3_settings, "\x01\x00\x00\x03", 4)) goto spdyerror; if (uwsgi_buffer_u32be(uhttp.spdy3_settings, 30 * 1000)) goto spdyerror; // SETTINGS_INITIAL_WINDOW_SIZE if (uwsgi_buffer_append(uhttp.spdy3_settings, "\x01\x00\x00\x07", 4)) goto spdyerror; if (uwsgi_buffer_u32be(uhttp.spdy3_settings, 8192)) goto spdyerror; uhttp.spdy3_settings_size = uhttp.spdy3_settings->pos; } #endif ugs->ctx = uwsgi_ssl_new_server_context(name, s2_cert, s2_key, s2_ciphers, s2_clientca); if (!ugs->ctx) { exit(1); } #ifdef UWSGI_SPDY if (s2_spdy) { SSL_CTX_set_info_callback(ugs->ctx, uwsgi_spdy_info_cb); SSL_CTX_set_next_protos_advertised_cb(ugs->ctx, uwsgi_spdy_npn, NULL); } #endif // set the ssl mode ugs->mode = UWSGI_HTTP_SSL; ucr->has_sockets++; return; #ifdef UWSGI_SPDY spdyerror: uwsgi_log("unable to initialize SPDY settings buffers\n"); exit(1); #endif } void uwsgi_opt_http_to_https(char *opt, char *value, void *cr) { struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) cr; char *sock = uwsgi_str(value); char *port = strchr(sock, ','); if (port) { *port = '\0'; port++; } struct uwsgi_gateway_socket *ugs = uwsgi_new_gateway_socket(sock, ucr->name); // set context to the port ugs->ctx = port; // force SSL mode ugs->mode = UWSGI_HTTP_FORCE_SSL; ucr->has_sockets++; } int hr_https_add_vars(struct http_session *hr, struct corerouter_peer *peer, struct uwsgi_buffer *out) { // HTTPS (adapted from nginx) if (hr->session.ugs->mode == UWSGI_HTTP_SSL) { if (uwsgi_buffer_append_keyval(out, "HTTPS", 5, "on", 2)) return -1; #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME const char *servername = SSL_get_servername(hr->ssl, TLSEXT_NAMETYPE_host_name); if (servername && strlen(servername) <= 0xff) { peer->key_len = strlen(servername); memcpy(peer->key, servername, peer->key_len) ; } #endif hr->ssl_client_cert = SSL_get_peer_certificate(hr->ssl); if (hr->ssl_client_cert) { int client_cert_len; unsigned char *client_cert_der = NULL; client_cert_len = i2d_X509(hr->ssl_client_cert, &client_cert_der); if (client_cert_len < 0) return -1; int ret = uwsgi_buffer_append_keyval(out, "HTTPS_CLIENT_CERTIFICATE", 24, (char*)client_cert_der, client_cert_len); OPENSSL_free(client_cert_der); if (ret) return -1; X509_NAME *name = X509_get_subject_name(hr->ssl_client_cert); if (name) { hr->ssl_client_dn = X509_NAME_oneline(name, NULL, 0); if (uwsgi_buffer_append_keyval(out, "HTTPS_DN", 8, hr->ssl_client_dn, strlen(hr->ssl_client_dn))) return -1; } if (uhttp.https_export_cert) { hr->ssl_bio = BIO_new(BIO_s_mem()); if (hr->ssl_bio) { if (PEM_write_bio_X509(hr->ssl_bio, hr->ssl_client_cert) > 0) { size_t cc_len = BIO_pending(hr->ssl_bio); hr->ssl_cc = uwsgi_malloc(cc_len); BIO_read(hr->ssl_bio, hr->ssl_cc, cc_len); if (uwsgi_buffer_append_keyval(out, "HTTPS_CC", 8, hr->ssl_cc, cc_len)) return -1; } } } } } else if (hr->session.ugs->mode == UWSGI_HTTP_FORCE_SSL) { hr->force_https = 1; } return 0; } void hr_session_ssl_close(struct corerouter_session *cs) { hr_session_close(cs); struct http_session *hr = (struct http_session *) cs; if (hr->ssl_client_dn) { OPENSSL_free(hr->ssl_client_dn); } if (hr->ssl_cc) { free(hr->ssl_cc); } if (hr->ssl_bio) { BIO_free(hr->ssl_bio); } if (hr->ssl_client_cert) { X509_free(hr->ssl_client_cert); } #ifdef UWSGI_SPDY if (hr->spdy_ping) { uwsgi_buffer_destroy(hr->spdy_ping); } if (hr->spdy) { deflateEnd(&hr->spdy_z_in); deflateEnd(&hr->spdy_z_out); } #endif // clear the errors (otherwise they could be propagated) hr_ssl_clear_errors(); SSL_free(hr->ssl); } int hr_force_https(struct corerouter_peer *peer) { struct corerouter_session *cs = peer->session; struct http_session *hr = (struct http_session *) cs; if (uwsgi_buffer_append(peer->in, "HTTP/1.1 301 Moved Permanently\r\nLocation: https://", 50)) return -1; char *colon = memchr(peer->key, ':', peer->key_len); if (colon) { if (uwsgi_buffer_append(peer->in, peer->key, colon-peer->key)) return -1; } else { if (uwsgi_buffer_append(peer->in, peer->key, peer->key_len)) return -1; } if (cs->ugs->ctx) { if (uwsgi_buffer_append(peer->in, ":", 1)) return -1; if (uwsgi_buffer_append(peer->in,cs->ugs->ctx, strlen(cs->ugs->ctx))) return -1; } if (uwsgi_buffer_append(peer->in, hr->request_uri, hr->request_uri_len)) return -1; if (uwsgi_buffer_append(peer->in, "\r\n\r\n", 4)) return -1; hr->session.wait_full_write = 1; peer->session->main_peer->out = peer->in; peer->session->main_peer->out_pos = 0; cr_write_to_main(peer, hr->func_write); return 0; } ssize_t hr_ssl_write(struct corerouter_peer *main_peer) { struct corerouter_session *cs = main_peer->session; struct http_session *hr = (struct http_session *) cs; hr_ssl_clear_errors(); int ret = SSL_write(hr->ssl, main_peer->out->buf + main_peer->out_pos, main_peer->out->pos - main_peer->out_pos); if (ret > 0) { main_peer->out_pos += ret; if (main_peer->out->pos == main_peer->out_pos) { // reset the buffer (if needed) main_peer->out->pos = 0; if (main_peer->session->wait_full_write) { main_peer->session->wait_full_write = 0; return 0; } if (main_peer->session->connect_peer_after_write) { cr_connect(main_peer->session->connect_peer_after_write, hr_instance_connected); main_peer->session->connect_peer_after_write = NULL; return ret; } cr_reset_hooks(main_peer); #ifdef UWSGI_SPDY if (hr->spdy) { return spdy_parse(main_peer); } #endif } return ret; } int err = SSL_get_error(hr->ssl, ret); if (err == SSL_ERROR_ZERO_RETURN || err == 0) return 0; if (err == SSL_ERROR_WANT_READ) { cr_reset_hooks_and_read(main_peer, hr_ssl_write); return 1; } else if (err == SSL_ERROR_WANT_WRITE) { cr_write_to_main(main_peer, hr_ssl_write); return 1; } else if (err == SSL_ERROR_SYSCALL) { if (errno != 0) uwsgi_cr_error(main_peer, "hr_ssl_write()"); } else if (err == SSL_ERROR_SSL && uwsgi.ssl_verbose) { ERR_print_errors_fp(stderr); } return -1; } ssize_t hr_ssl_read(struct corerouter_peer *main_peer) { struct corerouter_session *cs = main_peer->session; struct http_session *hr = (struct http_session *) cs; hr_ssl_clear_errors(); // try to always leave 4k available if (uwsgi_buffer_ensure(main_peer->in, uwsgi.page_size)) return -1; int ret = SSL_read(hr->ssl, main_peer->in->buf + main_peer->in->pos, main_peer->in->len - main_peer->in->pos); if (ret > 0) { // fix the buffer main_peer->in->pos += ret; // check for pending data int ret2 = SSL_pending(hr->ssl); if (ret2 > 0) { if (uwsgi_buffer_fix(main_peer->in, main_peer->in->len + ret2 )) { uwsgi_cr_log(main_peer, "cannot fix the buffer to %d\n", main_peer->in->len + ret2); return -1; } if (SSL_read(hr->ssl, main_peer->in->buf + main_peer->in->pos, ret2) != ret2) { uwsgi_cr_log(main_peer, "SSL_read() on %d bytes of pending data failed\n", ret2); return -1; } // fix the buffer main_peer->in->pos += ret2; } #ifdef UWSGI_SPDY if (hr->spdy) { //uwsgi_log("RUNNING THE SPDY PARSER FOR %d bytes\n", main_peer->in->pos); return spdy_parse(main_peer); } #endif return http_parse(main_peer); } int err = SSL_get_error(hr->ssl, ret); if (err == SSL_ERROR_ZERO_RETURN || err == 0) return 0; if (err == SSL_ERROR_WANT_READ) { cr_reset_hooks_and_read(main_peer, hr_ssl_read); return 1; } else if (err == SSL_ERROR_WANT_WRITE) { cr_write_to_main(main_peer, hr_ssl_read); return 1; } else if (err == SSL_ERROR_SYSCALL) { if (errno != 0) uwsgi_cr_error(main_peer, "hr_ssl_read()"); } else if (err == SSL_ERROR_SSL && uwsgi.ssl_verbose) { ERR_print_errors_fp(stderr); } return -1; } ssize_t hr_ssl_shutdown(struct corerouter_peer *peer) { // ensure no hooks are set if (uwsgi_cr_set_hooks(peer, NULL, NULL)) return -1; struct corerouter_session *cs = peer->session; struct http_session *hr = (struct http_session *) cs; hr_ssl_clear_errors(); int ret = SSL_shutdown(hr->ssl); int err = 0; if (ret != 1 && ERR_peek_error()) { err = SSL_get_error(hr->ssl, ret); } // no error, close the connection if (ret == 1 || err == 0 || err == SSL_ERROR_ZERO_RETURN) return 0; if (err == SSL_ERROR_WANT_READ) { if (uwsgi_cr_set_hooks(peer, hr_ssl_shutdown, NULL)) return -1; return 1; } else if (err == SSL_ERROR_WANT_WRITE) { if (uwsgi_cr_set_hooks(peer, NULL, hr_ssl_shutdown)) return -1; return 1; } else if (err == SSL_ERROR_SYSCALL) { if (errno != 0) uwsgi_cr_error(peer, "hr_ssl_shutdown()"); } else if (err == SSL_ERROR_SSL && uwsgi.ssl_verbose) { ERR_print_errors_fp(stderr); } return -1; } void hr_setup_ssl(struct http_session *hr, struct uwsgi_gateway_socket *ugs) { hr->ssl = SSL_new(ugs->ctx); SSL_set_fd(hr->ssl, hr->session.main_peer->fd); SSL_set_accept_state(hr->ssl); #ifdef UWSGI_SPDY SSL_set_ex_data(hr->ssl, uhttp.spdy_index, hr); #endif uwsgi_cr_set_hooks(hr->session.main_peer, hr_ssl_read, NULL); hr->session.main_peer->flush = hr_ssl_shutdown; hr->session.close = hr_session_ssl_close; hr->func_write = hr_ssl_write; } #endif uwsgi-2.0.29/plugins/http/keepalive.c000066400000000000000000000130541477626554400175420ustar00rootroot00000000000000#include "common.h" extern struct uwsgi_http uhttp; #ifdef UWSGI_ZLIB static char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 }; #endif int http_response_parse(struct http_session *hr, struct uwsgi_buffer *ub, size_t len) { size_t i; size_t next = 0; char *buf = ub->buf; int found = 0; // protocol for(i=0;isession.can_keepalive && uwsgi_strncmp("HTTP/1.1", 8, buf, i)) { goto end; } if (i+1 >= len) return -1;; next = i+1; found = 1; break; } } if (!found) goto end; // status found = 0; for(i=next;i= len) return -1; next = i + 1; found = 1; break; } } if (!found) goto end; char *key = NULL; // find first header position for(i=next;i= buf+len) return -1; #ifdef UWSGI_ZLIB if (hr->session.can_keepalive || (uhttp.auto_gzip && hr->can_gzip)) { #else if (hr->session.can_keepalive) { #endif if (!uwsgi_strnicmp(key, colon-key, "Connection", 10)) { has_connection = 1; if (!uwsgi_strnicmp(colon+2, h_len-((colon-key)+2), "close", 5)) { goto end; } } else if (!uwsgi_strnicmp(key, colon-key, "Trailers", 8)) { goto end; } else if (!uwsgi_strnicmp(key, colon-key, "Content-Length", 14)) { has_size = 1; } else if (!uwsgi_strnicmp(key, colon-key, "Transfer-Encoding", 17)) { has_size = 1; } } #ifdef UWSGI_ZLIB if (uhttp.auto_gzip && hr->can_gzip) { if (!uwsgi_strnicmp(key, colon-key, "Content-Encoding", 16)) { hr->can_gzip = 0; } else if (!uwsgi_strnicmp(key, colon-key, "uWSGI-Encoding", 14)) { if (!uwsgi_strnicmp(colon+2, h_len-((colon-key)+2), "gzip", 4)) { hr->has_gzip = 1; } } } #endif key = NULL; h_len = 0; } else { h_len++; } } else { if (buf[i] != '\r' && buf[i] != '\n') { key = buf+i; h_len = 1; } } } if (!has_size) { #ifdef UWSGI_ZLIB if (hr->has_gzip) { hr->force_gzip = 1; if (uwsgi_deflate_init(&hr->z, NULL, 0)) { hr->force_gzip = 0; goto end; } hr->gzip_crc32 = 0; uwsgi_crc32(&hr->gzip_crc32, NULL, 0); hr->gzip_size = 0; char cr = buf[len-2]; char nl = buf[len-1]; if (cr == '\r' && nl == '\n') { if (uwsgi_buffer_insert(ub, len-2, "Transfer-Encoding: chunked\r\n", 28)) return -1; if (uwsgi_buffer_insert(ub, len-2+28, "Content-Encoding: gzip\r\n", 24)) return -1; size_t remains = ub->pos - (len+28+24); if (remains > 0) { size_t zlen = 0; char *ptr = ub->buf + (ub->pos - remains); char *gzipped = uwsgi_deflate(&hr->z, ptr, remains, &zlen); if (!gzipped) return -1; uwsgi_crc32(&hr->gzip_crc32, ptr, remains); hr->gzip_size += remains; ub->pos = len + 28 + 24; if (uwsgi_buffer_append_chunked(ub, zlen + 10)) {free(gzipped); return -1;} if (uwsgi_buffer_append(ub, gzheader, 10)) {free(gzipped); return -1;} if (uwsgi_buffer_append(ub, gzipped, zlen)) {free(gzipped); return -1;} free(gzipped); if (uwsgi_buffer_append(ub, "\r\n", 2)) return -1; } else { if (uwsgi_buffer_append_chunked(ub, 10)) return -1; if (uwsgi_buffer_append(ub, gzheader, 10)) return -1; if (uwsgi_buffer_append(ub, "\r\n", 2)) return -1; } } } else #endif if (hr->session.can_keepalive) { if (uhttp.auto_chunked) { char cr = buf[len-2]; char nl = buf[len-1]; if (cr == '\r' && nl == '\n') { if (uwsgi_buffer_insert(ub, len-2, "Transfer-Encoding: chunked\r\n", 28)) return -1; size_t remains = ub->pos - (len+28); if (remains > 0) { if (uwsgi_buffer_insert_chunked(ub, len + 28, remains)) return -1; if (uwsgi_buffer_append(ub, "\r\n", 2)) return -1; } hr->force_chunked = 1; return 0; } } // avoid iOS making mess... if (!has_connection) { if (uwsgi_buffer_insert(ub, len-2, "Connection: close\r\n", 19)) return -1; } hr->session.can_keepalive = 0; } } return 0; end: hr->session.can_keepalive = 0; return 0; } uwsgi-2.0.29/plugins/http/spdy3.c000066400000000000000000000546471477626554400166540ustar00rootroot00000000000000/* uWSGI SPDY3 router */ #include "common.h" #ifdef UWSGI_SPDY extern struct uwsgi_http uhttp; #include "spdy3.h" static uint8_t spdy_h_read_control(uint8_t *header) { return header[0] >> 7; } static uint16_t spdy_h_read_version(uint8_t *header) { uint16_t ret = 0; uint8_t *ptr = (uint8_t *) &ret; ptr[0] = header[0] & 0x7f; ptr[1] = header[1]; return ntohs(ret); } static uint16_t spdy_h_read_type(uint8_t *header) { uint16_t ret = 0; uint8_t *ptr = (uint8_t *) &ret; ptr[0] = header[2]; ptr[1] = header[3]; return ntohs(ret); } static uint8_t spdy_h_read_flags(uint8_t *header) { return header[4]; } static uint32_t spdy_h_read_length(uint8_t *header) { uint32_t ret = 0; uint8_t *ptr = (uint8_t *) &ret; ptr[1] = header[5]; ptr[2] = header[6]; ptr[3] = header[7]; return ntohl(ret); } static uint32_t spdy_stream_id(uint8_t *body) { uint32_t ret = 0; uint8_t *ptr = (uint8_t *) &ret; ptr[0] = body[0] & 0x7f; ptr[1] = body[1]; ptr[2] = body[2]; ptr[3] = body[3]; return ntohl(ret); } /* static uint32_t spdy_associated_stream_id(uint8_t *body) { uint32_t ret = 0; uint8_t *ptr = (uint8_t *) &ret; ptr[0] = body[4] & 0x7f; ptr[1] = body[5]; ptr[2] = body[6]; ptr[3] = body[7]; return ntohl(ret); } */ static char *spdy_translate(char *buf, uint32_t len, uint16_t *d_len) { uint32_t i; if (len == 0) return NULL; if (buf[0] == ':') { if (!uwsgi_strncmp(buf+1, len-1, "method", 6)) { *d_len = 14; return uwsgi_str("REQUEST_METHOD"); } if (!uwsgi_strncmp(buf+1, len-1, "path", 4)) { *d_len = 11; return uwsgi_str("REQUEST_URI"); } if (!uwsgi_strncmp(buf+1, len-1, "version", 7)) { *d_len = 15; return uwsgi_str("SERVER_PROTOCOL"); } if (!uwsgi_strncmp(buf+1, len-1, "host", 4)) { *d_len = 9; return uwsgi_str("HTTP_HOST"); } if (!uwsgi_strncmp(buf+1, len-1, "scheme", 6)) { *d_len = 12; return uwsgi_str("UWSGI_SCHEME"); } return NULL; } if (!uwsgi_strncmp(buf, len, "content-length", 14)) { *d_len = 14; return uwsgi_str("CONTENT_LENGTH"); } if (!uwsgi_strncmp(buf, len, "content-type", 12)) { *d_len = 12; return uwsgi_str("CONTENT_TYPE"); } char *buf2 = uwsgi_malloc(len + 5); memcpy(buf2, "HTTP_", 5); char *ptr = buf2+5; for(i=0;ipos+=4; int found = 0; // :version for(i=0;i= len) goto end; next = i+1; found = 1; break; } } if (!found) goto end; // :status found = 0; for(i=next;i= len) goto end; next = i + 1; found = 1; break; } } if (!found) goto end; *hh = 2; char *key = NULL; // find first header position for(i=next;i= buf+len) goto end; // tolower !!! size_t j; for(j=0;jcustom_ptr; usl->custom_ptr = uwsgi_concat3n(usl->custom_ptr, usl->custom, "\0", 1, line_value, line_value_len); usl->custom = usl->custom + 1 + line_value_len; free(oldval); } else { // this key is new usl = uwsgi_string_new_list(&hr, key); usl->custom_ptr = line_value; usl->custom = line_value_len; } } else { // this is first key usl = uwsgi_string_new_list(&hr, key); usl->custom_ptr = line_value; usl->custom = line_value_len; } key = NULL; h_len = 0; } else { h_len++; } } else { if (buf[i] != '\r' && buf[i] != '\n') { key = buf+i; h_len = 1; } } } // append all merged header lines to buffer and free memory struct uwsgi_string_list *ohr; while (hr) { if (uwsgi_buffer_append_keyval32(ub, hr->value, hr->len, hr->custom_ptr, hr->custom)) goto end; *hh+=1; ohr = hr; hr = hr->next; free(ohr->custom_ptr); free(ohr); } return ub; end: uwsgi_buffer_destroy(ub); return NULL; } char *spdy_deflate_http_headers(struct http_session *, struct uwsgi_buffer *, size_t *); // be sure to have at least 8 free bytes static void spdy_data_header(char *buf, uint32_t len, uint32_t stream_id) { // stream id buf[3] = (uint8_t) (stream_id & 0xff); buf[2] = (uint8_t) ((stream_id >> 8) & 0xff); buf[1] = (uint8_t) ((stream_id >> 16) & 0xff); buf[0] = (uint8_t) ((stream_id >> 24) & 0xff); // FIN if (len == 0) { buf[4] = 1; } // length buf[7] = (uint8_t) (len & 0xff); buf[6] = (uint8_t) ((len >> 8) & 0xff); buf[5] = (uint8_t) ((len >> 16) & 0xff); } // be sure to have at least 12 free bytes static void spdy_reply_header(char *buf, uint32_t len, uint32_t stream_id) { buf[0] = 0x80; buf[1] = 0x03; buf[2] = 0; buf[3] = 0x02; // flags buf[4] = 0; // length buf[7] = (uint8_t) (len & 0xff); buf[6] = (uint8_t) ((len >> 8) & 0xff); buf[5] = (uint8_t) ((len >> 16) & 0xff); // stream id buf[11] = (uint8_t) (stream_id & 0xff); buf[10] = (uint8_t) ((stream_id >> 8) & 0xff); buf[9] = (uint8_t) ((stream_id >> 16) & 0xff); buf[8] = (uint8_t) ((stream_id >> 24) & 0xff); } // be sure to have at least 16 free bytes void spdy_window_update(char *buf, uint32_t stream_id, uint32_t wsize) { buf[0] = 0x80; buf[1] = 0x03; buf[2] = 0; buf[3] = 0x09; // flags buf[4] = 0; uint32_t len = 8; // length buf[7] = (uint8_t) (len & 0xff); buf[6] = (uint8_t) ((len >> 8) & 0xff); buf[5] = (uint8_t) ((len >> 16) & 0xff); // stream id buf[11] = (uint8_t) (stream_id & 0xff); buf[10] = (uint8_t) ((stream_id >> 8) & 0xff); buf[9] = (uint8_t) ((stream_id >> 16) & 0xff); buf[8] = (uint8_t) ((stream_id >> 24) & 0xff); buf[15] = (uint8_t) (wsize & 0xff); buf[14] = (uint8_t) ((wsize >> 8) & 0xff); buf[13] = (uint8_t) ((wsize >> 16) & 0xff); buf[12] = (uint8_t) ((wsize >> 24) & 0xff); } static ssize_t http_parse_to_spdy(struct corerouter_peer *peer) { size_t i; struct uwsgi_buffer *ub = peer->in; struct uwsgi_buffer *out = peer->out; // reset the out buf (it will hold the spdy frame) out->pos = 0; peer->session->main_peer->out_pos = 0; // end of the stream if (peer->r_parser_status == 5) { return -1; } // send DATA frame if (peer->r_parser_status == 4) { spdy_data_header(out->buf, ub->pos, peer->sid); out->pos = 8; // no need to call append on empty values if (ub->pos > 0) { if (uwsgi_buffer_append(out, ub->buf, ub->pos)) return -1; } else { peer->r_parser_status = 5; } // reset the input buffer ub->pos = 0; return 1; } // try to send REPLY frame for(i=0;ipos;i++) { char c = ub->buf[i]; if (c == '\r' && (peer->r_parser_status == 0 || peer->r_parser_status == 2)) { peer->r_parser_status++; } else if (c == '\r') { peer->r_parser_status = 1; } else if (c == '\n' && peer->r_parser_status == 1) { peer->r_parser_status = 2; } // parsing done else if (c == '\n' && peer->r_parser_status == 3) { peer->r_parser_status = 4; uint32_t hh = 0; struct uwsgi_buffer *h_buf = spdy_http_to_spdy(ub->buf, i, &hh); if (!h_buf) return -1; // put the number of headers on front of the buffer h_buf->buf[3] = (uint8_t) (hh & 0xff); h_buf->buf[2] = (uint8_t) ((hh >> 8) & 0xff); h_buf->buf[1] = (uint8_t) ((hh >> 16) & 0xff); h_buf->buf[0] = (uint8_t) ((hh >> 24) & 0xff); // ok now we need to deflate the buffer size_t cb_len = 0; char *compressed_buf = spdy_deflate_http_headers((struct http_session *) peer->session, h_buf, &cb_len); uwsgi_buffer_destroy(h_buf); if (!compressed_buf) { return -1; } // ok now we need an additional buffer spdy_reply_header(out->buf, 4+cb_len, peer->sid); out->pos = 12; if (uwsgi_buffer_append(out, compressed_buf, cb_len)) { free(compressed_buf); return -1; } free(compressed_buf); // any push request ??? // after all of the pushed requests are sent, we have to come back here... // remains ? if (ub->pos-i > 1) { uint32_t remains = ub->pos-(i+1); if (uwsgi_buffer_append(out, "\0\0\0\0\0\0\0\0", 8)) { return -1; } spdy_data_header(out->buf + (out->pos - 8), remains, peer->sid); if (uwsgi_buffer_append(out, ub->buf+i+1, remains)) { return -1; } } // reset the input buffer ub->pos = 0; return 1; } else { peer->r_parser_status = 0; } } return 0; } ssize_t hr_instance_read_to_spdy(struct corerouter_peer *peer) { ssize_t len = cr_read(peer, "hr_instance_read_to_spdy()"); // do not check for empty packet, as 0 will trigger a data frame len = http_parse_to_spdy(peer); if (len > 0) goto parsed; if (len < 0) { if (peer->r_parser_status == 5) return 0; return -1; } // need more data return 1; parsed: peer->session->main_peer->out = peer->out; peer->session->main_peer->out_pos = 0; cr_write_to_main(peer, hr_ssl_write); return 1; } char *spdy_deflate_http_headers(struct http_session *hr, struct uwsgi_buffer *h_buf, size_t *dlen) { // calculate the amount of bytes needed for output (+30 should be enough) Bytef *dbuf = uwsgi_malloc(h_buf->pos+30); z_stream *z = &hr->spdy_z_out; z->avail_in = h_buf->pos; z->next_in = (Bytef *) h_buf->buf; z->avail_out = h_buf->pos+30; z->next_out = dbuf; if (deflate(z, Z_SYNC_FLUSH) != Z_OK) { free(dbuf); return NULL; } *dlen = z->next_out - dbuf; return (char *) dbuf; } static ssize_t spdy_inflate_http_headers(struct http_session *hr) { Bytef zbuf[4096]; uint8_t *src = (uint8_t *) hr->session.main_peer->in->buf; hr->spdy_z_in.avail_in = hr->spdy_control_length - 10; hr->spdy_z_in.next_in = src + 10; struct uwsgi_buffer *ub = uwsgi_buffer_new(4096); while(hr->spdy_z_in.avail_in > 0) { hr->spdy_z_in.avail_out = 4096; hr->spdy_z_in.next_out = zbuf; int ret = inflate(&hr->spdy_z_in, Z_NO_FLUSH); if (ret == Z_NEED_DICT) { inflateSetDictionary(&hr->spdy_z_in, (Bytef *) SPDY_dictionary_txt, sizeof(SPDY_dictionary_txt)); ret = inflate(&hr->spdy_z_in, Z_NO_FLUSH); } if (ret != Z_OK) { uwsgi_buffer_destroy(ub); return -1; } size_t zlen = hr->spdy_z_in.next_out-zbuf; if (uwsgi_buffer_append(ub, (char *) zbuf, zlen)) { uwsgi_buffer_destroy(ub); return -1; } } if (ub->pos < 4) { uwsgi_buffer_destroy(ub); return -1; } uint32_t headers_num = uwsgi_be32(ub->buf); uint32_t i, watermark = ub->pos, pos = 4; struct corerouter_peer *new_peer = uwsgi_cr_peer_add(&hr->session); new_peer->last_hook_read = hr_instance_read_to_spdy; new_peer->out = uwsgi_buffer_new(uwsgi.page_size); // this will avoid the buffer being destroyed on the first instance write new_peer->out_need_free = 2; // leave space for uwsgi header new_peer->out->pos = 4; new_peer->sid = hr->spdy_data_stream_id; // leave space for header for(i=0;i watermark) { uwsgi_buffer_destroy(ub); return -1; } uint32_t k_len = uwsgi_be32( ub->buf + pos); pos += 4; if (pos + k_len > watermark) { uwsgi_buffer_destroy(ub); return -1; } char *k = ub->buf + pos; pos += k_len; // value if (pos + 4 > watermark) { uwsgi_buffer_destroy(ub); return -1; } uint32_t v_len = uwsgi_be32( ub->buf + pos); pos += 4; if (pos + v_len > watermark) { uwsgi_buffer_destroy(ub); return -1; } char *v = ub->buf + pos; pos += v_len; uint16_t nk_len = 0; char *cgi_name = spdy_translate(k, k_len, &nk_len); if (!cgi_name) { uwsgi_buffer_destroy(ub); return -1; } if (uwsgi_buffer_append_keyval(new_peer->out, cgi_name, nk_len, v, v_len)) { uwsgi_buffer_destroy(ub); return -1; } if (!uwsgi_strncmp(cgi_name, nk_len, "HTTP_HOST", 9)) { if (v_len <= 0xff) { memcpy(new_peer->key, new_peer->out->buf + (new_peer->out->pos - v_len), v_len); new_peer->key_len = v_len; } } else if (!uwsgi_strncmp(cgi_name, nk_len, "REQUEST_URI", 11)) { char *path_info = new_peer->out->buf + (new_peer->out->pos - v_len); uint16_t path_info_len = v_len; char *query_string = memchr(path_info, '?', v_len); if (query_string) { query_string++; path_info_len = (query_string - path_info) -1; uint16_t query_string_len = v_len - (path_info_len + 1); if (uwsgi_buffer_append_keyval(new_peer->out, "QUERY_STRING", 12, query_string, query_string_len)) { free(cgi_name); uwsgi_buffer_destroy(ub); return -1; } } if (uwsgi_buffer_append_keyval(new_peer->out, "PATH_INFO", 9, path_info, path_info_len)) { free(cgi_name); uwsgi_buffer_destroy(ub); return -1; } } free(cgi_name); } uwsgi_buffer_destroy(ub); // find the backend node if (new_peer->key_len == 0) return -1; if (uwsgi_buffer_append_keyval(new_peer->out, "HTTPS", 5, "on", 2)) return -1; if (uwsgi_buffer_append_keyval(new_peer->out, "SPDY", 4, "on", 2)) return -1; if (uwsgi_buffer_append_keynum(new_peer->out, "SPDY.version", 12, 3)) return -1; if (uwsgi_buffer_append_keynum(new_peer->out, "SPDY.stream", 11, new_peer->sid)) return -1; struct uwsgi_corerouter *ucr = hr->session.corerouter; // get instance name if (ucr->mapper(ucr, new_peer )) return -1; if (new_peer->instance_address_len == 0) { return -1; } uint16_t pktsize = new_peer->out->pos-4; // fix modifiers new_peer->out->buf[0] = new_peer->session->main_peer->modifier1; new_peer->out->buf[3] = new_peer->session->main_peer->modifier2; // fix pktsize new_peer->out->buf[1] = (uint8_t) (pktsize & 0xff); new_peer->out->buf[2] = (uint8_t) ((pktsize >> 8) & 0xff); new_peer->can_retry = 1; cr_connect(new_peer, hr_instance_connected); return 1; } ssize_t spdy_manage_settings(struct http_session *hs) { uwsgi_log("settings received !!!\n"); return 1; } ssize_t spdy_manage_syn_stream(struct http_session *hr) { uint8_t *buf = (uint8_t *) hr->session.main_peer->in->buf; hr->spdy_data_stream_id = spdy_stream_id(buf); //uwsgi_log("SYN_STREAM received %u !!!\n", hr->spdy_data_stream_id) ; //uwsgi_log("associated stream %u\n", spdy_associated_stream_id(buf)); return spdy_inflate_http_headers(hr); } ssize_t spdy_manage_rst_stream(struct http_session *hr) { uint8_t *buf = (uint8_t *) hr->session.main_peer->in->buf; hr->spdy_data_stream_id = spdy_stream_id(buf); //uwsgi_log("RST_STREAM received %u !!!\n", hr->spdy_data_stream_id) ; struct corerouter_peer *peer = uwsgi_cr_peer_find_by_sid(&hr->session, hr->spdy_data_stream_id); if (peer) { corerouter_close_peer(hr->session.corerouter, peer); } return 0; } ssize_t spdy_manage_ping(struct http_session *hr) { if (!hr->spdy_ping) { hr->spdy_ping = uwsgi_buffer_new(12); } hr->spdy_ping->pos = 0; if (uwsgi_buffer_append(hr->spdy_ping, hr->session.main_peer->in->buf, 12)) return -1; hr->session.main_peer->out = hr->spdy_ping; hr->session.main_peer->out_pos = 0; cr_write_to_main(hr->session.main_peer, hr_ssl_write); //uwsgi_log("PONG\n"); return 1; } /* read from ssl peer. This must be able to efficiently manage both http and spdy packets when the first chunk is received the spdy field of the session is checked. If it is a spdy packet, the SPDY parser will run... */ #define UWSGI_SPDY_PHASE_HEADER 0 #define UWSGI_SPDY_PHASE_CONTROL 1 #define UWSGI_SPDY_PHASE_DATA 2 ssize_t spdy_parse(struct corerouter_peer *main_peer) { struct corerouter_session *cs = main_peer->session; struct http_session *hr = (struct http_session *) cs; ssize_t ret = -1; if (!hr->spdy_initialized) { hr->spdy_z_in.zalloc = Z_NULL; hr->spdy_z_in.zfree = Z_NULL; hr->spdy_z_in.opaque = Z_NULL; if (inflateInit(&hr->spdy_z_in) != Z_OK) { return -1; } hr->spdy_z_out.zalloc = Z_NULL; hr->spdy_z_out.zfree = Z_NULL; hr->spdy_z_out.opaque = Z_NULL; if (deflateInit(&hr->spdy_z_out, Z_DEFAULT_COMPRESSION) != Z_OK) { return -1; } if (deflateSetDictionary(&hr->spdy_z_out, (Bytef *) SPDY_dictionary_txt, sizeof(SPDY_dictionary_txt)) != Z_OK) { return -1; } cs->can_keepalive = 1; hr->spdy_initialized = 1; hr->spdy_phase = UWSGI_SPDY_PHASE_HEADER; hr->spdy_need = 8; main_peer->out = uhttp.spdy3_settings; main_peer->out->pos = uhttp.spdy3_settings_size; main_peer->out_pos = 0; cr_write_to_main(main_peer, hr_ssl_write); return 1; } for(;;) { size_t len = main_peer->in->pos; if (len == 0) { return 1; } uint8_t *buf = (uint8_t *) main_peer->in->buf; //uwsgi_log("%d bytes available\n", len); switch(hr->spdy_phase) { case UWSGI_SPDY_PHASE_HEADER: if (len >= hr->spdy_need) { hr->spdy_frame_type = spdy_h_read_control(buf); if (hr->spdy_frame_type) { hr->spdy_control_version = spdy_h_read_version(buf); hr->spdy_control_type = spdy_h_read_type(buf); hr->spdy_control_flags = spdy_h_read_flags(buf); hr->spdy_control_length = spdy_h_read_length(buf); hr->spdy_phase = UWSGI_SPDY_PHASE_CONTROL; hr->spdy_need = hr->spdy_control_length; //uwsgi_log("now i need %llu bytes for type %u\n", (unsigned long long) hr->spdy_need, hr->spdy_control_type); } else { hr->spdy_phase = UWSGI_SPDY_PHASE_DATA; hr->spdy_data_stream_id = spdy_stream_id(buf); hr->spdy_control_length = spdy_h_read_length(buf); hr->spdy_need = hr->spdy_control_length; //uwsgi_log("need %llu bytes for stream_id %lu\n", (unsigned long long) hr->spdy_need, hr->spdy_data_stream_id); } if (uwsgi_buffer_decapitate(main_peer->in, 8)) return -1; continue; } return 1; case UWSGI_SPDY_PHASE_CONTROL: if (len >= hr->spdy_need) { switch(hr->spdy_control_type) { // SYN_STREAM case 1: ret = spdy_manage_syn_stream(hr); if (ret == 0) goto goon; if (ret < 0) return -1; goto newframe; // RST_STREAM case 3: ret = spdy_manage_rst_stream(hr); if (ret == 0) goto goon; if (ret < 0) return -1; goto newframe; case 4: //uwsgi_log("settings request...\n"); break; case 6: ret = spdy_manage_ping(hr); if (ret == 0) goto goon; if (ret < 0) return -1; goto newframe; break; case 7: // uwsgi_log("GO AWAY...\n"); break; case 9: // uwsgi_log("window update...\n"); break; default: uwsgi_log("i do not know how to manage type %u\n", hr->spdy_control_type); break; } goon: hr->spdy_phase = UWSGI_SPDY_PHASE_HEADER; hr->spdy_need = 8; if (uwsgi_buffer_decapitate(main_peer->in, hr->spdy_control_length)) return -1; continue; } return 1; case UWSGI_SPDY_PHASE_DATA: if (len >= hr->spdy_need) { struct corerouter_peer *peer = uwsgi_cr_peer_find_by_sid(&hr->session, hr->spdy_data_stream_id); if (!peer) { return -1; } peer->out->pos = 0; if (uwsgi_buffer_append(peer->out, main_peer->in->buf, hr->spdy_need)) return -1; peer->out_pos = 0; hr->spdy_update_window = hr->spdy_data_stream_id; cr_write_to_backend(peer, hr_instance_write); ret = 1; goto newframe; } return 1; default: return -1; } } return -1; newframe: hr->spdy_phase = UWSGI_SPDY_PHASE_HEADER; hr->spdy_need = 8; if (uwsgi_buffer_decapitate(main_peer->in, hr->spdy_control_length)) return -1; return ret; } int uwsgi_spdy_npn(SSL *ssl, const unsigned char **data, unsigned int *len, void *arg) { //*data = (const unsigned char *) "\x06spdy/3\x06spdy/2\x08http/1.1\x08http/1.0"; *data = (const unsigned char *) "\x06spdy/3\x08http/1.1\x08http/1.0"; *len = strlen((const char *) *data); return SSL_TLSEXT_ERR_OK; } void uwsgi_spdy_info_cb(SSL const *ssl, int where, int ret) { if (where & SSL_CB_HANDSHAKE_DONE) { const unsigned char * proto = NULL; unsigned len = 0; SSL_get0_next_proto_negotiated(ssl, &proto, &len); if (len == 6) { if (!memcmp(proto, "spdy/3", 6)) { //uwsgi_log("SPDY 3 !!!\n"); struct http_session *hr = SSL_get_ex_data(ssl, uhttp.spdy_index); hr->spdy = 3; //hr->spdy_hook = hr_recv_spdy_control_frame; } else if (!memcmp(proto, "spdy/2", 6)) { //uwsgi_log("SPDY 2 !!!\n"); struct http_session *hr = SSL_get_ex_data(ssl, uhttp.spdy_index); hr->spdy = 2; //uwsgi_log("SPDY/2\n"); //hr->spdy_hook = hr_recv_spdy_control_frame; } } #if OPENSSL_VERSION_NUMBER < 0x10100000L if (ssl->s3) { ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS; } #endif } } #endif uwsgi-2.0.29/plugins/http/spdy3.h000066400000000000000000000306151477626554400166460ustar00rootroot00000000000000const unsigned char SPDY_dictionary_txt[] = { 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, //\ - - - - o p t i 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, //\ o n s - - - - h 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, //\ e a d - - - - p 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, //\ o s t - - - - p 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, //\ u t - - - - d e 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, //\ l e t e - - - - 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, //\ t r a c e - - - 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, //\ - a c c e p t - 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, //\ - - - a c c e p 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, //\ t - c h a r s e 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, //\ t - - - - a c c 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, //\ e p t - e n c o 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, //\ d i n g - - - - 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, //\ a c c e p t - l 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, //\ a n g u a g e - 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, //\ - - - a c c e p 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, //\ t - r a n g e s 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, //\ - - - - a g e - 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, //\ - - - a l l o w 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, //\ - - - - a u t h 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, //\ o r i z a t i o 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, //\ n - - - - c a c 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, //\ h e - c o n t r 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, //\ o l - - - - c o 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, //\ n n e c t i o n 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, //\ - - - - c o n t 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, //\ e n t - b a s e 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, //\ - - - - c o n t 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, //\ e n t - e n c o 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, //\ d i n g - - - - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, //\ c o n t e n t - 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, //\ l a n g u a g e 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, //\ - - - - c o n t 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, //\ e n t - l e n g 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, //\ t h - - - - c o 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, //\ n t e n t - l o 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, //\ c a t i o n - - 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, //\ - - c o n t e n 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, //\ t - m d 5 - - - 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, //\ - c o n t e n t 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, //\ - r a n g e - - 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, //\ - - c o n t e n 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, //\ t - t y p e - - 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, //\ - - d a t e - - 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, //\ - - e t a g - - 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, //\ - - e x p e c t 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, //\ - - - - e x p i 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, //\ r e s - - - - f 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, //\ r o m - - - - h 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, //\ o s t - - - - i 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, //\ f - m a t c h - 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, //\ - - - i f - m o 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, //\ d i f i e d - s 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, //\ i n c e - - - - 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, //\ i f - n o n e - 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, //\ m a t c h - - - 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, //\ - i f - r a n g 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, //\ e - - - - i f - 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, //\ u n m o d i f i 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, //\ e d - s i n c e 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, //\ - - - - l a s t 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, //\ - m o d i f i e 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, //\ d - - - - l o c 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, //\ a t i o n - - - 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, //\ - m a x - f o r 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, //\ w a r d s - - - 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, //\ - p r a g m a - 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, //\ - - - p r o x y 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, //\ - a u t h e n t 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, //\ i c a t e - - - 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, //\ - p r o x y - a 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, //\ u t h o r i z a 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, //\ t i o n - - - - 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, //\ r a n g e - - - 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, //\ - r e f e r e r 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, //\ - - - - r e t r 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, //\ y - a f t e r - 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, //\ - - - s e r v e 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, //\ r - - - - t e - 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, //\ - - - t r a i l 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, //\ e r - - - - t r 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, //\ a n s f e r - e 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, //\ n c o d i n g - 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, //\ - - - u p g r a 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, //\ d e - - - - u s 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, //\ e r - a g e n t 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, //\ - - - - v a r y 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, //\ - - - - v i a - 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, //\ - - - w a r n i 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, //\ n g - - - - w w 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, //\ w - a u t h e n 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, //\ t i c a t e - - 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, //\ - - m e t h o d 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, //\ - - - - g e t - 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, //\ - - - s t a t u 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, //\ s - - - - 2 0 0 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, //\ - O K - - - - v 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, //\ e r s i o n - - 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, //\ - - H T T P - 1 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, //\ - 1 - - - - u r 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, //\ l - - - - p u b 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, //\ l i c - - - - s 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, //\ e t - c o o k i 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, //\ e - - - - k e e 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, //\ p - a l i v e - 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, //\ - - - o r i g i 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, //\ n 1 0 0 1 0 1 2 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, //\ 0 1 2 0 2 2 0 5 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, //\ 2 0 6 3 0 0 3 0 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, //\ 2 3 0 3 3 0 4 3 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, //\ 0 5 3 0 6 3 0 7 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, //\ 4 0 2 4 0 5 4 0 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, //\ 6 4 0 7 4 0 8 4 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, //\ 0 9 4 1 0 4 1 1 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, //\ 4 1 2 4 1 3 4 1 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, //\ 4 4 1 5 4 1 6 4 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, //\ 1 7 5 0 2 5 0 4 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, //\ 5 0 5 2 0 3 - N 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, //\ o n - A u t h o 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, //\ r i t a t i v e 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, //\ - I n f o r m a 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, //\ t i o n 2 0 4 - 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, //\ N o - C o n t e 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, //\ n t 3 0 1 - M o 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, //\ v e d - P e r m 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, //\ a n e n t l y 4 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, //\ 0 0 - B a d - R 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, //\ e q u e s t 4 0 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, //\ 1 - U n a u t h 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, //\ o r i z e d 4 0 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, //\ 3 - F o r b i d 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, //\ d e n 4 0 4 - N 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, //\ o t - F o u n d 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, //\ 5 0 0 - I n t e 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, //\ r n a l - S e r 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, //\ v e r - E r r o 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, //\ r 5 0 1 - N o t 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, //\ - I m p l e m e 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, //\ n t e d 5 0 3 - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, //\ S e r v i c e - 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, //\ U n a v a i l a 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, //\ b l e J a n - F 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, //\ e b - M a r - A 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, //\ p r - M a y - J 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, //\ u n - J u l - A 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, //\ u g - S e p t - 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, //\ O c t - N o v - 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, //\ D e c - 0 0 - 0 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, //\ 0 - 0 0 - M o n 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, //\ - - T u e - - W 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, //\ e d - - T h u - 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, //\ - F r i - - S a 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, //\ t - - S u n - - 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, //\ G M T c h u n k 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, //\ e d - t e x t - 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, //\ h t m l - i m a 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, //\ g e - p n g - i 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, //\ m a g e - j p g 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, //\ - i m a g e - g 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, //\ i f - a p p l i 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, //\ c a t i o n - x 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, //\ m l - a p p l i 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, //\ c a t i o n - x 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, //\ h t m l - x m l 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, //\ - t e x t - p l 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, //\ a i n - t e x t 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, //\ - j a v a s c r 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, //\ i p t - p u b l 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, //\ i c p r i v a t 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, //\ e m a x - a g e 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, //\ - g z i p - d e 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, //\ f l a t e - s d 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, //\ c h c h a r s e 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, //\ t - u t f - 8 c 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, //\ h a r s e t - i 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, //\ s o - 8 8 5 9 - 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, //\ 1 - u t f - - - 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e //\ - e n q - 0 - }; uwsgi-2.0.29/plugins/http/uwsgiplugin.py000066400000000000000000000001771477626554400203620ustar00rootroot00000000000000 NAME='http' CFLAGS = [] LDFLAGS = [] LIBS = [] REQUIRES = ['corerouter'] GCC_LIST = ['http', 'keepalive', 'https', 'spdy3'] uwsgi-2.0.29/plugins/jvm/000077500000000000000000000000001477626554400152435ustar00rootroot00000000000000uwsgi-2.0.29/plugins/jvm/jvm.h000066400000000000000000000065341477626554400162200ustar00rootroot00000000000000#include #include #include struct uwsgi_jvm { JavaVM *vm; JavaVMInitArgs vm_args; pthread_key_t env; struct uwsgi_string_list *classpath; struct uwsgi_string_list *classes; struct uwsgi_string_list *main_classes; struct uwsgi_string_list *opts; jclass request_body_class; jclass str_class; jclass str_array_class; jclass long_class; jclass int_class; jclass byte_class; jclass bytearray_class; jclass input_stream_class; jclass file_class; jclass hashmap_class; jclass list_class; jclass set_class; jclass iterator_class; jclass bool_class; jclass runtime_exception; jclass io_exception; jmethodID api_signal_handler_mid; jmethodID api_rpc_function_mid; int (*request_handlers[UMAX8])(struct wsgi_request *); int (*request_handlers_setup[UMAX8])(void); }; #define ujvm_env ((JNIEnv*)pthread_getspecific(ujvm.env)) jclass uwsgi_jvm_class(char *); jobject uwsgi_jvm_ref(jobject); void uwsgi_jvm_unref(jobject); int uwsgi_jvm_call_static(jclass, jmethodID, ...); int uwsgi_jvm_call(jobject, jmethodID, ...); void uwsgi_jvm_clear_exception(void); int uwsgi_jvm_exception(void); char *uwsgi_jvm_str2c(jobject); void uwsgi_jvm_throw(char *); void uwsgi_jvm_throw_io(char *); jobject uwsgi_jvm_call_objectA(jobject o, jmethodID mid, jvalue *); void uwsgi_jvm_release_chars(jobject, char *); int uwsgi_jvm_register_request_handler(uint8_t, int (*)(void), int (*)(struct wsgi_request *)); jmethodID uwsgi_jvm_get_static_method_id(jclass, char *, char *); jmethodID uwsgi_jvm_get_static_method_id_quiet(jclass, char *, char *); jobject uwsgi_jvm_str(char *, size_t); jobject uwsgi_jvm_hashmap(void); int uwsgi_jvm_hashmap_put(jobject, jobject, jobject); int uwsgi_jvm_hashmap_has(jobject, jobject); jobject uwsgi_jvm_list(void); int uwsgi_jvm_list_add(jobject, jobject); jobject uwsgi_jvm_call_object(jobject, jmethodID, ...); jobject uwsgi_jvm_call_object_static(jclass, jmethodID, ...); jmethodID uwsgi_jvm_get_method_id(jclass, char *, char *); jmethodID uwsgi_jvm_get_method_id_quiet(jclass, char *, char *); jclass uwsgi_jvm_class_from_object(jobject); jobject uwsgi_jvm_object_class_name(jobject); int uwsgi_jvm_object_is_instance(jobject, jclass); jobject uwsgi_jvm_hashmap_get(jobject, jobject); int uwsgi_jvm_iterator_hasNext(jobject); jobject uwsgi_jvm_iterator_next(jobject); jobject uwsgi_jvm_iterator(jobject); jobject uwsgi_jvm_auto_iterator(jobject); jobject uwsgi_jvm_getKey(jobject); jobject uwsgi_jvm_getValue(jobject); size_t uwsgi_jvm_strlen(jobject); long uwsgi_jvm_number2c(jobject); long uwsgi_jvm_int2c(jobject); long uwsgi_jvm_long2c(jobject); jobject uwsgi_jvm_filename(jobject); void uwsgi_jvm_local_unref(jobject); int uwsgi_jvm_call_bool(jobject, jmethodID, ...); int uwsgi_jvm_consume_input_stream(struct wsgi_request *, size_t, jobject); jobject uwsgi_jvm_num(long); jobject uwsgi_jvm_request_body_input_stream(void); jobject uwsgi_jvm_bool(long); size_t uwsgi_jvm_array_len(jobject); jobject uwsgi_jvm_array_get(jobject, long); int uwsgi_jvm_iterator_to_response_headers(struct wsgi_request *, jobject); jobject uwsgi_jvm_entryset(jobject); int uwsgi_jvm_object_to_response_body(struct wsgi_request *, jobject); jobject uwsgi_jvm_bytearray(char *, size_t); char *uwsgi_jvm_bytearray2c(jobject); void uwsgi_jvm_release_bytearray(jobject, char *); jobject uwsgi_jvm_to_string(jobject); uwsgi-2.0.29/plugins/jvm/jvm_plugin.c000066400000000000000000001236111477626554400175650ustar00rootroot00000000000000#include "jvm.h" /* with javap -s -p you can get method signatures This plugin is the core for all of the JVM-based ones some function (for performance reason) use static vars. They are thread safe in gcc. */ extern struct uwsgi_server uwsgi; struct uwsgi_plugin jvm_plugin; struct uwsgi_jvm ujvm; int uwsgi_jvm_register_request_handler(uint8_t modifier2,int (*setup)(void), int (*func)(struct wsgi_request *)) { if (ujvm.request_handlers[modifier2] || ujvm.request_handlers_setup[modifier2]) { uwsgi_log("JVM request_handler for modifier2 %u already registered !!!\n", modifier2); return -1; } ujvm.request_handlers_setup[modifier2] = setup; ujvm.request_handlers[modifier2] = func; return 0; } JNIEXPORT jint JNICALL uwsgi_jvm_api_worker_id(JNIEnv *env, jclass c) { return uwsgi.mywid; } JNIEXPORT void JNICALL uwsgi_jvm_api_register_signal(JNIEnv *env, jclass c, jint signum, jstring target, jobject handler) { // no need to release it char *t = uwsgi_jvm_str2c(target); if (uwsgi_register_signal(signum, t, uwsgi_jvm_ref(handler), jvm_plugin.modifier1)) { uwsgi_jvm_throw("unable to register signal handler"); } } JNIEXPORT void JNICALL uwsgi_jvm_api_register_rpc(JNIEnv *env, jclass c, jstring name, jobject func) { // no need to release it char *n = uwsgi_jvm_str2c(name); if (uwsgi_register_rpc(n, &jvm_plugin, 0, uwsgi_jvm_ref(func))) { uwsgi_jvm_throw("unable to register rpc function"); } } JNIEXPORT void JNICALL uwsgi_jvm_api_lock_zero(JNIEnv *env, jclass c) { uwsgi_lock(uwsgi.user_lock[0]); } JNIEXPORT void JNICALL uwsgi_jvm_api_unlock_zero(JNIEnv *env, jclass c) { uwsgi_unlock(uwsgi.user_lock[0]); } JNIEXPORT void JNICALL uwsgi_jvm_api_lock(JNIEnv *env, jclass c, jint locknum) { if (locknum < 0 || locknum > uwsgi.locks) { uwsgi_jvm_throw("invalid lock number"); return; } uwsgi_lock(uwsgi.user_lock[locknum]); } JNIEXPORT void JNICALL uwsgi_jvm_api_unlock(JNIEnv *env, jclass c, jint locknum) { if (locknum < 0 || locknum > uwsgi.locks) { uwsgi_jvm_throw("invalid lock number"); return; } uwsgi_unlock(uwsgi.user_lock[locknum]); } JNIEXPORT jobject JNICALL uwsgi_jvm_api_cache_get(JNIEnv *env, jclass c, jstring jkey) { if (!uwsgi.caches) { uwsgi_jvm_throw("cache not available"); return NULL; } size_t keylen = uwsgi_jvm_strlen(jkey); char *key = uwsgi_jvm_str2c(jkey); uint64_t vallen = 0; char *value = uwsgi_cache_magic_get(key, keylen, &vallen, NULL, NULL); uwsgi_jvm_release_chars(jkey, key); if (value) { jobject o = uwsgi_jvm_bytearray(value, vallen); free(value); return o; } return NULL; } JNIEXPORT jobject JNICALL uwsgi_jvm_api_cache_get_name(JNIEnv *env, jclass c, jstring jkey, jstring jcache) { if (!uwsgi.caches) { uwsgi_jvm_throw("cache not available"); return NULL; } size_t keylen = uwsgi_jvm_strlen(jkey); char *key = uwsgi_jvm_str2c(jkey); char *cache = uwsgi_jvm_str2c(jcache); uint64_t vallen = 0; char *value = uwsgi_cache_magic_get(key, keylen, &vallen, NULL, cache); uwsgi_jvm_release_chars(jkey, key); uwsgi_jvm_release_chars(jcache, cache); if (value) { jobject o = uwsgi_jvm_bytearray(value, vallen); free(value); return o; } return NULL; } JNIEXPORT void JNICALL uwsgi_jvm_api_alarm(JNIEnv *env, jclass c, jstring alarm, jstring msg) { char *c_alarm = uwsgi_jvm_str2c(alarm); size_t c_msg_len = uwsgi_jvm_strlen(msg); char *c_msg = uwsgi_jvm_str2c(msg); uwsgi_alarm_trigger(c_alarm, c_msg, c_msg_len); uwsgi_jvm_release_chars(msg, c_msg); uwsgi_jvm_release_chars(alarm, c_alarm); } JNIEXPORT jobject JNICALL uwsgi_jvm_api_rpc(JNIEnv *env, jclass c, jobject j_args) { char *argv[256]; uint16_t argvs[256]; jobject argvj[256]; uint64_t size = 0; size_t args = uwsgi_jvm_array_len(j_args); if (args < 2) return NULL; jobject server = uwsgi_jvm_array_get(j_args, 0); jobject func = uwsgi_jvm_array_get(j_args, 1); size_t i; for(i=0;i<(args-2);i++) { jobject j_arg = uwsgi_jvm_array_get(j_args, i + 2); argvs[i] = uwsgi_jvm_strlen(j_arg); argv[i] = uwsgi_jvm_str2c(j_arg); // need this value to unref later argvj[i] = j_arg; } char *c_server = uwsgi_jvm_str2c(server); char *c_func = uwsgi_jvm_str2c(func); char *response = uwsgi_do_rpc(c_server, c_func, args-2, argv, argvs, &size); uwsgi_jvm_release_chars(func, c_func); uwsgi_jvm_release_chars(server, c_server); uwsgi_jvm_local_unref(server); uwsgi_jvm_local_unref(func); for(i=0;i<(args-2);i++) { uwsgi_jvm_release_chars(argvj[i], argv[i]); uwsgi_jvm_local_unref(argvj[i]); } if (response) { jobject o = uwsgi_jvm_str(response, size); free(response); return o; } return NULL; } static JNINativeMethod uwsgi_jvm_api_methods[] = { {"register_signal", "(ILjava/lang/String;Luwsgi$SignalHandler;)V", (void *) &uwsgi_jvm_api_register_signal}, {"register_rpc", "(Ljava/lang/String;Luwsgi$RpcFunction;)V", (void *) &uwsgi_jvm_api_register_rpc}, {"worker_id", "()I", (void *) &uwsgi_jvm_api_worker_id}, {"lock", "()V", (void *) &uwsgi_jvm_api_lock_zero}, {"unlock", "()V", (void *) &uwsgi_jvm_api_unlock_zero}, {"lock", "(I)V", (void *) &uwsgi_jvm_api_lock}, {"unlock", "(I)V", (void *) &uwsgi_jvm_api_unlock}, {"cache_get", "(Ljava/lang/String;)[B", (void *) &uwsgi_jvm_api_cache_get}, {"cache_get", "(Ljava/lang/String;Ljava/lang/String;)[B", (void *) &uwsgi_jvm_api_cache_get_name}, {"alarm", "(Ljava/lang/String;Ljava/lang/String;)V", (void *) &uwsgi_jvm_api_alarm}, {"rpc", "([Ljava/lang/String;)Ljava/lang/String;", (void *) &uwsgi_jvm_api_rpc}, }; JNIEXPORT jint JNICALL uwsgi_jvm_request_body_read(JNIEnv *env, jobject o) { struct wsgi_request *wsgi_req = current_wsgi_req(); ssize_t rlen = 0; char *chunk = uwsgi_request_body_read(wsgi_req, 1, &rlen); if (!chunk) { uwsgi_jvm_throw_io("error reading request body"); return -1; } if (chunk == uwsgi.empty) { return -1; } uint8_t byte = chunk[0]; return (jint) byte; } JNIEXPORT jint JNICALL uwsgi_jvm_request_body_read_bytearray(JNIEnv *env, jobject o, jobject b) { struct wsgi_request *wsgi_req = current_wsgi_req(); ssize_t rlen = 0; size_t len = uwsgi_jvm_array_len(b); char *chunk = uwsgi_request_body_read(wsgi_req, len, &rlen); if (!chunk) { uwsgi_jvm_throw_io("error reading request body"); return -1; } if (chunk == uwsgi.empty) { return -1; } char *buf = (char *) (*ujvm_env)->GetByteArrayElements(ujvm_env, b, JNI_FALSE); if (!buf) return -1; memcpy(buf, chunk, rlen); (*ujvm_env)->ReleaseByteArrayElements(ujvm_env, b, (jbyte *) buf, 0); return rlen; } JNIEXPORT jint JNICALL uwsgi_jvm_request_body_readline_bytearray(JNIEnv *env, jobject o, jobject b) { struct wsgi_request *wsgi_req = current_wsgi_req(); ssize_t rlen = 0; size_t len = uwsgi_jvm_array_len(b); char *chunk = uwsgi_request_body_readline(wsgi_req, len, &rlen); if (!chunk) { uwsgi_jvm_throw_io("error reading request body"); return -1; } if (chunk == uwsgi.empty) { return -1; } char *buf = (char *) (*ujvm_env)->GetByteArrayElements(ujvm_env, b, JNI_FALSE); if (!buf) return -1; memcpy(buf, chunk, rlen); (*ujvm_env)->ReleaseByteArrayElements(ujvm_env, b, (jbyte *) buf, 0); return rlen; } JNIEXPORT jint JNICALL uwsgi_jvm_request_body_available(JNIEnv *env, jobject o) { struct wsgi_request *wsgi_req = current_wsgi_req(); return (jint) (wsgi_req->post_cl - wsgi_req->post_pos); } JNIEXPORT void JNICALL uwsgi_jvm_request_body_seek(JNIEnv *env, jobject o, jint pos) { struct wsgi_request *wsgi_req = current_wsgi_req(); uwsgi_request_body_seek(wsgi_req, pos); } static JNINativeMethod uwsgi_jvm_request_body_methods[] = { {"read", "()I", (void *) &uwsgi_jvm_request_body_read}, {"read", "([B)I", (void *) &uwsgi_jvm_request_body_read_bytearray}, {"readLine", "([B)I", (void *) &uwsgi_jvm_request_body_readline_bytearray}, {"available", "()I", (void *) &uwsgi_jvm_request_body_available}, {"seek", "(I)V", (void *) &uwsgi_jvm_request_body_seek}, }; static struct uwsgi_option uwsgi_jvm_options[] = { {"jvm-main-class", required_argument, 0, "load the specified class and call its main() function", uwsgi_opt_add_string_list, &ujvm.main_classes, 0}, {"jvm-opt", required_argument, 0, "add the specified jvm option", uwsgi_opt_add_string_list, &ujvm.opts, 0}, {"jvm-class", required_argument, 0, "load the specified class", uwsgi_opt_add_string_list, &ujvm.classes, 0}, {"jvm-classpath", required_argument, 0, "add the specified directory to the classpath", uwsgi_opt_add_string_list, &ujvm.classpath, 0}, {0, 0, 0, 0}, }; jobject uwsgi_jvm_entryset(jobject o) { jclass c = uwsgi_jvm_class_from_object(o); if (!c) return NULL; jmethodID mid = uwsgi_jvm_get_method_id(c, "entrySet", "()Ljava/util/Set;"); uwsgi_jvm_local_unref(c); if (!mid) return NULL; return uwsgi_jvm_call_object(o, mid); } jobject uwsgi_jvm_to_string(jobject o) { jclass c = uwsgi_jvm_class_from_object(o); if (!c) return NULL; jmethodID mid = uwsgi_jvm_get_method_id_quiet(c, "toString", "()Ljava/lang/String;"); uwsgi_jvm_local_unref(c); if (!mid) return NULL; return uwsgi_jvm_call_object(o, mid); } int uwsgi_jvm_object_to_response_body(struct wsgi_request *wsgi_req, jobject body) { // check for string if (uwsgi_jvm_object_is_instance(body, ujvm.str_class)) { char *c_body = uwsgi_jvm_str2c(body); size_t c_body_len = uwsgi_jvm_strlen(body); uwsgi_response_write_body_do(wsgi_req, c_body, c_body_len); uwsgi_jvm_release_chars(body, c_body); return 0; } // check for string array if (uwsgi_jvm_object_is_instance(body, ujvm.str_array_class)) { size_t items = uwsgi_jvm_array_len(body); size_t i; for(i=0;iExceptionCheck(ujvm_env)) { (*ujvm_env)->ExceptionDescribe(ujvm_env); (*ujvm_env)->ExceptionClear(ujvm_env); return -1; } return 0; } void uwsgi_jvm_clear_exception() { if ((*ujvm_env)->ExceptionCheck(ujvm_env)) { (*ujvm_env)->ExceptionClear(ujvm_env); } } int uwsgi_jvm_object_is_instance(jobject o, jclass c) { if ((*ujvm_env)->IsInstanceOf(ujvm_env, o, c)) { return 1; } return 0; } // load/find/get a class jclass uwsgi_jvm_class(char *name) { jclass my_class = (*ujvm_env)->FindClass(ujvm_env, name); if (uwsgi_jvm_exception()) { return NULL; } return my_class; } // get the class of an object jclass uwsgi_jvm_class_from_object(jobject o) { return (*ujvm_env)->GetObjectClass(ujvm_env, o); } // return a java string of the object class name jobject uwsgi_jvm_object_class_name(jobject o) { jclass c = uwsgi_jvm_class_from_object(o); jmethodID mid = uwsgi_jvm_get_method_id(c, "getClass", "()Ljava/lang/Class;"); uwsgi_jvm_local_unref(c); if (!mid) return NULL; jobject oc = uwsgi_jvm_call_object(o, mid); if (!oc) return NULL; jclass c2 = uwsgi_jvm_class_from_object(oc); if (!c2) return NULL; mid = uwsgi_jvm_get_method_id(c2, "getName", "()Ljava/lang/String;"); uwsgi_jvm_local_unref(c2); if (!mid) return NULL; return uwsgi_jvm_call_object(oc, mid); } long uwsgi_jvm_int2c(jobject o) { static jmethodID mid = 0; if (!mid) { mid = uwsgi_jvm_get_method_id(ujvm.int_class, "intValue", "()I"); if (!mid) return -1 ; } long value = (*ujvm_env)->CallIntMethod(ujvm_env, o, mid); if (uwsgi_jvm_exception()) { return -1; } return value; } long uwsgi_jvm_long2c(jobject o) { static jmethodID mid = 0; if (!mid) { mid = uwsgi_jvm_get_method_id(ujvm.long_class, "longValue", "()J"); if (!mid) return -1; } long value = (*ujvm_env)->CallLongMethod(ujvm_env, o, mid); if (uwsgi_jvm_exception()) { return -1; } return value; } long uwsgi_jvm_number2c(jobject o) { if (uwsgi_jvm_object_is_instance(o, ujvm.int_class)) { return uwsgi_jvm_int2c(o); } if (uwsgi_jvm_object_is_instance(o, ujvm.long_class)) { return uwsgi_jvm_long2c(o); } return -1; } size_t uwsgi_jvm_array_len(jobject o) { jsize len = (*ujvm_env)->GetArrayLength(ujvm_env, o); if (uwsgi_jvm_exception()) { return 0; } return len; } jobject uwsgi_jvm_array_get(jobject o, long index) { jobject ret = (*ujvm_env)->GetObjectArrayElement(ujvm_env, o, index); if (uwsgi_jvm_exception()) { return NULL; } return ret; } jobject uwsgi_jvm_bytearray(char *buf, size_t len) { jobject byte_buffer = (*ujvm_env)->NewByteArray(ujvm_env, len); if (!byte_buffer) return NULL; char *dbuf = (char *) (*ujvm_env)->GetByteArrayElements(ujvm_env, byte_buffer, JNI_FALSE); memcpy(dbuf, buf, len); (*ujvm_env)->ReleaseByteArrayElements(ujvm_env, byte_buffer, (jbyte *) dbuf, 0); return byte_buffer; } int uwsgi_jvm_consume_input_stream(struct wsgi_request *wsgi_req, size_t chunk, jobject o) { int ret = 0; jclass c = uwsgi_jvm_class_from_object(o); jmethodID mid_read = uwsgi_jvm_get_method_id(c, "read", "([B)I"); if (!mid_read) { uwsgi_jvm_local_unref(c); return -1; } jmethodID mid_close = uwsgi_jvm_get_method_id(c, "close", "()V"); if (!mid_close) { uwsgi_jvm_local_unref(c); return -1; } uwsgi_jvm_local_unref(c); // allocate the byte buffer jobject byte_buffer = (*ujvm_env)->NewByteArray(ujvm_env, chunk); if (!byte_buffer) return -1; // ok start reading from the input stream for(;;) { long len = (*ujvm_env)->CallIntMethod(ujvm_env, o, mid_read, byte_buffer); if ((*ujvm_env)->ExceptionCheck(ujvm_env)) { (*ujvm_env)->ExceptionClear(ujvm_env); break; } if (len <= 0) { break; } // get the body of the array char *buf = (char *) (*ujvm_env)->GetByteArrayElements(ujvm_env, byte_buffer, JNI_FALSE); if (!buf) { ret = -1; break; } //send if (uwsgi_response_write_body_do(wsgi_req, buf, len)) { (*ujvm_env)->ReleaseByteArrayElements(ujvm_env, byte_buffer, (jbyte *) buf, 0); ret = -1; break; } // release (*ujvm_env)->ReleaseByteArrayElements(ujvm_env, byte_buffer, (jbyte *) buf, 0); } uwsgi_jvm_local_unref(byte_buffer); // close the inputstream if (uwsgi_jvm_call(o, mid_close)) { return -1; } return ret; } // returns the method id, given the method name and its signature jmethodID uwsgi_jvm_get_method_id(jclass cls, char *name, char *signature) { jmethodID mid = (*ujvm_env)->GetMethodID(ujvm_env, cls, name, signature); if (uwsgi_jvm_exception()) { return NULL; } return mid; } // returns the method id, given the method name and its signature jmethodID uwsgi_jvm_get_method_id_quiet(jclass cls, char *name, char *signature) { jmethodID mid = (*ujvm_env)->GetMethodID(ujvm_env, cls, name, signature); if ((*ujvm_env)->ExceptionCheck(ujvm_env)) { (*ujvm_env)->ExceptionClear(ujvm_env); return NULL; } return mid; } jmethodID uwsgi_jvm_get_static_method_id_quiet(jclass cls, char *name, char *signature) { jmethodID mid = (*ujvm_env)->GetStaticMethodID(ujvm_env, cls, name, signature); if ((*ujvm_env)->ExceptionCheck(ujvm_env)) { (*ujvm_env)->ExceptionClear(ujvm_env); return NULL; } return mid; } // returns the static method id, given the method name and its signature jmethodID uwsgi_jvm_get_static_method_id(jclass cls, char *name, char *signature) { jmethodID mid = (*ujvm_env)->GetStaticMethodID(ujvm_env, cls, name, signature); if (uwsgi_jvm_exception()) { return NULL; } return mid; } jobject uwsgi_jvm_ref(jobject obj) { return (*ujvm_env)->NewGlobalRef(ujvm_env, obj); } void uwsgi_jvm_unref(jobject obj) { (*ujvm_env)->DeleteGlobalRef(ujvm_env, obj); } void uwsgi_jvm_local_unref(jobject obj) { (*ujvm_env)->DeleteLocalRef(ujvm_env, obj); } jobject uwsgi_jvm_list() { // optimization static jmethodID mid = 0; if (!mid) { mid = uwsgi_jvm_get_method_id(ujvm.list_class, "", "()V"); if (!mid) return NULL; } jobject ll = (*ujvm_env)->NewObject(ujvm_env, ujvm.list_class, mid); if (uwsgi_jvm_exception()) { return NULL; } return ll; } jobject uwsgi_jvm_hashmap() { // optimization static jmethodID mid = 0; if (!mid) { mid = uwsgi_jvm_get_method_id(ujvm.hashmap_class, "", "()V"); if (!mid) return NULL; } jobject hm = (*ujvm_env)->NewObject(ujvm_env, ujvm.hashmap_class, mid); if (uwsgi_jvm_exception()) { return NULL; } return hm; } int uwsgi_jvm_hashmap_put(jobject hm, jobject key, jobject value) { // optimization static jmethodID mid = 0; if (!mid) { mid = uwsgi_jvm_get_method_id(ujvm.hashmap_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); if (!mid) return -1; } return uwsgi_jvm_call(hm, mid, key, value); } int uwsgi_jvm_list_add(jobject ll, jobject value) { // optimization static jmethodID mid = 0; if (!mid) { mid = uwsgi_jvm_get_method_id(ujvm.list_class, "add", "(Ljava/lang/Object;)Z"); if (!mid) return -1; } return uwsgi_jvm_call(ll, mid, value); } jobject uwsgi_jvm_hashmap_get(jobject hm, jobject key) { // optimization static jmethodID mid = 0; if (!mid) { mid = uwsgi_jvm_get_method_id(ujvm.hashmap_class, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); if (!mid) return NULL; } return uwsgi_jvm_call_object(hm, mid, key); } int uwsgi_jvm_hashmap_has(jobject hm, jobject key) { // optimization static jmethodID mid = 0; if (!mid) { mid = uwsgi_jvm_get_method_id(ujvm.hashmap_class, "containsKey", "(Ljava/lang/Object;)Z"); if (!mid) return 0; } if (uwsgi_jvm_call_bool(hm, mid, key)) { return 1; } return 0; } jobject uwsgi_jvm_iterator(jobject set) { // optimization static jmethodID mid = 0; if (!mid) { mid = uwsgi_jvm_get_method_id(ujvm.set_class, "iterator", "()Ljava/util/Iterator;"); if (!mid) return 0; } return uwsgi_jvm_call_object(set, mid); } jobject uwsgi_jvm_auto_iterator(jobject o) { jclass c = uwsgi_jvm_class_from_object(o); if (!c) return NULL; jmethodID mid = uwsgi_jvm_get_method_id_quiet(c, "iterator", "()Ljava/util/Iterator;"); uwsgi_jvm_local_unref(c); if (!mid) return NULL; return uwsgi_jvm_call_object(o, mid); } // returns a java string of the filaname jobject uwsgi_jvm_filename(jobject o) { // optimization static jmethodID mid = 0; if (!mid) { mid = uwsgi_jvm_get_method_id(ujvm.file_class, "getPath", "()Ljava/lang/String;"); if (!mid) return 0; } return uwsgi_jvm_call_object(o, mid); } jobject uwsgi_jvm_getKey(jobject item) { jclass c = uwsgi_jvm_class_from_object(item); if (!c) return NULL; jmethodID mid = uwsgi_jvm_get_method_id(c, "getKey", "()Ljava/lang/Object;"); uwsgi_jvm_local_unref(c); if (!mid) return NULL; return uwsgi_jvm_call_object(item, mid); } jobject uwsgi_jvm_getValue(jobject item) { jclass c = uwsgi_jvm_class_from_object(item); if (!c) return NULL; jmethodID mid = uwsgi_jvm_get_method_id(c, "getValue", "()Ljava/lang/Object;"); uwsgi_jvm_local_unref(c); if (!mid) return NULL; return uwsgi_jvm_call_object(item, mid); } int uwsgi_jvm_iterator_hasNext(jobject iterator) { // optimization static jmethodID mid = 0; if (!mid) { mid = uwsgi_jvm_get_method_id(ujvm.iterator_class, "hasNext", "()Z"); if (!mid) return 0; } if (uwsgi_jvm_call_bool(iterator, mid)) { return 1; } return 0; } jobject uwsgi_jvm_iterator_next(jobject iterator) { // optimization static jmethodID mid = 0; if (!mid) { mid = uwsgi_jvm_get_method_id(ujvm.iterator_class, "next", "()Ljava/lang/Object;"); if (!mid) return NULL; } return uwsgi_jvm_call_object(iterator, mid); } jobject uwsgi_jvm_request_body_input_stream() { static jmethodID mid = 0; if (!mid) { mid = uwsgi_jvm_get_method_id(ujvm.request_body_class, "", "()V"); if (!mid) return NULL; } jobject o = (*ujvm_env)->NewObject(ujvm_env, ujvm.request_body_class, mid); if (uwsgi_jvm_exception()) { return NULL; } return o; } jobject uwsgi_jvm_num(long num) { static jmethodID mid = 0; if (!mid) { mid = uwsgi_jvm_get_method_id(ujvm.int_class, "", "(I)V"); if (!mid) return NULL; } jobject o = (*ujvm_env)->NewObject(ujvm_env, ujvm.int_class, mid, num); if (uwsgi_jvm_exception()) { return NULL; } return o; } jobject uwsgi_jvm_bool(long b) { static jmethodID mid = 0; if (!mid) { mid = uwsgi_jvm_get_method_id(ujvm.int_class, "", "(I)V"); if (!mid) return NULL; } jobject o = (*ujvm_env)->NewObject(ujvm_env, ujvm.bool_class, mid, b); if (uwsgi_jvm_exception()) { return NULL; } return o; } jobject uwsgi_jvm_str(char *str, size_t len) { jobject new_str; if (len > 0) { char *tmp = uwsgi_concat2n(str, len, "", 0); new_str = (*ujvm_env)->NewStringUTF(ujvm_env, tmp); free(tmp); } else { new_str = (*ujvm_env)->NewStringUTF(ujvm_env, str); } return new_str; } int uwsgi_jvm_call_static(jclass c, jmethodID mid, ...) { va_list args; va_start(args, mid); (*ujvm_env)->CallStaticVoidMethodV(ujvm_env, c, mid, args); va_end(args); return uwsgi_jvm_exception(); } int uwsgi_jvm_call(jobject o, jmethodID mid, ...) { va_list args; va_start(args, mid); (*ujvm_env)->CallVoidMethodV(ujvm_env, o, mid, args); va_end(args); return uwsgi_jvm_exception(); } jobject uwsgi_jvm_call_object_static(jclass c, jmethodID mid, ...) { va_list args; va_start(args, mid); jobject ret = (*ujvm_env)->CallStaticObjectMethodV(ujvm_env, c, mid, args); va_end(args); if (uwsgi_jvm_exception()) { return NULL; } return ret; } jobject uwsgi_jvm_call_object(jobject o, jmethodID mid, ...) { va_list args; va_start(args, mid); jobject ret = (*ujvm_env)->CallObjectMethodV(ujvm_env, o, mid, args); va_end(args); if (uwsgi_jvm_exception()) { return NULL; } return ret; } int uwsgi_jvm_call_bool(jobject o, jmethodID mid, ...) { va_list args; va_start(args, mid); int ret = (*ujvm_env)->CallBooleanMethodV(ujvm_env, o, mid, args); va_end(args); if (uwsgi_jvm_exception()) { return 0; } return ret; } jobject uwsgi_jvm_call_objectA(jobject o, jmethodID mid, jvalue *args) { jobject ret = (*ujvm_env)->CallObjectMethodA(ujvm_env, o, mid, args); if (uwsgi_jvm_exception()) { return NULL; } return ret; } void uwsgi_jvm_throw(char *message) { (*ujvm_env)->ThrowNew(ujvm_env, ujvm.runtime_exception, message); } void uwsgi_jvm_throw_io(char *message) { (*ujvm_env)->ThrowNew(ujvm_env, ujvm.io_exception, message); } static int uwsgi_jvm_init(void) { return 0; } static void uwsgi_jvm_create(void) { ujvm.vm_args.version = JNI_VERSION_1_2; JNI_GetDefaultJavaVMInitArgs(&ujvm.vm_args); JavaVMOption *options; struct uwsgi_string_list *usl = ujvm.opts; int opt_count = 1; while(usl) { opt_count++; usl = usl->next; } options = uwsgi_calloc(sizeof(JavaVMOption) * opt_count); options[0].optionString = "-Djava.class.path=."; char *old_cp = NULL ; struct uwsgi_string_list *cp = ujvm.classpath; while(cp) { if (old_cp) { options[0].optionString = uwsgi_concat3(old_cp, ":", cp->value); free(old_cp); } else { options[0].optionString = uwsgi_concat3(options[0].optionString, ":", cp->value); } old_cp = options[0].optionString ; cp = cp->next; } usl = ujvm.opts; opt_count = 1; while(usl) { options[opt_count].optionString = usl->value; opt_count++; usl = usl->next; } ujvm.vm_args.options = options; ujvm.vm_args.nOptions = opt_count; JNIEnv *env; if (pthread_key_create(&ujvm.env, NULL)) { uwsgi_error("pthread_key_create()"); exit(1); } if (JNI_CreateJavaVM(&ujvm.vm, (void **) &env, &ujvm.vm_args)) { uwsgi_log("unable to initialize the JVM\n"); exit(1); } pthread_setspecific(ujvm.env, env); char *java_version = NULL; jvmtiEnv *jvmti; if ((*ujvm.vm)->GetEnv(ujvm.vm, (void **)&jvmti, JVMTI_VERSION) == JNI_OK) { (*jvmti)->GetSystemProperty(jvmti, "java.vm.version", &java_version); } if (uwsgi.mywid > 0) { if (java_version) { uwsgi_log("JVM %s initialized at %p (worker: %d pid: %d)\n", java_version, ujvm_env, uwsgi.mywid, (int) uwsgi.mypid); } else { uwsgi_log("JVM initialized at %p (worker: %d pid: %d)\n", ujvm_env, uwsgi.mywid, (int) uwsgi.mypid); } } ujvm.str_class = uwsgi_jvm_class("java/lang/String"); if (!ujvm.str_class) exit(1); ujvm.str_array_class = uwsgi_jvm_class("[Ljava/lang/String;"); if (!ujvm.str_array_class) exit(1); ujvm.int_class = uwsgi_jvm_class("java/lang/Integer"); if (!ujvm.int_class) exit(1); ujvm.bool_class = uwsgi_jvm_class("java/lang/Boolean"); if (!ujvm.bool_class) exit(1); ujvm.long_class = uwsgi_jvm_class("java/lang/Long"); if (!ujvm.long_class) exit(1); ujvm.byte_class = uwsgi_jvm_class("java/lang/Byte"); if (!ujvm.byte_class) exit(1); ujvm.bytearray_class = uwsgi_jvm_class("[B"); if (!ujvm.bytearray_class) exit(1); ujvm.file_class = uwsgi_jvm_class("java/io/File"); if (!ujvm.file_class) exit(1); ujvm.input_stream_class = uwsgi_jvm_class("java/io/InputStream"); if (!ujvm.input_stream_class) exit(1); ujvm.hashmap_class = uwsgi_jvm_class("java/util/HashMap"); if (!ujvm.hashmap_class) exit(1); ujvm.list_class = uwsgi_jvm_class("java/util/ArrayList"); if (!ujvm.list_class) exit(1); ujvm.set_class = uwsgi_jvm_class("java/util/Set"); if (!ujvm.set_class) exit(1); ujvm.iterator_class = uwsgi_jvm_class("java/util/Iterator"); if (!ujvm.iterator_class) exit(1); ujvm.runtime_exception = uwsgi_jvm_class("java/lang/RuntimeException"); if (!ujvm.runtime_exception) exit(1); ujvm.io_exception = uwsgi_jvm_class("java/io/IOException"); if (!ujvm.io_exception) exit(1); jclass uwsgi_class = uwsgi_jvm_class("uwsgi"); if (!uwsgi_class) { exit(1); } /* start filling uwsgi.opt */ jfieldID opt_fid = (*ujvm_env)->GetStaticFieldID(ujvm_env, uwsgi_class, "opt", "Ljava/util/HashMap;"); if (uwsgi_jvm_exception()) { exit(1); } jobject opt_hm = uwsgi_jvm_hashmap(); int j; for (j = 0; j < uwsgi.exported_opts_cnt; j++) { jstring j_opt_key = uwsgi_jvm_str(uwsgi.exported_opts[j]->key, 0); if (uwsgi_jvm_hashmap_has(opt_hm, (jobject) j_opt_key)) { jobject j_opt_value = uwsgi_jvm_hashmap_get(opt_hm, (jobject) j_opt_key); if (uwsgi_jvm_object_is_instance(j_opt_value, ujvm.list_class)) { if (uwsgi.exported_opts[j]->value == NULL) { uwsgi_jvm_list_add(j_opt_value, uwsgi_jvm_bool(JNI_TRUE)); } else { uwsgi_jvm_list_add(j_opt_value, uwsgi_jvm_str(uwsgi.exported_opts[j]->value, 0)); } } else { jobject ll = uwsgi_jvm_list(); uwsgi_jvm_list_add(ll, j_opt_value); if (uwsgi.exported_opts[j]->value == NULL) { uwsgi_jvm_list_add(ll, uwsgi_jvm_bool(JNI_TRUE)); } else { uwsgi_jvm_list_add(ll, uwsgi_jvm_str(uwsgi.exported_opts[j]->value, 0)); } uwsgi_jvm_hashmap_put(opt_hm, j_opt_key, ll); } } else { if (uwsgi.exported_opts[j]->value == NULL) { uwsgi_jvm_hashmap_put(opt_hm, j_opt_key, uwsgi_jvm_bool(JNI_TRUE)); } else { uwsgi_jvm_hashmap_put(opt_hm, j_opt_key, uwsgi_jvm_str(uwsgi.exported_opts[j]->value, 0)); } } } (*ujvm_env)->SetStaticObjectField(ujvm_env, uwsgi_class, opt_fid, opt_hm); (*ujvm_env)->RegisterNatives(ujvm_env, uwsgi_class, uwsgi_jvm_api_methods, sizeof(uwsgi_jvm_api_methods)/sizeof(uwsgi_jvm_api_methods[0])); if (uwsgi_jvm_exception()) { exit(1); } jclass uwsgi_signal_handler_class = uwsgi_jvm_class("uwsgi$SignalHandler"); if (!uwsgi_signal_handler_class) exit(1); ujvm.api_signal_handler_mid = uwsgi_jvm_get_method_id(uwsgi_signal_handler_class, "function", "(I)V"); if (!ujvm.api_signal_handler_mid) exit(1); jclass uwsgi_rpc_function_class = uwsgi_jvm_class("uwsgi$RpcFunction"); if (!uwsgi_rpc_function_class) exit(1); ujvm.api_rpc_function_mid = uwsgi_jvm_get_method_id(uwsgi_rpc_function_class, "function", "([Ljava/lang/String;)Ljava/lang/String;"); if (!ujvm.api_rpc_function_mid) exit(1); ujvm.request_body_class = uwsgi_jvm_class("uwsgi$RequestBody"); if (!ujvm.request_body_class) exit(1); (*ujvm_env)->RegisterNatives(ujvm_env, ujvm.request_body_class, uwsgi_jvm_request_body_methods, sizeof(uwsgi_jvm_request_body_methods)/sizeof(uwsgi_jvm_request_body_methods[0])); if (uwsgi_jvm_exception()) { exit(1); } usl = ujvm.main_classes; while(usl) { jclass c = uwsgi_jvm_class(usl->value); if (!c) { exit(1); } jmethodID mid = uwsgi_jvm_get_static_method_id_quiet(c, "main", "([Ljava/lang/String;)V"); if (mid) { jobject j_args = (*ujvm_env)->NewObjectArray(ujvm_env, 0, ujvm.str_class, NULL); if (uwsgi_jvm_call_static(c, mid, j_args)) { exit(1); } uwsgi_jvm_local_unref(j_args); } else { mid = uwsgi_jvm_get_static_method_id(c, "main", "()V"); if (!mid) { uwsgi_log("unable to find main() method in class \"%s\"\n", usl->value); exit(1); } if (uwsgi_jvm_call_static(c, mid)) { exit(1); } } usl = usl->next; } usl = ujvm.classes; while(usl) { uwsgi_jvm_class(usl->value); usl = usl->next; } // load request_handlers setup functions int i; for(i=0;iGetStringUTFChars(ujvm_env, o, JNI_FALSE); } // get c from bytearray char *uwsgi_jvm_bytearray2c(jobject o) { return (char *) (*ujvm_env)->GetByteArrayElements(ujvm_env, o, JNI_FALSE); } // return the size of a java string (UTF8) size_t uwsgi_jvm_strlen(jobject obj) { return (*ujvm_env)->GetStringUTFLength(ujvm_env, obj); } static int uwsgi_jvm_signal_handler(uint8_t signum, void *handler) { long l_signum = signum; return uwsgi_jvm_call(handler, ujvm.api_signal_handler_mid, (void *) l_signum); } // route request to the specific JVM plugin (identified by modifier2) static int uwsgi_jvm_request(struct wsgi_request *wsgi_req) { uint8_t modifier2 = wsgi_req->uh->modifier2; if (!ujvm.request_handlers[modifier2]) { uwsgi_log("unable to find JVM request handler %u\n", modifier2); return -1; } /* Standard JVM request */ if (!wsgi_req->uh->pktsize) { uwsgi_log("Empty JVM request. skip.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } return ujvm.request_handlers[modifier2](wsgi_req); } void uwsgi_jvm_release_chars(jobject o, char *str) { (*ujvm_env)->ReleaseStringUTFChars(ujvm_env, o, str); } void uwsgi_jvm_release_bytearray(jobject o, char *str) { (*ujvm_env)->ReleaseByteArrayElements(ujvm_env, o, (jbyte *)str, 0); } static uint64_t uwsgi_jvm_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char **buffer) { jvalue args[1]; jobject str_array = (*ujvm_env)->NewObjectArray(ujvm_env, argc, ujvm.str_class, NULL); if (!str_array) return 0; uint8_t i; for(i=0;iSetObjectArrayElement(ujvm_env, str_array, i, j_arg); uwsgi_jvm_local_unref(j_arg); } args[0].l = str_array; jobject ret = uwsgi_jvm_call_objectA(func, ujvm.api_rpc_function_mid, args); uwsgi_jvm_local_unref(str_array); if (ret == NULL) { return 0; } size_t rlen = uwsgi_jvm_strlen(ret); if (rlen > 0) { *buffer = uwsgi_malloc(rlen); char *b = uwsgi_jvm_str2c(ret); memcpy(*buffer, b, rlen); uwsgi_jvm_release_chars(ret, b); uwsgi_jvm_local_unref(ret); return rlen; } uwsgi_jvm_local_unref(ret); return 0; } static void uwsgi_jvm_init_thread(int coreid) { JNIEnv *env; (*ujvm.vm)->AttachCurrentThread(ujvm.vm, (void **) &env, NULL); pthread_setspecific(ujvm.env, env); } static void uwsgi_jvm_after_request(struct wsgi_request *wsgi_req) { log_request(wsgi_req); } struct uwsgi_plugin jvm_plugin = { .name = "jvm", .modifier1 = 8, .request = uwsgi_jvm_request, .after_request = uwsgi_jvm_after_request, .init = uwsgi_jvm_init, .options = uwsgi_jvm_options, .post_fork = uwsgi_jvm_create, .signal_handler = uwsgi_jvm_signal_handler, .rpc = uwsgi_jvm_rpc, .init_thread = uwsgi_jvm_init_thread, }; uwsgi-2.0.29/plugins/jvm/uwsgi.java000066400000000000000000000030071477626554400172440ustar00rootroot00000000000000import java.io.*; import java.util.*; public class uwsgi { static HashMap opt; public static class RequestBody extends InputStream { public native int read(); public native int read(byte[] b); public native int readLine(byte[] b); public native int available(); public native void seek(int pos); } public interface SignalHandler { void function(int signum); } public interface RpcFunction { String function(String... args); } public static native int worker_id(); public static native void register_signal(int signum, String target, SignalHandler sh); public static native void register_rpc(String name, RpcFunction rf); public static native void lock(); public static native void unlock(); public static native void lock(int locknum); public static native void unlock(int locknum); public static native byte[] cache_get(String key); public static native byte[] cache_get(String key, String cache); public static native void cache_set(String key, byte[] value); public static native void cache_update(String key, byte[] value); public static native void cache_set(String key, byte[] value, int expires); public static native void cache_update(String key, byte[] value, int expires); public static native void cache_set(String key, byte[] value, int expires, String cache); public static native void cache_update(String key, byte[] value, int expires, String cache); public static native void alarm(String alarm, String msg); public static native String rpc(String... args); } uwsgi-2.0.29/plugins/jvm/uwsgiplugin.py000066400000000000000000000064171477626554400202020ustar00rootroot00000000000000import os import shutil import subprocess NAME='jvm' JVM_INCPATH = None JVM_LIBPATH = None operating_system = os.uname()[0].lower() try: arch = os.environ['JVM_ARCH'] except: arch = os.uname()[4].lower() if arch in ('i686', 'x86', 'x86_32'): arch = 'i386' elif arch in ('x86_64',): arch = 'amd64' elif arch.startswith('arm'): arch = 'arm' # try to detect the JVM if operating_system == 'darwin': known_jvms = ('/System/Library/Frameworks/JavaVM.framework/Headers',) for jvm in known_jvms: if os.path.exists(jvm): JVM_INCPATH = ["-Wno-deprecated-declarations", "-I%s" % jvm] JVM_LIBPATH = ["-framework JavaVM"] elif operating_system.startswith('cygwin'): JVM_INCPATH = ['-I"/cygdrive/c/Program Files/Java/jdk1.7.0_17/include"', '-I"/cygdrive/c/Program Files/Java/jdk1.7.0_17/include/win32"'] JVM_LIBPATH = ['-L"/cygdrive/c/Program Files/Java/jdk1.7.0_17/jre/bin/server"'] else: known_jvms = ('/usr/lib/jvm/java-7-openjdk', '/usr/local/openjdk7', '/usr/lib/jvm/java-6-openjdk', '/usr/local/openjdk', '/usr/java', '/usr/lib/jvm/java/', '/usr/lib/jvm/java-8-openjdk-%s' % arch, '/usr/lib/jvm/java-11-openjdk-%s' % arch) for jvm in known_jvms: if os.path.exists(jvm + '/include'): JVM_INCPATH = ["-I%s/include/" % jvm, "-I%s/include/%s" % (jvm, operating_system)] if os.path.exists("%s/jre" % jvm): JVM_LIBPATH = ["-L%s/jre/lib/%s/server" % (jvm, arch)] else: JVM_LIBPATH = ["-L%s/lib/server" % (jvm,)] break if os.path.exists("%s-%s/include" % (jvm, arch)): jvm = "%s-%s" % (jvm, arch) JVM_INCPATH = ["-I%s/include/" % jvm, "-I%s/include/%s" % (jvm, operating_system)] JVM_LIBPATH = ["-L%s/jre/lib/%s/server" % (jvm, arch)] break try: JVM_INCPATH = ['-I"' + os.environ['UWSGICONFIG_JVM_INCPATH'] + '"'] except: pass try: JVM_LIBPATH = ['-L"' + os.environ['UWSGICONFIG_JVM_LIBPATH'] + '"'] except: pass if not JVM_INCPATH or not JVM_LIBPATH: print("unable to autodetect the JVM path, please specify UWSGICONFIG_JVM_INCPATH and UWSGICONFIG_JVM_LIBPATH environment vars") os._exit(1) CFLAGS = JVM_INCPATH LDFLAGS = JVM_LIBPATH LIBS = ['-ljvm'] if "-framework JavaVM" in JVM_LIBPATH: LIBS = [] GCC_LIST = ['jvm_plugin'] if 'LD_RUN_PATH' in os.environ: os.environ['LD_RUN_PATH'] += ':' + JVM_LIBPATH[0][2:] else: os.environ['LD_RUN_PATH'] = JVM_LIBPATH[0][2:] def post_build(config): if subprocess.call("javac %s/plugins/jvm/uwsgi.java" % os.getcwd(), shell=True) != 0: os._exit(1) if subprocess.call("cd %s/plugins/jvm ; jar cvf uwsgi.jar *.class" % os.getcwd(), shell=True) != 0: os._exit(1) print("*** uwsgi.jar available in %s/plugins/jvm/uwsgi.jar ***" % os.getcwd()) env = os.environ.get('VIRTUAL_ENV') if env: src = "%s/plugins/jvm/uwsgi.jar" % os.getcwd() tgt = "%s/lib/uwsgi.jar" % env shutil.copyfile(src, tgt) print("*** uwsgi.jar had been copied to %s" % tgt) plugin = "%s/jvm_plugin.so" % os.getcwd() if os.path.exists(plugin): tgt = "%s/bin/jvm_plugin.so" % env shutil.copyfile(plugin, tgt) print("*** jvm_plugin.so had been copied to %s" % tgt) uwsgi-2.0.29/plugins/jwsgi/000077500000000000000000000000001477626554400155725ustar00rootroot00000000000000uwsgi-2.0.29/plugins/jwsgi/jwsgi_plugin.c000066400000000000000000000123561477626554400204460ustar00rootroot00000000000000#include extern struct uwsgi_server uwsgi; extern struct uwsgi_jvm ujvm; #define UWSGI_JVM_REQUEST_HANDLER_JWSGI 0 struct uwsgi_jwsgi { char *app; jmethodID app_mid; jclass app_class; jobject app_instance; } ujwsgi; static struct uwsgi_option uwsgi_jwsgi_options[] = { {"jwsgi", required_argument, 0, "load the specified JWSGI application (syntax class:method)", uwsgi_opt_set_str, &ujwsgi.app, 0}, {0, 0, 0, 0}, }; static int uwsgi_jwsgi_add_request_item(jobject hm, char *key, uint16_t key_len, char *value, uint16_t value_len) { jobject j_key = uwsgi_jvm_str(key, key_len); if (!j_key) return -1; jobject j_value = NULL; // avoid clobbering vars if (value_len > 0) { j_value = uwsgi_jvm_str(value, value_len); } else { char *tmp = uwsgi_str(""); j_value = uwsgi_jvm_str(tmp, 0); free(tmp); } if (!j_value) { uwsgi_jvm_local_unref(j_value); return -1; } int ret = uwsgi_jvm_hashmap_put(hm, j_key, j_value); uwsgi_jvm_local_unref(j_key); uwsgi_jvm_local_unref(j_value); return ret; } static int uwsgi_jwsgi_add_request_input(jobject hm, char *key, uint16_t key_len) { jobject j_key = uwsgi_jvm_str(key, key_len); if (!j_key) return -1; jobject j_value = uwsgi_jvm_request_body_input_stream(); if (!j_value) { uwsgi_jvm_local_unref(j_value); return -1; } int ret = uwsgi_jvm_hashmap_put(hm, j_key, j_value); uwsgi_jvm_local_unref(j_key); uwsgi_jvm_local_unref(j_value); return ret; } static int uwsgi_jwsgi_request(struct wsgi_request *wsgi_req) { char status_str[11]; jobject hm = NULL; jobject response = NULL; jobject r_status = NULL; jobject r_headers = NULL; jobject r_headers_entries = NULL; jobject r_body = NULL; hm = uwsgi_jvm_hashmap(); if (!hm) return -1; int i; for(i=0;ivar_cnt;i+=2) { char *hk = wsgi_req->hvec[i].iov_base; uint16_t hk_l = wsgi_req->hvec[i].iov_len; char *hv = wsgi_req->hvec[i+1].iov_base; uint16_t hv_l = wsgi_req->hvec[i+1].iov_len; if (uwsgi_jwsgi_add_request_item(hm, hk, hk_l, hv, hv_l)) goto end; } if (uwsgi_jwsgi_add_request_input(hm, "jwsgi.input", 11)) goto end; if (!ujwsgi.app_instance) { response = uwsgi_jvm_call_object_static(ujwsgi.app_class, ujwsgi.app_mid, hm); } else { response = uwsgi_jvm_call_object(ujwsgi.app_instance, ujwsgi.app_mid, hm); } if (!response) goto end; if (uwsgi_jvm_array_len(response) != 3) { uwsgi_log("invalid JWSGI response object\n"); goto end; } r_status = uwsgi_jvm_array_get(response, 0); if (!r_status) goto end; long n_status = uwsgi_jvm_number2c(r_status); if (n_status == -1) goto end; if (uwsgi_num2str2(n_status, status_str) != 3) { goto end; } if (uwsgi_response_prepare_headers(wsgi_req, status_str, 3)) goto end; r_headers = uwsgi_jvm_array_get(response, 1); if (!r_headers) goto end; // get entrySet r_headers_entries = uwsgi_jvm_entryset(r_headers); if (!r_headers_entries) goto end; // get iterator jobject values = uwsgi_jvm_auto_iterator(r_headers_entries); if (values) { int ret = uwsgi_jvm_iterator_to_response_headers(wsgi_req, values); uwsgi_jvm_local_unref(values); if (ret) goto end; } else { uwsgi_log("unsupported response headers type !!! (must be java/util/HashMap)\n"); goto end; } r_body = uwsgi_jvm_array_get(response, 2); if (!r_body) goto end; if (uwsgi_jvm_object_to_response_body(wsgi_req, r_body)) { uwsgi_log("unsupported JWSGI response body type\n"); } end: if (r_status) uwsgi_jvm_local_unref(r_status); if (r_headers_entries) uwsgi_jvm_local_unref(r_headers_entries); if (r_headers) uwsgi_jvm_local_unref(r_headers); if (r_body) uwsgi_jvm_local_unref(r_body); if (response) { uwsgi_jvm_local_unref(response); } uwsgi_jvm_local_unref(hm); return UWSGI_OK; } static int uwsgi_jwsgi_setup() { char *app = uwsgi_str(ujwsgi.app); char *method = "application"; char *colon = strchr(app, ':'); if (colon) { *colon = 0; method = colon + 1; } ujwsgi.app_class = uwsgi_jvm_class(app); if (!ujwsgi.app_class) { exit(1); } ujwsgi.app_mid = uwsgi_jvm_get_static_method_id_quiet(ujwsgi.app_class, method, "(Ljava/util/HashMap;)[Ljava/lang/Object;"); if (uwsgi_jvm_exception() || !ujwsgi.app_mid) { jmethodID mid = uwsgi_jvm_get_method_id(ujwsgi.app_class, "", "()V"); if (uwsgi_jvm_exception() || !mid) exit(1); ujwsgi.app_instance = (*ujvm_env)->NewObject(ujvm_env, ujwsgi.app_class, mid); if (uwsgi_jvm_exception() || !ujwsgi.app_instance) { exit(1); } ujwsgi.app_mid = uwsgi_jvm_get_method_id(ujwsgi.app_class, method, "(Ljava/util/HashMap;)[Ljava/lang/Object;"); if (uwsgi_jvm_exception() || !ujwsgi.app_mid) { exit(1); } } uwsgi_log("JWSGI app \"%s\" loaded\n", ujwsgi.app); return 0; } static int uwsgi_jwsgi_init() { if (!ujwsgi.app) return 0; if (uwsgi_jvm_register_request_handler(UWSGI_JVM_REQUEST_HANDLER_JWSGI, uwsgi_jwsgi_setup, uwsgi_jwsgi_request)) { exit(1); } return 0; } struct uwsgi_plugin jwsgi_plugin = { .name = "jwsgi", .options = uwsgi_jwsgi_options, .init = uwsgi_jwsgi_init, }; uwsgi-2.0.29/plugins/jwsgi/uwsgiplugin.py000066400000000000000000000004521477626554400205220ustar00rootroot00000000000000jvm_path = 'plugins/jvm' up = {} try: execfile('%s/uwsgiplugin.py' % jvm_path, up) except: f = open('%s/uwsgiplugin.py' % jvm_path) exec(f.read(), up) f.close() NAME='jwsgi' CFLAGS = up['CFLAGS'] CFLAGS.append('-I%s' % jvm_path) LDFLAGS = [] LIBS = [] GCC_LIST = ['jwsgi_plugin'] uwsgi-2.0.29/plugins/ldap/000077500000000000000000000000001477626554400153675ustar00rootroot00000000000000uwsgi-2.0.29/plugins/ldap/ldap.c000066400000000000000000000354411477626554400164620ustar00rootroot00000000000000#include /* Authors: Roberto De Ioris - general LDAP support, reading uWSGI configuration from LDAP servers Łukasz Mierzwa - LDAP auth router support */ extern struct uwsgi_server uwsgi; #include #ifndef LDAP_OPT_SUCCESS #define LDAP_OPT_SUCCESS LDAP_SUCCESS #endif #ifndef ldap_unbind_ext_s #define ldap_unbind_ext_s ldap_unbind_ext #endif static void uwsgi_opt_ldap_dump(char *, char *, void *); static void uwsgi_opt_ldap_dump_ldif(char *, char *, void *); static void uwsgi_ldap_config(char *); static void uwsgi_opt_load_ldap(char *opt, char *url, void *none) { uwsgi_ldap_config(url); } static struct uwsgi_option uwsgi_ldap_options[] = { {"ldap", required_argument, 0, "load configuration from ldap server", uwsgi_opt_load_ldap, NULL, UWSGI_OPT_IMMEDIATE}, {"ldap-schema", no_argument, 0, "dump uWSGI ldap schema", uwsgi_opt_ldap_dump, NULL, UWSGI_OPT_IMMEDIATE}, {"ldap-schema-ldif", no_argument, 0, "dump uWSGI ldap schema in ldif format", uwsgi_opt_ldap_dump_ldif, NULL, UWSGI_OPT_IMMEDIATE}, {0, 0, 0, 0, 0, 0, 0}, }; static void ldap2uwsgi(char *ldapname, char *uwsginame) { char *ptr = uwsginame; int i; for (i = 0; i < (int) strlen(ldapname); i++) { if (isupper((int) ldapname[i])) { *ptr++ = '-'; *ptr++ = tolower((int) ldapname[i]); } else { *ptr++ = ldapname[i]; } } *ptr++ = 0; } static int calc_ldap_name(char *name) { int i; int counter = 0; for (i = 0; i < (int) strlen(name); i++) { if (isupper((int) name[i])) { counter++; } } return strlen(name) + counter; } struct uwsgi_ldap_entry { int num; char names[1024]; int has_arg; }; static void uwsgi_name_to_ldap(char *src, char *dst) { int i; char *ptr = dst; memset(dst, 0, 1024); strcat(dst, " 'uWSGI"); ptr += 7; for (i = 0; i < (int) strlen(src); i++) { if (src[i] == '-') { i++; *ptr++ = toupper((int) src[i]); } else { *ptr++ = src[i]; } } strcat(dst, "'"); } static struct uwsgi_ldap_entry *search_ldap_cache(struct uwsgi_ldap_entry *root, char *name, int count) { int i; struct uwsgi_ldap_entry *ule; for (i = 0; i < count; i++) { ule = &root[i]; if (uwsgi_list_has_str(ule->names, name + 1)) { return ule; } } return NULL; } static struct uwsgi_ldap_entry *get_ldap_names(int *count) { struct uwsgi_option *op = uwsgi.options; struct uwsgi_ldap_entry *ule, *entry; char ldap_name[1024]; *count = 0; ule = uwsgi_malloc(sizeof(struct uwsgi_ldap_entry) * uwsgi_count_options(op)); while (op && op->name) { uwsgi_name_to_ldap((char *) op->name, ldap_name); entry = search_ldap_cache(ule, ldap_name, *count); if (entry) goto next; entry = &ule[*count]; entry->num = *count; strcpy(entry->names, ldap_name); *count = *count + 1; entry->has_arg = op->type; next: op++; } return ule; } static void uwsgi_opt_ldap_dump_ldif(char *opt, char *foo, void *bar) { int i; int items; uwsgi_log("\n"); uwsgi_log("dn: cn=uwsgi,cn=schema,cn=config\n"); uwsgi_log("objectClass: olcSchemaConfig\n"); uwsgi_log("cn: uwsgi\n"); struct uwsgi_ldap_entry *entry, *ule = get_ldap_names(&items); for (i = 0; i < items; i++) { entry = &ule[i]; uwsgi_log("olcAttributeTypes: ( 1.3.6.1.4.1.35156.17.4.%d NAME (%s", entry->num, entry->names); if (entry->has_arg) { uwsgi_log(" ) SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )\n"); } else { uwsgi_log(" ) SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )\n"); } } uwsgi_log("olcAttributeTypes: ( 1.3.6.1.4.1.35156.17.4.50000 NAME 'uWSGInull' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )\n"); uwsgi_log("olcObjectClasses: ( 1.3.6.1.4.1.35156.17.3.1 NAME 'uWSGIConfig' SUP top AUXILIARY DESC 'uWSGI configuration' MAY ( "); for (i = 0; i < items; i++) { entry = &ule[i]; char *list2 = uwsgi_concat2(entry->names + 1, ""); char *p, *ctx = NULL; uwsgi_foreach_token(list2, " ", p, ctx) { uwsgi_log("%.*s $ ", strlen(p) - 2, p + 1); } free(list2); } uwsgi_log("uWSGInull ))\n"); uwsgi_log("\n"); exit(0); } static void uwsgi_opt_ldap_dump(char *opt, char *foo, void *bar) { int i; int items; struct uwsgi_ldap_entry *entry, *ule = get_ldap_names(&items); for (i = 0; i < items; i++) { entry = &ule[i]; uwsgi_log("attributetype ( 1.3.6.1.4.1.35156.17.4.%d NAME (%s", entry->num, entry->names); if (entry->has_arg) { uwsgi_log(" ) SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )\n"); } else { uwsgi_log(" ) SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )\n"); } } uwsgi_log("attributetype ( 1.3.6.1.4.1.35156.17.4.50000 NAME 'uWSGInull' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )\n"); uwsgi_log("objectclass ( 1.3.6.1.4.1.35156.17.3.1 NAME 'uWSGIConfig' SUP top AUXILIARY DESC 'uWSGI configuration' MAY ( "); for (i = 0; i < items; i++) { entry = &ule[i]; char *list2 = uwsgi_concat2(entry->names + 1, ""); char *p, *ctx = NULL; uwsgi_foreach_token(list2, " ", p, ctx) { uwsgi_log("%.*s $ ", strlen(p) - 2, p + 1); } free(list2); } uwsgi_log("uWSGInull ))\n"); exit(0); } static void uwsgi_ldap_config(char *url) { LDAP *ldp; LDAPMessage *results, *entry; BerElement *ber; struct berval **bervalues; char *attr; char *uwsgi_attr; char *url_slash; int desired_version = LDAP_VERSION3; int ret; LDAPURLDesc *ldap_url; if (!ldap_is_ldap_url(url)) { uwsgi_log("invalid LDAP url.\n"); exit(1); } if (ldap_url_parse(url, &ldap_url) != LDAP_SUCCESS) { uwsgi_log("unable to parse LDAP url.\n"); exit(1); } uwsgi_log("[uWSGI] getting LDAP configuration from %s\n", url); url_slash = strchr(url, '/'); url_slash = strchr(url_slash + 1, '/'); url_slash = strchr(url_slash + 1, '/'); if (url_slash) { url_slash[0] = 0; } #ifdef UWSGI_DEBUG uwsgi_debug("LDAP URL: %s\n", url); uwsgi_debug("LDAP BASE DN: %s\n", ldap_url->lud_dn); #endif #if LDAP_API_VERSION >= 3000 if ((ret = ldap_initialize(&ldp, url)) != LDAP_SUCCESS) { uwsgi_log("LDAP: %s\n", ldap_err2string(ret)); exit(1); } #else if ((ldp = ldap_init(ldap_url->lud_host, ldap_url->lud_port)) == NULL) { uwsgi_error("ldap_init()"); exit(1); } #endif if ((ret = ldap_set_option(ldp, LDAP_OPT_PROTOCOL_VERSION, &desired_version)) != LDAP_OPT_SUCCESS) { uwsgi_log("LDAP: %s\n", ldap_err2string(ret)); exit(1); } if ((ret = ldap_search_ext_s(ldp, ldap_url->lud_dn, ldap_url->lud_scope, ldap_url->lud_filter, NULL, 0, NULL, NULL, NULL, 1, &results)) != LDAP_SUCCESS) { uwsgi_log("LDAP: %s\n", ldap_err2string(ret)); exit(1); } #ifdef UWSGI_DEBUG uwsgi_debug("LDAP connection initialized %p\n", ldp); #endif free(ldap_url); if (ldap_count_entries(ldp, results) < 1) { uwsgi_log("no LDAP entry found\n"); exit(1); } entry = ldap_first_entry(ldp, results); int found = 0; for (attr = ldap_first_attribute(ldp, entry, &ber); attr != NULL; attr = ldap_next_attribute(ldp, entry, ber)) { if (!strncmp(attr, "uWSGI", 5)) { found = 1; uwsgi_attr = malloc(calc_ldap_name(attr) + 1); if (!uwsgi_attr) { uwsgi_error("malloc()"); exit(1); } ldap2uwsgi(attr + 5, uwsgi_attr); #ifdef UWSGI_DEBUG uwsgi_debug("LDAP attribute: %s = --%s\n", attr, uwsgi_attr); #endif bervalues = ldap_get_values_len(ldp, entry, attr); if (bervalues) { // do not free uwsgi_attr/uwsgi_val; char *uwsgi_val = malloc(bervalues[0]->bv_len + 1); if (!uwsgi_val) { uwsgi_error("malloc()"); exit(1); } memcpy(uwsgi_val, bervalues[0]->bv_val, bervalues[0]->bv_len); uwsgi_val[bervalues[0]->bv_len] = 0; add_exported_option((char *) uwsgi_attr, uwsgi_val, 0); free(bervalues); } else { free(uwsgi_attr); } } free(attr); } if (!found) { uwsgi_log("no uWSGI LDAP entry found\n"); exit(1); } free(ber); free(results); ldap_unbind_ext_s(ldp, NULL, NULL); } #ifdef UWSGI_ROUTING struct uwsgi_ldapauth_config { char *url; LDAPURLDesc *ldap_url; char *binddn; char *bindpw; char *basedn; char *filter; char *login_attr; int loglevel; }; static uint16_t ldap_passwd_check(struct uwsgi_ldapauth_config *ulc, char *auth) { char *colon = strchr(auth, ':'); if (!colon) return 0; int ret; uint16_t ulen = 0; LDAP *ldp; int desired_version = LDAP_VERSION3; #if LDAP_API_VERSION >= 3000 if ((ret = ldap_initialize(&ldp, ulc->url)) != LDAP_SUCCESS) { uwsgi_log("[router-ldapauth] can't connect to LDAP server at %s\n", ulc->url); return 0; } #else if ((ldp = ldap_init(ulc->ldap_url->lud_host, ulc->ldap_url->lud_port)) == NULL) { uwsgi_log("[router-ldapauth] can't connect to LDAP server at %s\n", ulc->url); return 0; } #endif if ((ret = ldap_set_option(ldp, LDAP_OPT_PROTOCOL_VERSION, &desired_version)) != LDAP_OPT_SUCCESS) { uwsgi_log("[router-ldapauth] LDAP protocol version mismatch: %s\n", ldap_err2string(ret)); goto close; } // first bind if needed if (ulc->binddn && ulc->bindpw) { #if LDAP_API_VERSION >= 3000 struct berval bval; bval.bv_val = ulc->bindpw; bval.bv_len = strlen(bval.bv_val); if ((ret = ldap_sasl_bind_s(ldp, ulc->binddn, LDAP_SASL_SIMPLE, &bval, NULL, NULL, NULL)) != LDAP_OPT_SUCCESS) { #else if ((ret = ldap_bind_s(ldp, ulc->binddn, ulc->bindpw, LDAP_AUTH_SIMPLE)) != LDAP_OPT_SUCCESS) { #endif uwsgi_log("[router-ldapauth] can't bind as user '%s' to '%s': %s\n", ulc->binddn, ulc->url, ldap_err2string(ret)); goto close; } } // search for user char *userdn = NULL; LDAPMessage *msg, *entry; // use the minimal amount of memory char *filter = uwsgi_malloc( strlen(ulc->login_attr) + (colon-auth) + strlen(ulc->filter) + 7); ret = snprintf(filter, 1024, "(&(%s=%.*s)%s)", ulc->login_attr, (int) (colon-auth), auth, ulc->filter); if (ret <= 0 || ret >= 1024) { free(filter); uwsgi_error("ldap_passwd_check()/sprintfn(filter)"); goto close; } if ((ret = ldap_search_ext_s(ldp, ulc->basedn, LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL, NULL, 0, &msg)) != LDAP_SUCCESS) { free(filter); uwsgi_log("[router-ldapauth] search error on '%s': %s\n", ulc->url, ldap_err2string(ret)); goto close; } else { free(filter); entry = ldap_first_entry(ldp, msg); while (entry) { struct berval **vals = ldap_get_values_len(ldp, entry, ulc->login_attr); if (!uwsgi_strncmp(auth, colon-auth, vals[0]->bv_val, vals[0]->bv_len)) { userdn = ldap_get_dn(ldp, entry); free(vals); break; } free(vals); entry = ldap_next_entry(ldp, entry); } ldap_msgfree(msg); } if (userdn) { // user found in ldap, try to bind #if LDAP_API_VERSION >= 3000 struct berval bval; bval.bv_val = colon+1; bval.bv_len = strlen(bval.bv_val); if ((ret = ldap_sasl_bind_s(ldp, userdn, LDAP_SASL_SIMPLE, &bval, NULL, NULL, NULL)) != LDAP_OPT_SUCCESS) { #else if ((ret = ldap_bind_s(ldp, userdn, colon+1, LDAP_AUTH_SIMPLE)) != LDAP_OPT_SUCCESS) { #endif if (ulc->loglevel) uwsgi_log("[router-ldapauth] can't bind as user '%s' to '%s': %s\n", userdn, ulc->url, ldap_err2string(ret)); } else { if (ulc->loglevel > 1) uwsgi_log("[router-ldapauth] successful bind as user '%s' to '%s'\n", userdn, ulc->url); ulen = colon-auth; } ldap_memfree(userdn); } else if (ulc->loglevel) { uwsgi_log("router-ldapauth] user '%.*s' not found in LDAP server at '%s'\n", colon-auth, auth, ulc->url); } close: if ((ret = ldap_unbind_ext_s(ldp, NULL, NULL)) != LDAP_OPT_SUCCESS) { uwsgi_log("[router-ldapauth] LDAP unbind error: %s\n", ldap_err2string(ret)); } return ulen; } int uwsgi_routing_func_ldapauth(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { // skip if already authenticated if (wsgi_req->remote_user_len > 0) { return UWSGI_ROUTE_NEXT; } if (wsgi_req->authorization_len > 7 && ur->data2) { if (strncmp(wsgi_req->authorization, "Basic ", 6)) goto forbidden; size_t auth_len = 0; char *auth = uwsgi_base64_decode(wsgi_req->authorization+6, wsgi_req->authorization_len-6, &auth_len); if (auth) { if (!ur->custom) { uint16_t ulen = ldap_passwd_check(ur->data2, auth); if (ulen > 0) { wsgi_req->remote_user = uwsgi_req_append(wsgi_req, "REMOTE_USER", 11, auth, ulen); if (wsgi_req->remote_user) wsgi_req->remote_user_len = ulen; } else if (ur->data3_len == 0) { free(auth); goto forbidden; } } free(auth); return UWSGI_ROUTE_NEXT; } } forbidden: if (uwsgi_response_prepare_headers(wsgi_req, "401 Authorization Required", 26)) goto end; char *realm = uwsgi_concat3n("Basic realm=\"", 13, ur->data, ur->data_len, "\"", 1); int ret = uwsgi_response_add_header(wsgi_req, "WWW-Authenticate", 16, realm, 13 + ur->data_len + 1); free(realm); if (ret) goto end; uwsgi_response_write_body_do(wsgi_req, "Unauthorized", 12); end: return UWSGI_ROUTE_BREAK; } static int uwsgi_router_ldapauth(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_ldapauth; char *comma = strchr(args, ','); if (!comma) { uwsgi_log("invalid route syntax: %s\n", args); exit(1); } *comma = 0; ur->data = args; ur->data_len = strlen(args); char *url = NULL; char *binddn = NULL; char *bindpw = NULL; char *basedn = NULL; char *filter = NULL; char *attr = NULL; char *loglevel = NULL; if (uwsgi_kvlist_parse(comma+1, strlen(comma+1), ';', '=', "url", &url, "binddn", &binddn, "bindpw", &bindpw, "basedn", &basedn, "filter", &filter, "attr", &attr, "loglevel", &loglevel, NULL)) { uwsgi_log("[router-ldapauth] unable to parse options: %s\n", comma+1); exit(1); } else { struct uwsgi_ldapauth_config *ulc = uwsgi_malloc(sizeof(struct uwsgi_ldapauth_config)); if (!basedn) { uwsgi_log("[router-ldapauth] missing LDAP base dn (basedn option) on line: %s\n", comma+1); exit(1); } else { ulc->basedn = basedn; } if (!url) { uwsgi_log("[router-ldapauth] missing LDAP server url (url option) on line: %s\n", comma+1); exit(1); } else { if (!ldap_is_ldap_url(url)) { uwsgi_log("[router-ldapauth] invalid LDAP url: %s\n", url); exit(1); } if (ldap_url_parse(url, &ulc->ldap_url) != LDAP_SUCCESS) { uwsgi_log("[router-ldapauth] unable to parse LDAP url: %s\n", url); exit(1); } } if (!filter) { ulc->filter = uwsgi_str("(objectClass=*)"); } else { ulc->filter = filter; } if (!attr) { ulc->login_attr = uwsgi_str("uid"); } else { ulc->login_attr = attr; } ulc->url = url; ulc->binddn = binddn; ulc->bindpw = bindpw; if (loglevel) { ulc->loglevel = atoi(loglevel); } else { ulc->loglevel = 0; } ur->data2 = ulc; } return 0; } static int uwsgi_router_ldapauth_next(struct uwsgi_route *ur, char *args) { ur->data3_len = 1; return uwsgi_router_ldapauth(ur, args); } #endif void uwsgi_ldap_register(void) { #ifdef UWSGI_ROUTING uwsgi_register_router("ldapauth", uwsgi_router_ldapauth); uwsgi_register_router("ldapauth-next", uwsgi_router_ldapauth_next); #endif } struct uwsgi_plugin ldap_plugin = { .name = "ldap", .options = uwsgi_ldap_options, .on_load = uwsgi_ldap_register, }; uwsgi-2.0.29/plugins/ldap/uwsgiplugin.py000066400000000000000000000001151477626554400203130ustar00rootroot00000000000000 NAME='ldap' CFLAGS = [] LDFLAGS = [] LIBS = ['-lldap'] GCC_LIST = ['ldap'] uwsgi-2.0.29/plugins/legion_cache_fetch/000077500000000000000000000000001477626554400202205ustar00rootroot00000000000000uwsgi-2.0.29/plugins/legion_cache_fetch/legion_cache_fetch.c000066400000000000000000000036221477626554400241400ustar00rootroot00000000000000#include extern struct uwsgi_server uwsgi; static int legion_action_cache_fetch_from_legion(struct uwsgi_legion *ul, char *arg) { uwsgi_log("[legion-cache-fetch] getting cache '%s' dump from legion '%s' nodes\n", arg, ul->legion); struct uwsgi_cache *uc = uwsgi_cache_by_name(arg); if (!uc) { uwsgi_log("[legion-cache-fetch] cannot sync, cache '%s' not found\n", arg); return 1; } struct uwsgi_string_list *dump_from_nodes = NULL; uwsgi_rlock(ul->lock); struct uwsgi_legion_node *legion_nodes = ul->nodes_head; while (legion_nodes) { char *dump_socket = NULL; if (uwsgi_kvlist_parse(legion_nodes->scroll, legion_nodes->scroll_len, ',', '=', "dump-socket", &dump_socket, NULL)) { uwsgi_log("[legion-cache-fetch] cannot sync from %.*s, cache socket address not found in legion scroll: %.*s\n", legion_nodes->name_len, legion_nodes->name, legion_nodes->scroll_len, legion_nodes->scroll); } else { if (dump_socket) { uwsgi_string_new_list(&dump_from_nodes, dump_socket); } else { uwsgi_log("[legion-cache-fetch] cannot sync from %.*s, cache socket address not found in legion scroll: %.*s\n", legion_nodes->name_len, legion_nodes->name, legion_nodes->scroll_len, legion_nodes->scroll); } } legion_nodes = legion_nodes->next; } // update uc->sync_nodes list struct uwsgi_string_list *usl = uc->sync_nodes; struct uwsgi_string_list *next; while (usl) { next = usl->next; free(usl->value); free(usl); usl = next; } uwsgi_rwunlock(ul->lock); uwsgi_rlock(uc->lock); uc->sync_nodes = dump_from_nodes; uwsgi_rwunlock(uc->lock); // call sync uwsgi_cache_sync_from_nodes(uc); return 0; } static void legion_cache_register() { uwsgi_legion_action_register("legion-cache-fetch", legion_action_cache_fetch_from_legion); } struct uwsgi_plugin legion_cache_fetch_plugin = { .name = "legion_cache_fetch", .on_load = legion_cache_register, }; uwsgi-2.0.29/plugins/legion_cache_fetch/uwsgiplugin.py000066400000000000000000000001441477626554400231460ustar00rootroot00000000000000 NAME = 'legion_cache_fetch' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['legion_cache_fetch'] uwsgi-2.0.29/plugins/libffi/000077500000000000000000000000001477626554400157025ustar00rootroot00000000000000uwsgi-2.0.29/plugins/libffi/libffi.c000066400000000000000000000034461477626554400173100ustar00rootroot00000000000000#include #include ffi_type *uwsgi_libffi_get_type(char *what, size_t *skip) { if (!uwsgi_startswith(what, "int:", 4)) { *skip = 4; return &ffi_type_sint32;} if (!uwsgi_startswith(what, "sint:", 5)) { *skip = 5; return &ffi_type_sint32;} if (!uwsgi_startswith(what, "uint:", 5)) { *skip = 5;return &ffi_type_uint32;} return &ffi_type_pointer; } void *uwsgi_libffi_get_value(char *what, ffi_type *t) { if (t == &ffi_type_sint32) { int32_t *num = uwsgi_malloc(sizeof(int32_t)); *num = atoi(what); return num; } return NULL; } static int uwsgi_libffi_hook(char *arg) { size_t argc = 0; size_t i; char **argv = uwsgi_split_quoted(arg, strlen(arg), " \t", &argc); if (!argc) goto end; void *func = dlsym(RTLD_DEFAULT, argv[0]); if (!func) goto destroy; ffi_cif cif; ffi_type **args_type = (ffi_type **) uwsgi_malloc(sizeof(ffi_type) * (argc-1)); void **values = uwsgi_malloc(sizeof(void*) * (argc-1)); for(i=1;i #include unsigned long long uwsgi_libtcc_counter = 0; static int uwsgi_libtcc_hook(char *arg) { char *func_base = "uwsgi_libtcc_func"; size_t func_len = strlen(func_base) + sizeof(UMAX64_STR); char *func_name = uwsgi_malloc(func_len); int ret = snprintf(func_name, func_len, "%s%llu", func_base, uwsgi_libtcc_counter); if (ret < (int) strlen(func_base) || ret >= (int) func_len) { free(func_name); return -1; } uwsgi_libtcc_counter++; size_t source_len = 64 + func_len + strlen(arg); char *source = uwsgi_malloc(source_len); ret = snprintf(source, source_len, "void %s() { %s ;}", func_name, arg); if (ret < (int) ( strlen(func_base) + strlen(arg)) || ret >= (int) (source_len)) { free(func_name); free(source); return -1; } TCCState *s = tcc_new(); if (tcc_compile_string(s, source)) goto error; if (tcc_relocate(s, TCC_RELOCATE_AUTO)) goto error; void (*func)() = tcc_get_symbol(s, func_name); if (!func) goto error; free(func_name); free(source); // call the function func(); tcc_delete(s); return 0; error: free(func_name); free(source); tcc_delete(s); return -1; } static void uwsgi_libtcc_setup() { uwsgi_register_hook("tcc", uwsgi_libtcc_hook); } struct uwsgi_plugin libtcc_plugin = { .name = "libtcc", .on_load = uwsgi_libtcc_setup, }; uwsgi-2.0.29/plugins/libtcc/uwsgiplugin.py000066400000000000000000000001061477626554400206330ustar00rootroot00000000000000NAME='libtcc' CFLAGS=[] LDFLAGS=[] LIBS=['-ltcc'] GCC_LIST=['libtcc'] uwsgi-2.0.29/plugins/logcrypto/000077500000000000000000000000001477626554400164715ustar00rootroot00000000000000uwsgi-2.0.29/plugins/logcrypto/logcrypto.c000066400000000000000000000124121477626554400206570ustar00rootroot00000000000000#include /* this is an UDP logger encrypting each packet with the choosen algo, key and iv. It is useful in cloud services without persistent storage for which you want to send logs to an external system. Syntax: --logger/--req-logger crypto:addr=,algo=,secret=,iv=,prefix= example: uwsgi --plugin logcrypto --logger crypto:addr=127.0.0.1:1717,algo=bf-cbc,secret=ciaociao -M -p 4 -s :3031 */ extern struct uwsgi_server uwsgi; struct uwsgi_crypto_logger_conf { EVP_CIPHER_CTX *encrypt_ctx; char *addr; char *algo; char *secret; char *iv; char *prefix; size_t prefix_len; }; static void uwsgi_crypto_logger_setup_encryption(struct uwsgi_crypto_logger_conf *uclc) { if (!uwsgi.ssl_initialized) { uwsgi_ssl_init(); } #if OPENSSL_VERSION_NUMBER < 0x10100000L uclc->encrypt_ctx = uwsgi_malloc(sizeof(EVP_CIPHER_CTX)); EVP_CIPHER_CTX_init(uclc->encrypt_ctx); #else uclc->encrypt_ctx = EVP_CIPHER_CTX_new(); #endif const EVP_CIPHER *cipher = EVP_get_cipherbyname(uclc->algo); if (!cipher) { uwsgi_log_safe("[uwsgi-logcrypto] unable to find algorithm/cipher\n"); exit(1); } int cipher_len = EVP_CIPHER_key_length(cipher); size_t s_len = strlen(uclc->secret); if ((unsigned int) cipher_len > s_len) { char *secret_tmp = uwsgi_malloc(cipher_len); memcpy(secret_tmp, uclc->secret, s_len); memset(secret_tmp + s_len, 0, cipher_len - s_len); uclc->secret = secret_tmp; } int iv_len = EVP_CIPHER_iv_length(cipher); size_t s_iv_len = 0; if (uclc->iv) { s_iv_len = strlen(uclc->iv); } if ((unsigned int) iv_len > s_iv_len) { char *secret_tmp = uwsgi_malloc(iv_len); memcpy(secret_tmp, uclc->iv, s_iv_len); memset(secret_tmp + s_iv_len, '0', iv_len - s_iv_len); uclc->iv = secret_tmp; } if (EVP_EncryptInit_ex(uclc->encrypt_ctx, cipher, NULL, (const unsigned char *) uclc->secret, (const unsigned char *) uclc->iv) <= 0) { uwsgi_error_safe("uwsgi_crypto_logger_setup_encryption()/EVP_EncryptInit_ex()"); exit(1); } } static ssize_t uwsgi_crypto_logger(struct uwsgi_logger *ul, char *message, size_t len) { struct uwsgi_crypto_logger_conf *uclc = (struct uwsgi_crypto_logger_conf *) ul->data; if (!ul->configured) { uclc = uwsgi_calloc(sizeof(struct uwsgi_crypto_logger_conf)); if (uwsgi_kvlist_parse(ul->arg, strlen(ul->arg), ',', '=', "addr", &uclc->addr, "algo", &uclc->algo, "secret", &uclc->secret, "iv", &uclc->iv, "prefix", &uclc->prefix, NULL)) { uwsgi_log_safe("[uwsgi-logcrypto] unable to parse options\n"); exit(1); } if (!uclc->addr || !uclc->algo || !uclc->secret) { uwsgi_log_safe("[uwsgi-logcrypto] you have to specify at least addr,algo and secret options\n"); exit(1); } if (uclc->prefix) { uclc->prefix_len = strlen(uclc->prefix); } char *colon = strchr(uclc->addr, ':'); if (!colon) { uwsgi_log_safe("[uwsgi-logcrypto] invalid UDP address\n"); exit(1); } ul->addr_len = socket_to_in_addr(uclc->addr, colon, 0, &ul->addr.sa_in); ul->fd = socket(AF_INET, SOCK_DGRAM, 0); if (ul->fd < 0) { uwsgi_error_safe("uwsgi_crypto_logger()/socket()"); exit(1); } uwsgi_crypto_logger_setup_encryption(uclc); ul->data = uclc; ul->configured = 1; } struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); if (uwsgi_buffer_num64(ub, uwsgi_micros())) goto error; if (uwsgi_buffer_append(ub, " ", 1)) goto error; if (uclc->prefix) { if (uwsgi_buffer_append(ub, uclc->prefix, uclc->prefix_len)) goto error; if (uwsgi_buffer_append(ub, " ", 1)) goto error; } if (uwsgi_buffer_append(ub, message, len)) goto error; // let's encrypt the message unsigned char *encrypted = uwsgi_malloc(ub->pos + EVP_MAX_BLOCK_LENGTH); if (EVP_EncryptInit_ex(uclc->encrypt_ctx, NULL, NULL, NULL, NULL) <= 0) { uwsgi_error_safe("[uwsgi-logcrypto] EVP_EncryptInit_ex()"); free(encrypted); goto error; } int e_len = 0; if (EVP_EncryptUpdate(uclc->encrypt_ctx, encrypted, &e_len, (unsigned char *) ub->buf, ub->pos) <= 0) { uwsgi_error("[uwsgi-logcrypto] EVP_EncryptUpdate()"); free(encrypted); goto error; } int tmplen = 0; if (EVP_EncryptFinal_ex(uclc->encrypt_ctx, encrypted + e_len, &tmplen) <= 0) { uwsgi_error("[uwsgi-logcrypto] EVP_EncryptFinal_ex()"); free(encrypted); goto error; } uwsgi_buffer_destroy(ub); ssize_t rlen = sendto(ul->fd, encrypted, e_len + tmplen, 0, (struct sockaddr *) &ul->addr.sa_in, ul->addr_len); free(encrypted); return rlen; error: uwsgi_buffer_destroy(ub); return -1; } static void uwsgi_logcrypto_register() { uwsgi_register_logger("crypto", uwsgi_crypto_logger); } struct uwsgi_plugin logcrypto_plugin = { .name = "logcrypto", .on_load = uwsgi_logcrypto_register, }; uwsgi-2.0.29/plugins/logcrypto/uwsgiplugin.py000066400000000000000000000001161477626554400214160ustar00rootroot00000000000000NAME='logcrypto' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['logcrypto'] uwsgi-2.0.29/plugins/logfile/000077500000000000000000000000001477626554400160705ustar00rootroot00000000000000uwsgi-2.0.29/plugins/logfile/logfile.c000066400000000000000000000046661477626554400176710ustar00rootroot00000000000000#include extern struct uwsgi_server uwsgi; struct logfile_data { char *logfile; char *backupname; uint64_t maxsize; }; static ssize_t uwsgi_file_logger(struct uwsgi_logger *ul, char *message, size_t len) { if (!ul->configured) { if (ul->arg) { int is_keyval = 0; char *backupname = NULL; char *maxsize = NULL; char *logfile = NULL; if (strchr(ul->arg, '=')) { if (uwsgi_kvlist_parse(ul->arg, strlen(ul->arg), ',', '=', "logfile", &logfile, "backupname", &backupname, "maxsize", &maxsize, NULL)) { uwsgi_log("[uwsgi-logfile] invalid keyval syntax\n"); exit(1); } is_keyval = 1; } if (is_keyval) { if (!logfile) { uwsgi_log("[uwsgi-logfile] missing logfile key\n"); return 0; } if (maxsize) { struct logfile_data *data = uwsgi_malloc(sizeof(struct logfile_data)); data->logfile = logfile; data->backupname = backupname; data->maxsize = (uint64_t)strtoull(maxsize, NULL, 10); ul->data = data; free(maxsize); maxsize = NULL; } } else { logfile = ul->arg; } ul->fd = open(logfile, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP); if (ul->fd >= 0) { ul->configured = 1; } } } if (ul->fd >= 0) { ssize_t written = write(ul->fd, message, len); if (ul->data) { struct logfile_data *data = ul->data; off_t logsize = lseek(ul->fd, 0, SEEK_CUR); if (data->maxsize > 0 && (uint64_t) logsize > data->maxsize) { uwsgi_log_do_rotate(data->logfile, data->backupname, logsize, ul->fd); } } return written; } return 0; } static ssize_t uwsgi_fd_logger(struct uwsgi_logger *ul, char *message, size_t len) { if (!ul->configured) { ul->fd = -1; if (ul->arg) ul->fd = atoi(ul->arg); ul->configured = 1; } if (ul->fd >= 0) { return write(ul->fd, message, len); } return 0; } static ssize_t uwsgi_stdio_logger(struct uwsgi_logger *ul, char *message, size_t len) { if (uwsgi.original_log_fd >= 0) { return write(uwsgi.original_log_fd, message, len); } return 0; } void uwsgi_file_logger_register() { uwsgi_register_logger("file", uwsgi_file_logger); uwsgi_register_logger("fd", uwsgi_fd_logger); uwsgi_register_logger("stdio", uwsgi_stdio_logger); } struct uwsgi_plugin logfile_plugin = { .name = "logfile", .on_load = uwsgi_file_logger_register, }; uwsgi-2.0.29/plugins/logfile/uwsgiplugin.py000066400000000000000000000001121477626554400210110ustar00rootroot00000000000000NAME='logfile' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['logfile'] uwsgi-2.0.29/plugins/logpipe/000077500000000000000000000000001477626554400161065ustar00rootroot00000000000000uwsgi-2.0.29/plugins/logpipe/logpipe.c000066400000000000000000000022421477626554400177110ustar00rootroot00000000000000#include /* The pipe logger Author: INADA Naoki every log line is sent to the stdin of an external process Example: req-logger = pipe:/usr/local/bin/mylogger */ static ssize_t uwsgi_pipe_logger(struct uwsgi_logger *ul, char *message, size_t len) { if (!ul->configured) { if (ul->arg) { int pipefd[2]; // retry later... if (pipe(pipefd) < 0) return -1; pid_t pid = fork(); if (pid < 0) return -1; if (pid > 0) { close(pipefd[0]); ul->fd = pipefd[1]; } else { // child if (setsid() < 0) { uwsgi_error("setsid()"); exit(1); } close(pipefd[1]); dup2(pipefd[0], STDIN_FILENO); close(pipefd[0]); uwsgi_exec_command_with_args(ul->arg); exit(1); // if here something seriously failed } } ul->configured = 1; } int err = write(ul->fd, message, len); // on failed writes, re-configure the logger if (err <= 0) { close(ul->fd); ul->configured = 0; return err; } return 0; } static void uwsgi_pipe_logger_register() { uwsgi_register_logger("pipe", uwsgi_pipe_logger); } struct uwsgi_plugin logpipe_plugin = { .name = "logpipe", .on_load = uwsgi_pipe_logger_register, }; uwsgi-2.0.29/plugins/logpipe/uwsgiplugin.py000066400000000000000000000001121477626554400210270ustar00rootroot00000000000000NAME='logpipe' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['logpipe'] uwsgi-2.0.29/plugins/logsocket/000077500000000000000000000000001477626554400164415ustar00rootroot00000000000000uwsgi-2.0.29/plugins/logsocket/logsocket_plugin.c000066400000000000000000000031101477626554400221500ustar00rootroot00000000000000#include "../../uwsgi.h" extern struct uwsgi_server uwsgi; ssize_t uwsgi_socket_logger(struct uwsgi_logger *ul, char *message, size_t len) { int family = AF_UNIX; if (!ul->configured) { char *comma = strchr(ul->arg, ','); if (comma) { ul->data = comma+1; *comma = 0; } char *colon = strchr(ul->arg, ':'); if (colon) { family = AF_INET; ul->addr_len = socket_to_in_addr(ul->arg, colon, 0, &ul->addr.sa_in); } else { ul->addr_len = socket_to_un_addr(ul->arg, &ul->addr.sa_un); } ul->fd = socket(family, SOCK_DGRAM, 0); if (ul->fd < 0) { uwsgi_error_safe("socket()"); exit(1); } memset(&ul->msg, 0, sizeof(struct msghdr)); ul->msg.msg_name = &ul->addr; ul->msg.msg_namelen = ul->addr_len; if (ul->data) { ul->msg.msg_iov = uwsgi_malloc(sizeof(struct iovec) * 2); ul->msg.msg_iov[0].iov_base = ul->data; ul->msg.msg_iov[0].iov_len = strlen(ul->data); ul->msg.msg_iovlen = 2; ul->count = 1; } else { ul->msg.msg_iov = uwsgi_malloc(sizeof(struct iovec)); ul->msg.msg_iovlen = 1; ul->count = 0; } if (comma) { *comma = ',' ; } ul->configured = 1; } ul->msg.msg_iov[ul->count].iov_base = message; ul->msg.msg_iov[ul->count].iov_len = len; return sendmsg(ul->fd, &ul->msg, 0); } void uwsgi_logsocket_register() { uwsgi_register_logger("socket", uwsgi_socket_logger); } struct uwsgi_plugin logsocket_plugin = { .name = "logsocket", .on_load = uwsgi_logsocket_register, }; uwsgi-2.0.29/plugins/logsocket/uwsgiplugin.py000066400000000000000000000001251477626554400213660ustar00rootroot00000000000000NAME='logsocket' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['logsocket_plugin'] uwsgi-2.0.29/plugins/logzmq/000077500000000000000000000000001477626554400157605ustar00rootroot00000000000000uwsgi-2.0.29/plugins/logzmq/plugin.c000066400000000000000000000033171477626554400174260ustar00rootroot00000000000000#include #include extern struct uwsgi_server uwsgi; static struct uwsgi_option uwsgi_zmq_logger_options[] = { {"log-zeromq", required_argument, 0, "send logs to a zeromq server", uwsgi_opt_set_logger, "zeromq", UWSGI_OPT_MASTER | UWSGI_OPT_LOG_MASTER}, {NULL, 0, 0, NULL, NULL, NULL, 0}, }; // the zeromq logger static ssize_t uwsgi_zeromq_logger(struct uwsgi_logger *ul, char *message, size_t len) { if (!ul->configured) { if (!ul->arg) { uwsgi_log_safe("invalid zeromq syntax\n"); exit(1); } void *ctx = zmq_init(1); if (!ctx) exit(1); ul->data = zmq_socket(ctx, ZMQ_PUSH); if (ul->data == NULL) { uwsgi_error_safe("zmq_socket()"); exit(1); } if (zmq_connect(ul->data, ul->arg) < 0) { uwsgi_error_safe("zmq_connect()"); exit(1); } ul->configured = 1; } zmq_msg_t msg; if (zmq_msg_init_size(&msg, len) == 0) { memcpy(zmq_msg_data(&msg), message, len); #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) zmq_sendmsg(ul->data, &msg, 0); #else zmq_send(ul->data, &msg, 0); #endif zmq_msg_close(&msg); } return 0; } static void uwsgi_zmq_logger_register() { uwsgi_register_logger("zmq", uwsgi_zeromq_logger); uwsgi_register_logger("zeromq", uwsgi_zeromq_logger); } struct uwsgi_plugin logzmq_plugin = { .name = "logzmq", .options = uwsgi_zmq_logger_options, .on_load = uwsgi_zmq_logger_register, }; uwsgi-2.0.29/plugins/logzmq/uwsgiplugin.py000066400000000000000000000001201477626554400207000ustar00rootroot00000000000000 NAME='logzmq' CFLAGS = [] LDFLAGS = [] LIBS = ['-lzmq'] GCC_LIST = ['plugin'] uwsgi-2.0.29/plugins/lua/000077500000000000000000000000001477626554400152305ustar00rootroot00000000000000uwsgi-2.0.29/plugins/lua/lua_plugin.c000066400000000000000000000646471477626554400175540ustar00rootroot00000000000000#include #include #include #include #if LUA_VERSION_NUM < 502 # define luaL_newuwsgilib(L,l) luaL_register(L, "uwsgi",l) # define lua_rawlen lua_objlen #else # define luaL_newuwsgilib(L,l) lua_newtable(L);luaL_setfuncs (L, l, 0);lua_pushvalue(L,-1);lua_setglobal(L,"uwsgi") #endif extern struct uwsgi_server uwsgi; struct uwsgi_lua { struct lua_State **L; char *shell; char *filename; struct uwsgi_string_list *load; int gc_freq; } ulua; struct uwsgi_plugin lua_plugin; #define lca(L, n) ulua_check_args(L, __FUNCTION__, n) static void uwsgi_opt_luashell(char *opt, char *value, void *foobar) { uwsgi.honour_stdin = 1; if (value) { ulua.shell = value; } else { ulua.shell = ""; } } static struct uwsgi_option uwsgi_lua_options[] = { {"lua", required_argument, 0, "load lua wsapi app", uwsgi_opt_set_str, &ulua.filename, 0}, {"lua-load", required_argument, 0, "load a lua file", uwsgi_opt_add_string_list, &ulua.load, 0}, {"lua-shell", no_argument, 0, "run the lua interactive shell (debug.debug())", uwsgi_opt_luashell, NULL, 0}, {"luashell", no_argument, 0, "run the lua interactive shell (debug.debug())", uwsgi_opt_luashell, NULL, 0}, {"lua-gc-freq", no_argument, 0, "set the lua gc frequency (default: 0, runs after every request)", uwsgi_opt_set_int, &ulua.gc_freq, 0}, {0, 0, 0, 0}, }; static void ulua_check_args(lua_State *L, const char *func, int n) { int args = lua_gettop(L); char error[1024]; if (args != n) { if (n == 1) { snprintf(error, 1024, "uwsgi.%s takes 1 parameter", func+10); } else { snprintf(error, 1024, "uwsgi.%s takes %d parameters", func+10, n); } lua_pushstring(L, error); lua_error(L); } } static int uwsgi_api_log(lua_State *L) { const char *logline ; lca(L, 1); if (lua_isstring(L, 1)) { logline = lua_tolstring(L, 1, NULL); uwsgi_log( "%s\n", logline); } return 0; } static int uwsgi_api_register_rpc(lua_State *L) { uint8_t argc = lua_gettop(L); const char *name; // a hack for 64bit; int func; long lfunc; if (argc < 2) { lua_pushnil(L); return 1; } name = lua_tolstring(L, 1, NULL); lua_pushvalue(L, 2); func = luaL_ref(L, LUA_REGISTRYINDEX); uwsgi_log("registered function %d in Lua global table\n", func); lfunc = func; if (uwsgi_register_rpc((char *)name, &lua_plugin, 0, (void *) lfunc)) { lua_pushnil(L); } else { lua_pushboolean(L, 1); } return 1; } static int uwsgi_api_cache_set(lua_State *L) { uint8_t argc = lua_gettop(L); const char *key ; const char *value ; uint64_t expires = 0; size_t vallen; size_t keylen; const char *cache = NULL; if (argc < 2) goto error; key = lua_tolstring(L, 1, &keylen); value = lua_tolstring(L, 2, &vallen); if (argc > 2) { expires = lua_tonumber(L, 3); if (argc > 3) { cache = lua_tolstring(L, 4, NULL); } } if (!uwsgi_cache_magic_set((char *)key, keylen, (char *)value, vallen, expires, 0, (char *) cache)) { lua_pushboolean(L, 1); return 1; } error: lua_pushnil(L); return 1; } static int uwsgi_api_cache_update(lua_State *L) { uint8_t argc = lua_gettop(L); const char *key ; const char *value ; uint64_t expires = 0; size_t vallen; size_t keylen; const char *cache = NULL; if (argc < 2) goto error; key = lua_tolstring(L, 1, &keylen); value = lua_tolstring(L, 2, &vallen); if (argc > 2) { expires = lua_tonumber(L, 3); if (argc > 3) { cache = lua_tolstring(L, 4, NULL); } } if (!uwsgi_cache_magic_set((char *)key, keylen, (char *)value, vallen, expires, UWSGI_CACHE_FLAG_UPDATE, (char *)cache)) { lua_pushboolean(L, 1); return 1; } error: lua_pushnil(L); return 1; } static int uwsgi_api_register_signal(lua_State *L) { int args = lua_gettop(L); uint8_t sig; long lhandler; const char *who; if (args >= 3) { sig = lua_tonumber(L, 1); who = lua_tostring(L, 2); lua_pushvalue(L, 3); lhandler = luaL_ref(L, LUA_REGISTRYINDEX); uwsgi_register_signal(sig, (char *)who, (void *) lhandler, 6); } lua_pushnil(L); return 1; } static int uwsgi_api_cache_clear(lua_State *L) { const char *cache = NULL; uint8_t argc = lua_gettop(L); if (argc > 0) { cache = lua_tolstring(L, 2, NULL); } if (!uwsgi_cache_magic_clear((char *)cache)) { lua_pushboolean(L, 1); return 1; } lua_pushnil(L); return 1; } static int uwsgi_api_cache_del(lua_State *L) { size_t keylen; const char *key ; const char *cache = NULL; uint8_t argc = lua_gettop(L); if (argc == 0) goto error; if (lua_isstring(L, 1)) { // get the key key = lua_tolstring(L, 1, &keylen); if (argc > 1) { cache = lua_tolstring(L, 2, NULL); } if (!uwsgi_cache_magic_del((char *)key, keylen, (char *)cache)) { lua_pushboolean(L, 1); return 1; } } error: lua_pushnil(L); return 1; } static int uwsgi_api_cache_exists(lua_State *L) { size_t keylen; const char *key ; const char *cache = NULL; uint8_t argc = lua_gettop(L); if (argc == 0) goto error; if (lua_isstring(L, 1)) { // get the key key = lua_tolstring(L, 1, &keylen); if (argc > 1) { cache = lua_tolstring(L, 2, NULL); } if (uwsgi_cache_magic_exists((char *)key, keylen,(char *)cache)) { lua_pushboolean(L, 1); return 1; } } error: lua_pushnil(L); return 1; } static int uwsgi_api_async_sleep(lua_State *L) { uint8_t argc = lua_gettop(L); if (argc == 0) goto end; struct wsgi_request *wsgi_req = current_wsgi_req(); int timeout = lua_tonumber(L, 1); if (timeout >= 0) { async_add_timeout(wsgi_req, timeout); } end: lua_pushnil(L); return 1; } static int uwsgi_api_wait_fd_read(lua_State *L) { uint8_t argc = lua_gettop(L); if (argc == 0) goto end; struct wsgi_request *wsgi_req = current_wsgi_req(); int fd = lua_tonumber(L, 1); int timeout = 0; if (argc > 1) { timeout = lua_tonumber(L, 2); } if (async_add_fd_read(wsgi_req, fd, timeout)) { lua_pushstring(L, "unable to call async_add_fd_read()"); lua_error(L); return 0; } end: lua_pushnil(L); return 1; } static int uwsgi_api_wait_fd_write(lua_State *L) { uint8_t argc = lua_gettop(L); if (argc == 0) goto end; struct wsgi_request *wsgi_req = current_wsgi_req(); int fd = lua_tonumber(L, 1); int timeout = 0; if (argc > 1) { timeout = lua_tonumber(L, 2); } if (async_add_fd_write(wsgi_req, fd, timeout)) { lua_pushstring(L, "unable to call async_add_fd_write()"); lua_error(L); return 0; } end: lua_pushnil(L); return 1; } static int uwsgi_api_async_connect(lua_State *L) { uint8_t argc = lua_gettop(L); if (argc == 0) goto end; int fd = uwsgi_connect((char *)lua_tostring(L, 1), 0, 1); lua_pushnumber(L, fd); return 1; end: lua_pushnil(L); return 1; } static int uwsgi_api_is_connected(lua_State *L) { uint8_t argc = lua_gettop(L); if (argc == 0) goto end; int fd = lua_tonumber(L, 1); if (uwsgi_is_connected(fd)) { lua_pushboolean(L, 1); return 1; } lua_pushboolean(L, 0); return 1; end: lua_pushnil(L); return 1; } static int uwsgi_api_close(lua_State *L) { uint8_t argc = lua_gettop(L); if (argc == 0) goto end; int fd = lua_tonumber(L, 1); close(fd); end: lua_pushnil(L); return 1; } static int uwsgi_api_ready_fd(lua_State *L) { struct wsgi_request *wsgi_req = current_wsgi_req(); int fd = uwsgi_ready_fd(wsgi_req); lua_pushnumber(L, fd); return 1; } static int uwsgi_api_websocket_handshake(lua_State *L) { uint8_t argc = lua_gettop(L); const char *key = NULL, *origin = NULL, *proto = NULL; size_t key_len = 0, origin_len = 0, proto_len = 0; if (argc > 0) { key = lua_tolstring(L, 1, &key_len); if (argc > 1) { origin = lua_tolstring(L, 2, &origin_len); if (argc > 2) { proto = lua_tolstring(L, 3, &proto_len); } } } struct wsgi_request *wsgi_req = current_wsgi_req(); if (uwsgi_websocket_handshake(wsgi_req, (char *)key, key_len, (char *)origin, origin_len, (char *) proto, proto_len)) { goto error; } lua_pushnil(L); return 1; error: lua_pushstring(L, "unable to complete websocket handshake"); lua_error(L); return 0; } static int uwsgi_api_websocket_send(lua_State *L) { uint8_t argc = lua_gettop(L); if (argc == 0) goto error; size_t message_len = 0; const char *message = lua_tolstring(L, 1, &message_len); struct wsgi_request *wsgi_req = current_wsgi_req(); if (uwsgi_websocket_send(wsgi_req, (char *) message, message_len)) { goto error; } lua_pushnil(L); return 1; error: lua_pushstring(L, "unable to send websocket message"); lua_error(L); return 0; } static int uwsgi_api_websocket_send_binary(lua_State *L) { uint8_t argc = lua_gettop(L); if (argc == 0) goto error; size_t message_len = 0; const char *message = lua_tolstring(L, 1, &message_len); struct wsgi_request *wsgi_req = current_wsgi_req(); if (uwsgi_websocket_send_binary(wsgi_req, (char *) message, message_len)) { goto error; } lua_pushnil(L); return 1; error: lua_pushstring(L, "unable to send websocket binary message"); lua_error(L); return 0; } static int uwsgi_api_websocket_send_from_sharedarea(lua_State *L) { uint8_t argc = lua_gettop(L); if (argc < 2) goto error; int id = lua_tonumber(L, 1); uint64_t pos = lua_tonumber(L, 2); uint64_t len = 0; if (argc > 2) { len = lua_tonumber(L, 3); } struct wsgi_request *wsgi_req = current_wsgi_req(); if (uwsgi_websocket_send_from_sharedarea(wsgi_req, id, pos, len)) { goto error; } lua_pushnil(L); return 1; error: lua_pushstring(L, "unable to send websocket message from sharedarea"); lua_error(L); return 0; } static int uwsgi_api_websocket_send_binary_from_sharedarea(lua_State *L) { uint8_t argc = lua_gettop(L); if (argc < 2) goto error; int id = lua_tonumber(L, 1); uint64_t pos = lua_tonumber(L, 2); uint64_t len = 0; if (argc > 2) { len = lua_tonumber(L, 3); } struct wsgi_request *wsgi_req = current_wsgi_req(); if (uwsgi_websocket_send_binary_from_sharedarea(wsgi_req, id, pos, len)) { goto error; } lua_pushnil(L); return 1; error: lua_pushstring(L, "unable to send websocket message from sharedarea"); lua_error(L); return 0; } static int uwsgi_api_websocket_recv(lua_State *L) { struct wsgi_request *wsgi_req = current_wsgi_req(); struct uwsgi_buffer *ub = uwsgi_websocket_recv(wsgi_req); if (!ub) { lua_pushstring(L, "unable to receive websocket message"); lua_error(L); return 0; } lua_pushlstring(L, ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return 1; } static int uwsgi_api_websocket_recv_nb(lua_State *L) { struct wsgi_request *wsgi_req = current_wsgi_req(); struct uwsgi_buffer *ub = uwsgi_websocket_recv_nb(wsgi_req); if (!ub) { lua_pushstring(L, "unable to receive websocket message"); lua_error(L); return 0; } lua_pushlstring(L, ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return 1; } static int uwsgi_api_cache_get(lua_State *L) { char *value ; uint64_t valsize; size_t keylen; const char *key ; const char *cache = NULL; uint8_t argc = lua_gettop(L); if (argc == 0) goto error; if (lua_isstring(L, 1)) { // get the key key = lua_tolstring(L, 1, &keylen); if (argc > 1) { cache = lua_tolstring(L, 2, NULL); } value = uwsgi_cache_magic_get((char *)key, keylen, &valsize, NULL, (char *)cache); if (value) { lua_pushlstring(L, value, valsize); free(value); return 1; } } error: lua_pushnil(L); return 1; } static int uwsgi_api_req_fd(lua_State *L) { struct wsgi_request *wsgi_req = current_wsgi_req(); lua_pushnumber(L, wsgi_req->fd); return 1; } static int uwsgi_api_lock(lua_State *L) { int lock_num = 0; // the spooler cannot lock resources if (uwsgi.i_am_a_spooler) { lua_pushstring(L, "The spooler cannot lock/unlock resources"); lua_error(L); } if (lua_gettop(L) > 0) { lock_num = lua_isnumber(L, 1) ? lua_tonumber(L, 1) : -1; if (lock_num < 0 || lock_num > uwsgi.locks) { lua_pushstring(L, "Invalid lock number"); lua_error(L); } } uwsgi_lock(uwsgi.user_lock[lock_num]); return 0; } static int uwsgi_api_unlock(lua_State *L) { int lock_num = 0; // the spooler cannot lock resources if (uwsgi.i_am_a_spooler) { lua_pushstring(L, "The spooler cannot lock/unlock resources"); lua_error(L); } if (lua_gettop(L) > 0) { lock_num = lua_isnumber(L, 1) ? lua_tonumber(L, 1) : -1; if (lock_num < 0 || lock_num > uwsgi.locks) { lua_pushstring(L, "Invalid lock number"); lua_error(L); } } uwsgi_unlock(uwsgi.user_lock[lock_num]); return 0; } static const luaL_Reg uwsgi_api[] = { {"log", uwsgi_api_log}, {"connection_fd", uwsgi_api_req_fd}, {"cache_get", uwsgi_api_cache_get}, {"cache_set", uwsgi_api_cache_set}, {"cache_update", uwsgi_api_cache_update}, {"cache_del", uwsgi_api_cache_del}, {"cache_exists", uwsgi_api_cache_exists}, {"cache_clear", uwsgi_api_cache_clear}, {"register_signal", uwsgi_api_register_signal}, {"register_rpc", uwsgi_api_register_rpc}, {"websocket_handshake", uwsgi_api_websocket_handshake}, {"websocket_recv", uwsgi_api_websocket_recv}, {"websocket_recv_nb", uwsgi_api_websocket_recv_nb}, {"websocket_send", uwsgi_api_websocket_send}, {"websocket_send_from_sharedarea", uwsgi_api_websocket_send_from_sharedarea}, {"websocket_send_binary", uwsgi_api_websocket_send_binary}, {"websocket_send_binary_from_sharedarea", uwsgi_api_websocket_send_binary_from_sharedarea}, {"lock", uwsgi_api_lock}, {"unlock", uwsgi_api_unlock}, {"async_sleep", uwsgi_api_async_sleep}, {"async_connect", uwsgi_api_async_connect}, {"is_connected", uwsgi_api_is_connected}, {"close", uwsgi_api_close}, {"wait_fd_read", uwsgi_api_wait_fd_read}, {"wait_fd_write", uwsgi_api_wait_fd_write}, {"ready_fd", uwsgi_api_ready_fd}, {NULL, NULL} }; static int uwsgi_lua_input(lua_State *L) { struct wsgi_request *wsgi_req = current_wsgi_req(); ssize_t sum = 0; int n = lua_gettop(L); if (n > 1) { sum = lua_tonumber(L, 2); } ssize_t rlen = 0; char *buf = uwsgi_request_body_read(wsgi_req, sum, &rlen); if (buf) { lua_pushlstring(L, buf, rlen); return 1; } return 0; } static int uwsgi_lua_init(){ uwsgi_log("Initializing Lua environment... (%d lua_States)\n", uwsgi.cores); ulua.L = uwsgi_malloc( sizeof(lua_State*) * uwsgi.cores ); // ok the lua engine is ready return 0; } static void uwsgi_lua_app() { int i; if (!ulua.filename && !ulua.load && !ulua.shell) return; for(i=0;ivalue)) { uwsgi_log("unable to load Lua file %s: %s\n", usl->value, lua_tostring(ulua.L[i], -1)); exit(1); } usl = usl->next; } if (ulua.filename) { if (luaL_loadfile(ulua.L[i], ulua.filename)) { uwsgi_log("unable to load Lua file %s: %s\n", ulua.filename, lua_tostring(ulua.L[i], -1)); exit(1); } // use a pcall //lua_call(ulua.L[i], 0, 1); if (lua_pcall(ulua.L[i], 0, 1, 0) != 0) { uwsgi_log("%s\n", lua_tostring(ulua.L[i], -1)); exit(1); } // if the loaded lua app returns as a table, fetch the // run function. if (lua_istable(ulua.L[i], 2)) { lua_pushstring(ulua.L[i], "run" ); lua_gettable(ulua.L[i], 2); lua_replace(ulua.L[i], 2); } if (! lua_isfunction(ulua.L[i], 2)) { uwsgi_log("Can't find WSAPI entry point (no function, nor a table with function'run').\n"); exit(1); } } } } static int uwsgi_lua_request(struct wsgi_request *wsgi_req) { int i; const char *http, *http2; size_t slen, slen2; char *ptrbuf; lua_State *L = ulua.L[wsgi_req->async_id]; if (wsgi_req->async_status == UWSGI_AGAIN) { if ((i = lua_pcall(L, 0, 1, 0)) == 0) { if (lua_type(L, -1) == LUA_TSTRING) { http = lua_tolstring(L, -1, &slen); uwsgi_response_write_body_do(wsgi_req, (char *)http, slen); } lua_pop(L, 1); lua_pushvalue(L, -1); return UWSGI_AGAIN; } goto clear; } /* Standard WSAPI request */ if (!wsgi_req->uh->pktsize) { uwsgi_log( "Empty lua request. skip.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } // put function in the stack //lua_getfield(L, LUA_GLOBALSINDEX, "run"); lua_pushvalue(L, -1); // put cgi vars in the stack lua_newtable(L); lua_pushstring(L, ""); lua_setfield(L, -2, "CONTENT_TYPE"); for(i=0;ivar_cnt;i+=2) { lua_pushlstring(L, (char *)wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len); // transform it in a valid c string TODO this is ugly ptrbuf = wsgi_req->hvec[i].iov_base+wsgi_req->hvec[i].iov_len; *ptrbuf = 0; lua_setfield(L, -2, (char *)wsgi_req->hvec[i].iov_base); } // put "input" table lua_newtable(L); lua_pushcfunction(L, uwsgi_lua_input); lua_setfield(L, -2, "read"); lua_setfield(L, -2, "input"); #ifdef UWSGI_DEBUG uwsgi_log("stack pos %d\n", lua_gettop(L)); #endif // call function i = lua_pcall(L, 1, 3, 0); if (i != 0) { uwsgi_log("%s\n", lua_tostring(L, -1)); lua_pop(L, 1); lua_pushvalue(L, -1); goto clear2; } //uwsgi_log("%d %s %s %s\n",i,lua_typename(L, lua_type(L, -3)), lua_typename(L, lua_type(L, -2)) , lua_typename(L, lua_type(L, -1))); // send status if (lua_type(L, -3) == LUA_TSTRING || lua_type(L, -3) == LUA_TNUMBER) { http = lua_tolstring(L, -3, &slen); if (uwsgi_response_prepare_headers(wsgi_req, (char *) http, slen)) goto clear2; } else { uwsgi_log("[uwsgi-lua] invalid response status !!!\n"); // let's continue } // send headers lua_pushnil(L); while(lua_next(L, -3) != 0) { http = lua_tolstring(L, -2, &slen); if (lua_type(L, -1) == LUA_TTABLE) { for (i = 1; /*empty*/ ; ++i) { lua_rawgeti(L, -1, i); if (lua_isnil(L, -1)) { lua_pop(L, 1); break; } http2 = lua_tolstring(L, -1, &slen2); uwsgi_response_add_header(wsgi_req, (char *) http, slen, (char *) http2, slen2); lua_pop(L, 1); } } else { http2 = lua_tolstring(L, -1, &slen2); uwsgi_response_add_header(wsgi_req, (char *) http, slen, (char *) http2, slen2); } lua_pop(L, 1); } // send body with coroutine lua_pushvalue(L, -1); while ( (i = lua_pcall(L, 0, 1, 0)) == 0) { if (lua_type(L, -1) == LUA_TSTRING) { http = lua_tolstring(L, -1, &slen); uwsgi_response_write_body_do(wsgi_req, (char *)http, slen); } lua_pop(L, 1); lua_pushvalue(L, -1); if (uwsgi.async > 1) { return UWSGI_AGAIN; } } clear: lua_pop(L, 4); clear2: // set frequency if (!ulua.gc_freq || uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].requests % ulua.gc_freq == 0) { lua_gc(L, LUA_GCCOLLECT, 0); } return UWSGI_OK; } static void uwsgi_lua_after_request(struct wsgi_request *wsgi_req) { log_request(wsgi_req); } static int uwsgi_lua_magic(char *mountpoint, char *lazy) { if (!strcmp(lazy+strlen(lazy)-4, ".lua")) { ulua.filename = lazy; return 1; } else if (!strcmp(lazy+strlen(lazy)-3, ".ws")) { ulua.filename = lazy; return 1; } return 0; } static char *uwsgi_lua_code_string(char *id, char *code, char *func, char *key, uint16_t keylen) { static struct lua_State *L = NULL; if (!L) { L = luaL_newstate(); luaL_openlibs(L); if (luaL_loadfile(L, code) || lua_pcall(L, 0, 0, 0)) { uwsgi_log("unable to load file %s: %s\n", code, lua_tostring(L, -1)); lua_close(L); L = NULL; return NULL; } lua_getglobal(L, func); if (!lua_isfunction(L,-1)) { uwsgi_log("unable to find %s function in lua file %s\n", func, code); lua_close(L); L = NULL; return NULL; } lua_pushnil(L); } lua_pop(L, 1); lua_pushvalue(L, -1); lua_pushlstring(L, key, keylen); #ifdef UWSGI_DEBUG uwsgi_log("stack pos %d %.*s\n", lua_gettop(L), keylen, key); #endif if (lua_pcall(L, 1, 1, 0) != 0) { uwsgi_log("error running function `f': %s", lua_tostring(L, -1)); return NULL; } if (lua_isstring(L, -1)) { const char *ret = lua_tolstring(L, -1, NULL); return (char *)ret; } return NULL; } static int uwsgi_lua_signal_handler(uint8_t sig, void *handler) { struct wsgi_request *wsgi_req = current_wsgi_req(); lua_State *L = ulua.L[wsgi_req->async_id]; #ifdef UWSGI_DEBUG uwsgi_log("managing signal handler on core %d\n", wsgi_req->async_id); #endif lua_rawgeti(L, LUA_REGISTRYINDEX, (long) handler); lua_pushnumber(L, sig); if (lua_pcall(L, 1, 1, 0) != 0) { uwsgi_log("error running function `f': %s", lua_tostring(L, -1)); return -1; } return 0; } static uint64_t uwsgi_lua_rpc(void * func, uint8_t argc, char **argv, uint16_t argvs[], char **buffer) { uint8_t i; const char *sv; size_t sl; long lfunc = (long) func; int ifunc = lfunc; struct wsgi_request *wsgi_req = current_wsgi_req(); lua_State *L = ulua.L[wsgi_req->async_id]; #ifdef UWSGI_DEBUG uwsgi_log("get function %d\n", ifunc); #endif lua_rawgeti(L, LUA_REGISTRYINDEX, ifunc); for(i=0;i 0) { *buffer = uwsgi_malloc(sl); memcpy(*buffer, sv, sl); lua_pop(L, 1); return sl; } lua_pop(L, 1); return 0; } static void uwsgi_lua_configurator_array(lua_State *L) { int i; int n = lua_rawlen(L, -3); for(i=1;i<=n;i++) { lua_rawgeti(L, 1, i); if (lua_istable(L, -1)) { lua_pushnil(L); while (lua_next(L, -2) != 0) { char *key = uwsgi_str((char *)lua_tostring(L, -2)); char *value = uwsgi_str((char *)lua_tostring(L, -1)); add_exported_option(key, value, 0); lua_pop(L, 1); } } } } static void uwsgi_lua_configurator(char *filename, char *magic_table[]) { size_t len = 0; uwsgi_log_initial("[uWSGI] getting Lua configuration from %s\n", filename); char *code = uwsgi_open_and_read(filename, &len, 1, magic_table); lua_State *L = luaL_newstate(); if (!L) { uwsgi_log("unable to initialize Lua state for configuration\n"); exit(1); } luaL_openlibs(L); if (luaL_dostring(L, code) != 0) { uwsgi_log("error running Lua configurator: %s\n", lua_tostring(L, -1)); exit(1); } free(code); if (!lua_istable(L, -1)) { uwsgi_log("Lua configurator has to return a table !!!\n"); exit(1); } lua_pushnil(L); // we always use uwsgi_str to avoid GC destroying our strings // and to be able to call lua_close at the end while (lua_next(L, -2) != 0) { // array ? if (lua_isnumber(L, -2)) { uwsgi_lua_configurator_array(L); break; } // dictionary else { char *key = uwsgi_str((char *)lua_tostring(L, -2)); if (lua_istable(L, -1)) { lua_pushnil(L); while (lua_next(L, -2) != 0) { char *value = uwsgi_str((char *)lua_tostring(L, -1)); add_exported_option(key, value, 0); lua_pop(L, 1); } } else { char *value = uwsgi_str((char *)lua_tostring(L, -1)); add_exported_option(key, value, 0); } } lua_pop(L, 1); } // this will destroy the whole Lua state lua_close(L); } static void uwsgi_register_lua_features() { uwsgi_register_configurator(".lua", uwsgi_lua_configurator); } static void uwsgi_lua_hijack(void) { if (ulua.shell && uwsgi.mywid == 1) { uwsgi.workers[uwsgi.mywid].hijacked = 1; uwsgi.workers[uwsgi.mywid].hijacked_count++; // re-map stdin to stdout and stderr if we are logging to a file if (uwsgi.logfile) { if (dup2(0, 1) < 0) { uwsgi_error("dup2()"); } if (dup2(0, 2) < 0) { uwsgi_error("dup2()"); } } int ret = -1; // run in the first state lua_State *L = ulua.L[0]; lua_getglobal(L, "debug"); lua_getfield(L, -1, "debug"); ret = lua_pcall(L, 0, 0, 0); if (ret == 0) { exit(UWSGI_QUIET_CODE); } exit(0); } } struct uwsgi_plugin lua_plugin = { .name = "lua", .modifier1 = 6, .init = uwsgi_lua_init, .options = uwsgi_lua_options, .request = uwsgi_lua_request, .after_request = uwsgi_lua_after_request, .init_apps = uwsgi_lua_app, .magic = uwsgi_lua_magic, .signal_handler = uwsgi_lua_signal_handler, .hijack_worker = uwsgi_lua_hijack, .code_string = uwsgi_lua_code_string, .rpc = uwsgi_lua_rpc, .on_load = uwsgi_register_lua_features, }; uwsgi-2.0.29/plugins/lua/uwsgiplugin.py000066400000000000000000000013261477626554400201610ustar00rootroot00000000000000import os,sys LUAINC = os.environ.get('UWSGICONFIG_LUAINC') LUALIB = os.environ.get('UWSGICONFIG_LUALIB') LUALIBPATH = os.environ.get('UWSGICONFIG_LUALIBPATH') LUAPC = os.environ.get('UWSGICONFIG_LUAPC', 'lua5.1') # we LUAINC/LUALIB/LUALIBPATH override the LUAPC for backwards compat if LUAINC: CFLAGS = ['-I%s' % LUAINC] else: try: CFLAGS = os.popen('pkg-config --cflags %s' % LUAPC).read().rstrip().split() except: CFLAGS = ['-I/usr/include/lua5.1'] if LUALIB: LIBS = ['-l%s' % LUALIB] else: try: LIBS = os.popen('pkg-config --libs %s' % LUAPC).read().rstrip().split() except: LIBS = ['-llua5.1'] if LUALIBPATH: LDFLAGS = ['-L%s' % LUALIBPATH] else: LDFLAGS = [] NAME='lua' GCC_LIST = ['lua_plugin'] uwsgi-2.0.29/plugins/matheval/000077500000000000000000000000001477626554400162505ustar00rootroot00000000000000uwsgi-2.0.29/plugins/matheval/math.c000066400000000000000000000035041477626554400173470ustar00rootroot00000000000000#include #include static char *uwsgi_route_var_math(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) { char *ret = NULL; // avoid crash if (!wsgi_req->var_cnt) return NULL; // we make a bit of fun here, we do a copy of the vars buffer (+1 byte for final zero) and zeor-pad all of the strings char *vars_buf = uwsgi_malloc(wsgi_req->uh->pktsize + keylen + 1); char **names = uwsgi_malloc(sizeof(char *) * (wsgi_req->var_cnt/2)); double *values = uwsgi_calloc(sizeof(double) * (wsgi_req->var_cnt/2)); int i,j = 0; char *ptr = vars_buf; for (i = wsgi_req->var_cnt-1; i > 0; i -= 2) { memcpy(ptr, wsgi_req->hvec[i-1].iov_base, wsgi_req->hvec[i-1].iov_len); names[j] = ptr; ptr += wsgi_req->hvec[i-1].iov_len; *ptr++=0; char *num = ptr; memcpy(ptr, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len); ptr += wsgi_req->hvec[i].iov_len; *ptr++=0; values[j] = strtod(num, NULL); j++; } char *expr = ptr; memcpy(ptr, key, keylen); ptr += keylen; *ptr++=0; void *e = evaluator_create(expr); if (!e) goto end; double n = evaluator_evaluate(e, j, names, values); evaluator_destroy(e); ret = uwsgi_num2str((int)n); *vallen = strlen(ret); end: free(vars_buf); free(names); free(values); return ret; } static void router_matheval_register() { struct uwsgi_route_var *urv = uwsgi_register_route_var("math", uwsgi_route_var_math); urv->need_free = 1; } struct uwsgi_plugin matheval_plugin = { .name = "matheval", .on_load = router_matheval_register, }; uwsgi-2.0.29/plugins/matheval/uwsgiplugin.py000066400000000000000000000001241477626554400211740ustar00rootroot00000000000000NAME='matheval' CFLAGS = [] LDFLAGS = [] LIBS = ['-lmatheval'] GCC_LIST = ['math'] uwsgi-2.0.29/plugins/mongodb/000077500000000000000000000000001477626554400160745ustar00rootroot00000000000000uwsgi-2.0.29/plugins/mongodb/plugin.c000066400000000000000000000002541477626554400175370ustar00rootroot00000000000000#include /* a fake plugin used for preloading mongodb library when only available as static. */ struct uwsgi_plugin mongodb_plugin = { .name = "mongodb", }; uwsgi-2.0.29/plugins/mongodb/uwsgiplugin.py000066400000000000000000000003031477626554400210170ustar00rootroot00000000000000NAME='mongodb' CFLAGS = [] LDFLAGS = [] LIBS = ['-Wl,-whole-archive', '-lmongoclient', '-Wl,-no-whole-archive', '-lboost_thread', '-lboost_system', '-lboost_filesystem'] GCC_LIST = ['plugin'] uwsgi-2.0.29/plugins/mongodblog/000077500000000000000000000000001477626554400165765ustar00rootroot00000000000000uwsgi-2.0.29/plugins/mongodblog/mongodblog_plugin.c000066400000000000000000000077371477626554400224650ustar00rootroot00000000000000#include extern struct uwsgi_server uwsgi; struct uwsgi_mongodb_header { int32_t len; int32_t request_id; int32_t response_id; int32_t opcode; }; struct uwsgi_mongodb_state { int fd; char *address; int32_t base_len; struct uwsgi_mongodb_header header; int32_t flags; char *collection; int32_t bson_base_len; int32_t bson_len; int64_t ts; int32_t bson_node_len; char *bson_node; int32_t bson_msg_len; struct iovec iovec[13]; }; static ssize_t uwsgi_mongodb_logger(struct uwsgi_logger *ul, char *message, size_t len) { struct uwsgi_mongodb_state *ums = NULL; if (!ul->configured) { ul->data = uwsgi_calloc(sizeof(struct uwsgi_mongodb_state)); ums = (struct uwsgi_mongodb_state *) ul->data; // full default if (ul->arg == NULL) { ums->address = uwsgi_str("127.0.0.1:27017"); ums->collection = "uwsgi.logs"; ums->bson_node = uwsgi.hostname; ums->bson_node_len = uwsgi.hostname_len; goto done; } ums->address = uwsgi_str(ul->arg); char *collection = strchr(ums->address, ','); // default to uwsgi.logs if (!collection) { ums->collection = "uwsgi.logs"; ums->bson_node = uwsgi.hostname; ums->bson_node_len = uwsgi.hostname_len; goto done; } *collection = 0; ums->collection = collection+1; char *node = strchr(ums->collection, ','); // default to hostname if (!node) { ums->bson_node = uwsgi.hostname; ums->bson_node_len = uwsgi.hostname_len; goto done; } *node = 0; ums->bson_node = node+1; ums->bson_node_len = strlen(ums->bson_node)+1; done: ums->fd = -1; // header ums->iovec[0].iov_base = &ums->header; ums->iovec[0].iov_len = sizeof(struct uwsgi_mongodb_header); // OPCODE INSERT ums->header.opcode = 2002; // flags ums->iovec[1].iov_base = &ums->flags; ums->iovec[1].iov_len = sizeof(int32_t); // collection name ums->iovec[2].iov_base = ums->collection; ums->iovec[2].iov_len = strlen(ums->collection)+1; // BSON len ums->iovec[3].iov_base = &ums->bson_len; ums->iovec[3].iov_len = sizeof(int32_t); // BSON node ums->iovec[4].iov_base = "\x02node\0"; ums->iovec[4].iov_len = 6; ums->iovec[5].iov_base = &ums->bson_node_len; ums->iovec[5].iov_len = sizeof(int32_t); ums->iovec[6].iov_base = ums->bson_node; ums->iovec[6].iov_len = ums->bson_node_len; // BSON timestamp (ts) ums->iovec[7].iov_base = "\x09ts\0"; ums->iovec[7].iov_len = 4; ums->iovec[8].iov_base = &ums->ts; ums->iovec[8].iov_len = sizeof(int64_t); // BSON msg ums->iovec[9].iov_base = "\2msg\0"; ums->iovec[9].iov_len = 5; ums->iovec[10].iov_base = &ums->bson_msg_len; ums->iovec[10].iov_len = sizeof(int32_t); // iov 11 is reset at each cycle // ... // BSON end (msg_zero + bson_zero); ums->iovec[12].iov_base = "\0\0"; ums->iovec[12].iov_len = 2; ums->bson_base_len = ums->iovec[3].iov_len + ums->iovec[4].iov_len + ums->iovec[5].iov_len + ums->iovec[6].iov_len + ums->iovec[7].iov_len + ums->iovec[8].iov_len + ums->iovec[9].iov_len + ums->iovec[10].iov_len + ums->iovec[12].iov_len; ums->base_len = ums->iovec[0].iov_len + ums->iovec[1].iov_len + ums->iovec[2].iov_len + ums->bson_base_len; ul->configured = 1; } ums = (struct uwsgi_mongodb_state *) ul->data; if (ums->fd == -1) { ums->fd = uwsgi_connect(ums->address, uwsgi.socket_timeout, 0); } if (ums->fd == -1) return -1; // fix the packet ums->bson_msg_len = len+1; ums->bson_len = ums->bson_base_len + len; ums->header.len = ums->base_len + len; ums->header.request_id++; // get milliseconds time ums->ts = uwsgi_micros()/1000; ums->iovec[11].iov_base = message; ums->iovec[11].iov_len = len; ssize_t ret = writev(ums->fd, ums->iovec, 13); if (ret <= 0) { close(ums->fd); ums->fd = -1; return -1; } return ret; } static void uwsgi_mongodblog_register() { uwsgi_register_logger("mongodblog", uwsgi_mongodb_logger); } struct uwsgi_plugin mongodblog_plugin = { .name = "mongodblog", .on_load = uwsgi_mongodblog_register, }; uwsgi-2.0.29/plugins/mongodblog/uwsgiplugin.py000066400000000000000000000001271477626554400215250ustar00rootroot00000000000000NAME='mongodblog' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['mongodblog_plugin'] uwsgi-2.0.29/plugins/mongrel2/000077500000000000000000000000001477626554400161745ustar00rootroot00000000000000uwsgi-2.0.29/plugins/mongrel2/mongrel2.c000066400000000000000000000546001477626554400200720ustar00rootroot00000000000000/* Mongrel2 protocol parser */ #include #include extern struct uwsgi_server uwsgi; static struct uwsgi_option mongrel2_options[] = { {"zeromq", required_argument, 0, "create a mongrel2/zeromq pub/sub pair", uwsgi_opt_add_lazy_socket, "mongrel2", 0}, {"zmq", required_argument, 0, "create a mongrel2/zeromq pub/sub pair", uwsgi_opt_add_lazy_socket, "mongrel2", 0}, {"zeromq-socket", required_argument, 0, "create a mongrel2/zeromq pub/sub pair", uwsgi_opt_add_lazy_socket, "mongrel2", 0}, {"zmq-socket", required_argument, 0, "create a mongrel2/zeromq pub/sub pair", uwsgi_opt_add_lazy_socket, "mongrel2", 0}, {"mongrel2", required_argument, 0, "create a mongrel2/zeromq pub/sub pair", uwsgi_opt_add_lazy_socket, "mongrel2", 0}, }; #ifdef UWSGI_JSON #include static char *uwsgi_mongrel2_json_get_string(json_t * node, const char *json_key) { json_t *json_value = json_object_get(node, json_key); if (json_is_string(json_value)) { return (char *) json_string_value(json_value); } return NULL; } static uint16_t uwsgi_mongrel2_json_add(struct wsgi_request *wsgi_req, json_t * node, const char *json_key, char *key, uint16_t keylen, char **extra, size_t * extra_len) { char *json_val; json_t *json_value = json_object_get(node, json_key); if (json_is_string(json_value)) { json_val = (char *) json_string_value(json_value); // invalid value ? if (strlen(json_val) > 0xffff) return 0; if (extra) { *extra = json_val; *extra_len = strlen(json_val); } return proto_base_add_uwsgi_var(wsgi_req, key, keylen, json_val, strlen(json_val)); } return 0; } static int uwsgi_mongrel2_json_parse(json_t * root, struct wsgi_request *wsgi_req) { char *json_val; char *query_string = NULL; size_t query_string_len = 0; size_t script_name_len = 0; void *json_iter; char *json_key; json_t *json_value; if ((json_val = uwsgi_mongrel2_json_get_string(root, "METHOD"))) { if (!strcmp(json_val, "JSON")) { return -1; } wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_METHOD", 14, json_val, strlen(json_val)); } // pretty easy, we get the file and we map it to wsgi_req->post_file, uWSGI read api will automatically use this if ((json_val = uwsgi_mongrel2_json_get_string(root, "x-mongrel2-upload-done"))) { wsgi_req->post_file = fopen(json_val, "r"); if (!wsgi_req->post_file) { uwsgi_error_open(json_val); return -1; } } else if (uwsgi_mongrel2_json_get_string(root, "x-mongrel2-upload-start")) { return -1; } wsgi_req->uh->pktsize += uwsgi_mongrel2_json_add(wsgi_req, root, "VERSION", "SERVER_PROTOCOL", 15, NULL, NULL); wsgi_req->uh->pktsize += uwsgi_mongrel2_json_add(wsgi_req, root, "QUERY", "QUERY_STRING", 12, &query_string, &query_string_len); if (query_string == NULL) { // always set QUERY_STRING wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, "", 0); } // set SCRIPT_NAME to an empty value wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SCRIPT_NAME", 11, "", 0); if ((json_val = uwsgi_mongrel2_json_get_string(root, "PATH"))) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "PATH_INFO", 9, json_val + script_name_len, strlen(json_val + script_name_len)); if (query_string_len) { char *request_uri = uwsgi_concat3n(json_val, strlen(json_val), "?", 1, query_string, query_string_len); wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, request_uri, strlen(json_val) + 1 + query_string_len); free(request_uri); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, json_val, strlen(json_val)); } } if ((json_val = uwsgi_mongrel2_json_get_string(root, "URL_SCHEME"))) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "UWSGI_SCHEME", 12, json_val, strlen(json_val)); } if ((json_val = uwsgi_mongrel2_json_get_string(root, "host"))) { char *colon = strchr(json_val, ':'); if (colon) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, colon + 1, strlen(colon + 1)); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, "80", 2); } } if ((json_val = uwsgi_mongrel2_json_get_string(root, "x-forwarded-for"))) { char *colon = strchr(json_val, ','); if (colon) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, colon + 1, (colon + 1) - json_val); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, json_val, strlen(json_val)); } } if ((json_val = uwsgi_mongrel2_json_get_string(root, "content-length"))) { wsgi_req->post_cl = atoi(json_val); } wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len); json_iter = json_object_iter(root); while (json_iter) { json_key = (char *) json_object_iter_key(json_iter); // is it a header ? if (json_key[0] >= 97) { json_value = json_object_iter_value(json_iter); if (json_is_string(json_value)) { json_val = (char *) json_string_value(json_value); wsgi_req->uh->pktsize += proto_base_add_uwsgi_header(wsgi_req, json_key, strlen(json_key), json_val, strlen(json_val)); } } json_iter = json_object_iter_next(root, json_iter); } return 0; } #endif // dumb/fake tnetstring implementation...all is a string static int uwsgi_mongrel2_tnetstring_parse(struct wsgi_request *wsgi_req, char *buf, int len) { char *ptr = buf; char *watermark = buf + len; char *key = NULL; size_t keylen = 0; char *val = NULL; size_t vallen = 0; uint16_t script_name_len = 0; char *query_string = NULL; uint16_t query_string_len = 0; int async_upload = 0; // set an empty SCRIPT_NAME wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SCRIPT_NAME", 11, "", 0); while (ptr < watermark) { ptr = uwsgi_netstring(ptr, len - (ptr - buf), &key, &keylen); if (ptr == NULL) break; // empty keys are not allowed if (keylen == 0) break; if (ptr >= watermark) break; ptr = uwsgi_netstring(ptr, len - (ptr - buf), &val, &vallen); if (ptr == NULL) break; if (key[0] < 97) { if (!uwsgi_strncmp("METHOD", 6, key, keylen)) { if (!uwsgi_strncmp("JSON", 4, val, vallen)) { return -1; } wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_METHOD", 14, val, vallen); } else if (!uwsgi_strncmp("VERSION", 7, key, keylen)) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PROTOCOL", 15, val, vallen); } else if (!uwsgi_strncmp("QUERY", 5, key, keylen)) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, val, vallen); query_string = val; query_string_len = vallen; } else if (!uwsgi_strncmp("PATH", 4, key, keylen)) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "PATH_INFO", 9, val + script_name_len, vallen - script_name_len); if (query_string_len) { char *request_uri = uwsgi_concat3n(val, vallen, "?", 1, query_string, query_string_len); wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, request_uri, vallen + 1 + query_string_len); free(request_uri); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, val, vallen); } } else if (!uwsgi_strncmp("URL_SCHEME", 10, key, keylen)) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "UWSGI_SCHEME", 12, val, vallen); } } else { // add header if (!uwsgi_strncmp("host", 4, key, keylen)) { char *colon = memchr(val, ':', vallen); if (colon) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, colon + 1, vallen - ((colon + 1) - val)); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, "80", 2); } } else if (!uwsgi_strncmp("content-length", 14, key, keylen)) { wsgi_req->post_cl = uwsgi_str_num(val, vallen); } else if (!uwsgi_strncmp("x-mongrel2-upload-done", 22, key, keylen)) { char *post_filename = uwsgi_concat2n(val, vallen, "", 0); wsgi_req->post_file = fopen(post_filename, "r"); if (!wsgi_req->post_file) { uwsgi_error_open(post_filename); wsgi_req->do_not_log = 1; } async_upload += 2; free(post_filename); } else if (!uwsgi_strncmp("x-forwarded-for", 15, key, keylen)) { char *colon = memchr(val, ',', vallen); if (colon) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, colon + 1, (colon + 1) - val); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, val, vallen); } } else if (!uwsgi_strncmp("x-mongrel2-upload-start", 23, key, keylen)) { async_upload += 1; } wsgi_req->uh->pktsize += proto_base_add_uwsgi_header(wsgi_req, key, keylen, val, vallen); } } wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len); if (query_string == NULL) { // always set QUERY_STRING wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, "", 0); } // reject uncomplete upload if (async_upload == 1) { return -1; } return 0; } // fake function, we parse requests in the accept phase int uwsgi_proto_zeromq_parser(struct wsgi_request *wsgi_req) { return UWSGI_OK; } void uwsgi_proto_zeromq_thread_fixup(struct uwsgi_socket *uwsgi_sock, int async_id) { void *tmp_zmq_pull = zmq_socket(uwsgi_sock->ctx, ZMQ_PULL); if (tmp_zmq_pull == NULL) { uwsgi_error("zmq_socket()"); exit(1); } if (zmq_connect(tmp_zmq_pull, uwsgi_sock->receiver) < 0) { uwsgi_error("zmq_connect()"); exit(1); } pthread_setspecific(uwsgi_sock->key, tmp_zmq_pull); #ifdef ZMQ_FD if (uwsgi.threads > 1) { size_t zmq_socket_len = sizeof(int); if (zmq_getsockopt(pthread_getspecific(uwsgi_sock->key), ZMQ_FD, &uwsgi_sock->fd_threads[async_id], &zmq_socket_len) < 0) { uwsgi_error("zmq_getsockopt()"); exit(1); } uwsgi_sock->retry[async_id] = 1; } #endif } // fake function, the body is in a file or completely in memory ssize_t uwsgi_proto_zeromq_read_body(struct wsgi_request *wsgi_req, char *buf, size_t len) { size_t remains = wsgi_req->post_cl - wsgi_req->proto_parser_status; if (remains > 0) { if (len > remains) len = remains; memcpy(buf, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_buf_size + wsgi_req->proto_parser_status, len); wsgi_req->proto_parser_status += len; return len; } return 0; } int uwsgi_proto_zeromq_accept(struct wsgi_request *wsgi_req, int fd) { zmq_msg_t message; char *req_uuid = NULL; size_t req_uuid_len = 0; char *req_id = NULL; size_t req_id_len = 0; char *req_path = NULL; size_t req_path_len = 0; #ifdef UWSGI_JSON json_t *root; json_error_t error; #endif char *mongrel2_req = NULL; size_t mongrel2_req_size = 0; int resp_id_len; uint32_t events = 0; char *message_ptr; size_t message_size = 0; char *post_data; #ifdef ZMQ_EVENTS size_t events_len = sizeof(uint32_t); if (zmq_getsockopt(pthread_getspecific(wsgi_req->socket->key), ZMQ_EVENTS, &events, &events_len) < 0) { uwsgi_error("zmq_getsockopt()"); goto retry; } #endif if (events & ZMQ_POLLIN || (wsgi_req->socket->retry && wsgi_req->socket->retry[wsgi_req->async_id])) { wsgi_req->do_not_add_to_async_queue = 1; wsgi_req->proto_parser_status = 0; zmq_msg_init(&message); #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) if (zmq_recvmsg(pthread_getspecific(wsgi_req->socket->key), &message, wsgi_req->socket->recv_flag) < 0) { #else if (zmq_recv(pthread_getspecific(wsgi_req->socket->key), &message, wsgi_req->socket->recv_flag) < 0) { #endif if (errno == EAGAIN) { zmq_msg_close(&message); goto repoll; } uwsgi_error("zmq_recv()"); zmq_msg_close(&message); goto retry; } message_size = zmq_msg_size(&message); //uwsgi_log("%.*s\n", (int) wsgi_req->proto_parser_pos, zmq_msg_data(&message)); if (message_size > 0xffff) { uwsgi_log("too much big message %d\n", message_size); zmq_msg_close(&message); goto retry; } message_ptr = zmq_msg_data(&message); // warning mongrel2_req_size will contains a bad value, but this is not a problem... post_data = uwsgi_split4(message_ptr, message_size, ' ', &req_uuid, &req_uuid_len, &req_id, &req_id_len, &req_path, &req_path_len, &mongrel2_req, &mongrel2_req_size); if (post_data == NULL) { uwsgi_log("cannot parse message (split4 phase)\n"); zmq_msg_close(&message); goto retry; } // fix post_data, mongrel2_req and mongrel2_req_size post_data = uwsgi_netstring(mongrel2_req, message_size - (mongrel2_req - message_ptr), &mongrel2_req, &mongrel2_req_size); if (post_data == NULL) { uwsgi_log("cannot parse message (body netstring phase)\n"); zmq_msg_close(&message); goto retry; } // ok ready to parse tnetstring/json data and build uwsgi request if (mongrel2_req[mongrel2_req_size] == '}') { if (uwsgi_mongrel2_tnetstring_parse(wsgi_req, mongrel2_req, mongrel2_req_size)) { zmq_msg_close(&message); goto retry; } } else { #ifdef UWSGI_JSON #ifdef UWSGI_DEBUG uwsgi_log("JSON %d: %.*s\n", mongrel2_req_size, mongrel2_req_size, mongrel2_req); #endif // add a zero to the end of buf mongrel2_req[mongrel2_req_size] = 0; root = json_loads(mongrel2_req, 0, &error); if (!root) { uwsgi_log("error parsing JSON data: line %d %s\n", error.line, error.text); zmq_msg_close(&message); goto retry; } if (uwsgi_mongrel2_json_parse(root, wsgi_req)) { json_decref(root); zmq_msg_close(&message); goto retry; } json_decref(root); #else uwsgi_log("JSON support not enabled (recompile uWSGI with libjansson support, or re-configure mongrel2 with \"protocol='tnetstring'\". skip request\n"); #endif } // pre-build the mongrel2 response_header wsgi_req->proto_parser_buf_size = req_uuid_len + 1 + 11 + 1 + req_id_len + 1 + 1; wsgi_req->proto_parser_buf = uwsgi_malloc(wsgi_req->proto_parser_buf_size); memcpy(wsgi_req->proto_parser_buf, req_uuid, req_uuid_len); ((char *) wsgi_req->proto_parser_buf)[req_uuid_len] = ' '; resp_id_len = uwsgi_num2str2(req_id_len, wsgi_req->proto_parser_buf + req_uuid_len + 1); ((char *) wsgi_req->proto_parser_buf)[req_uuid_len + 1 + resp_id_len] = ':'; memcpy((char *) wsgi_req->proto_parser_buf + req_uuid_len + 1 + resp_id_len + 1, req_id, req_id_len); memcpy((char *) wsgi_req->proto_parser_buf + req_uuid_len + 1 + resp_id_len + 1 + req_id_len, ", ", 2); wsgi_req->proto_parser_pos = (uint64_t) req_uuid_len + 1 + resp_id_len + 1 + req_id_len + 1 + 1; // handle post data (in memory) // reallocate wsgi_req->proto_parser_buf and change its size to be able to store request body // the parser status holds the current position for read_body hook if (wsgi_req->post_cl > 0 && !wsgi_req->post_file) { if (uwsgi_netstring(post_data, message_size - (post_data - message_ptr), &message_ptr, &wsgi_req->post_cl)) { char *tmp = realloc(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf_size + wsgi_req->post_cl); if (!tmp) { uwsgi_error("realloc()"); exit(1); } wsgi_req->proto_parser_buf = tmp; // status is an offset... wsgi_req->proto_parser_status = 0; #ifdef UWSGI_DEBUG uwsgi_log("post_size: %d\n", wsgi_req->post_cl); #endif memcpy(wsgi_req->proto_parser_buf + wsgi_req->proto_parser_buf_size, message_ptr, wsgi_req->post_cl); } } zmq_msg_close(&message); // retry by default wsgi_req->socket->retry[wsgi_req->async_id] = 1; return 0; } repoll: // force polling of the socket wsgi_req->socket->retry[wsgi_req->async_id] = 0; return -1; retry: // retry til EAGAIN; wsgi_req->do_not_log = 1; wsgi_req->socket->retry[wsgi_req->async_id] = 1; return -1; } static int uwsgi_proto_zeromq_write_do(struct wsgi_request *wsgi_req, char *buf, size_t len) { zmq_msg_t reply; if (zmq_msg_init_size(&reply, wsgi_req->proto_parser_pos + len)) { uwsgi_error("uwsgi_proto_zeromq_write()/zmq_msg_init_size()"); return -1; } char *zmq_body = zmq_msg_data(&reply); memcpy(zmq_body, wsgi_req->proto_parser_buf, wsgi_req->proto_parser_pos); if (len > 0) memcpy(zmq_body + wsgi_req->proto_parser_pos, buf, len); if (uwsgi.threads > 1) pthread_mutex_lock(&wsgi_req->socket->lock); #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) if (zmq_sendmsg(wsgi_req->socket->pub, &reply, 0)) { #else if (zmq_send(wsgi_req->socket->pub, &reply, 0)) { #endif if (uwsgi.threads > 1) pthread_mutex_unlock(&wsgi_req->socket->lock); zmq_msg_close(&reply); return -1; } if (uwsgi.threads > 1) pthread_mutex_unlock(&wsgi_req->socket->lock); zmq_msg_close(&reply); return UWSGI_OK; } int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t len) { int ret = uwsgi_proto_zeromq_write_do(wsgi_req, buf, len); if (ret == UWSGI_OK) { wsgi_req->write_pos += len; } return ret; } void uwsgi_proto_zeromq_close(struct wsgi_request *wsgi_req) { uwsgi_proto_zeromq_write_do(wsgi_req, "", 0); } /* we have a problem... recent Mongrel2 releases introduced a ring buffer that limit the amount of messages we can send (or better, the amount of messages mongrel2 is able to manage). If we send a big static file we can fill that buffer immediately. How to deal with this ? We know that the message ring can contains a fixed amount of messages. We could try to split the file in chunks (upto the maximum number supported by a specific mongrel2 instance). This is suboptimal, but there are no better solutions for now. Before you ask: do you really think that sending a single message with a 2GB file is a good approach ????? By the way, for now, waiting for a better approach, we use a 2MB buffer. Should support flawlessly files up to 32MB without being rejected by mongrel2. For bigger files you can tune it to higher values (or increase the mongrel2 ring buffer) */ #define UWSGI_MONGREL2_MAX_MSGSIZE 2*1024*1024 int uwsgi_proto_zeromq_sendfile(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) { size_t chunk_size = UMIN( len - wsgi_req->write_pos, UWSGI_MONGREL2_MAX_MSGSIZE); char *tmp_buf = uwsgi_malloc(chunk_size); ssize_t rlen = read(fd, tmp_buf, chunk_size); if (rlen <= 0) { free(tmp_buf); return -1; } wsgi_req->write_pos += rlen; if (uwsgi_proto_zeromq_write_do(wsgi_req, tmp_buf, rlen) < 0) { free(tmp_buf); return -1; } free(tmp_buf); if (wsgi_req->write_pos == len) { return UWSGI_OK; } return UWSGI_AGAIN; } static void uwsgi_proto_mongrel2_setup(struct uwsgi_socket *uwsgi_sock) { uwsgi_sock->proto = uwsgi_proto_zeromq_parser; uwsgi_sock->proto_accept = uwsgi_proto_zeromq_accept; uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers; uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header; uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers; uwsgi_sock->proto_read_body = uwsgi_proto_zeromq_read_body; uwsgi_sock->proto_write = uwsgi_proto_zeromq_write; uwsgi_sock->proto_write_headers = uwsgi_proto_zeromq_write; uwsgi_sock->proto_sendfile = uwsgi_proto_zeromq_sendfile; uwsgi_sock->proto_close = uwsgi_proto_zeromq_close; uwsgi_sock->proto_thread_fixup = uwsgi_proto_zeromq_thread_fixup; uwsgi_sock->edge_trigger = 1; uwsgi_sock->retry = uwsgi_malloc(sizeof(int) * uwsgi.threads); uwsgi_sock->retry[0] = 1; uwsgi_sock->fd = -1; }; static void mongrel2_register_proto() { uwsgi_register_protocol("mongrel2", uwsgi_proto_mongrel2_setup); } static void mongrel2_connect() { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while(uwsgi_sock) { if (uwsgi_sock->proto != uwsgi_proto_zeromq_parser) goto next; uwsgi_sock->ctx = zmq_init(1); if (!uwsgi_sock->ctx) { uwsgi_error("mongrel2_connect()/zmq_init()"); exit(1); } char *responder = strchr(uwsgi_sock->name, ','); if (!responder) { uwsgi_log("invalid zeromq address: %s\n", uwsgi_sock->name); exit(1); } uwsgi_sock->receiver = uwsgi_concat2n(uwsgi_sock->name, responder - uwsgi_sock->name, "", 0); responder++; uwsgi_sock->pub = zmq_socket(uwsgi_sock->ctx, ZMQ_PUB); if (uwsgi_sock->pub == NULL) { uwsgi_error("mongrel2_connect()/zmq_socket()"); exit(1); } // generate uuid uwsgi_uuid(uwsgi_sock->uuid); if (zmq_setsockopt(uwsgi_sock->pub, ZMQ_IDENTITY, uwsgi_sock->uuid, 36) < 0) { uwsgi_error("mongrel2_connect()/zmq_setsockopt()"); exit(1); } if (zmq_connect(uwsgi_sock->pub, responder) < 0) { uwsgi_error("mongrel2_connect()/zmq_connect()"); exit(1); } uwsgi_log("zeromq UUID for responder %s on worker %d: %.*s\n", responder, uwsgi.mywid, 36, uwsgi_sock->uuid); // inform loop engine about edge trigger status uwsgi.is_et = 1; // initialize a lock for multithread usage if (uwsgi.threads > 1) { pthread_mutex_init(&uwsgi_sock->lock, NULL); } // one pull per-thread if (pthread_key_create(&uwsgi_sock->key, NULL)) { uwsgi_error("mongrel2_connect()/pthread_key_create()"); exit(1); } void *tmp_zmq_pull = zmq_socket(uwsgi_sock->ctx, ZMQ_PULL); if (tmp_zmq_pull == NULL) { uwsgi_error("mongrel2_connect()/zmq_socket()"); exit(1); } if (zmq_connect(tmp_zmq_pull, uwsgi_sock->receiver) < 0) { uwsgi_error("mongrel2_connect()/zmq_connect()"); exit(1); } pthread_setspecific(uwsgi_sock->key, tmp_zmq_pull); #ifdef ZMQ_FD size_t zmq_socket_len = sizeof(int); if (zmq_getsockopt(pthread_getspecific(uwsgi_sock->key), ZMQ_FD, &uwsgi_sock->fd, &zmq_socket_len) < 0) { uwsgi_error("mongrel2_connect()/zmq_getsockopt()"); exit(1); } if (uwsgi.threads > 1) { uwsgi_sock->fd_threads = uwsgi_malloc(sizeof(int) * uwsgi.threads); uwsgi_sock->fd_threads[0] = uwsgi_sock->fd; } #endif uwsgi_sock->bound = 1; #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) uwsgi_sock->recv_flag = ZMQ_DONTWAIT; #else uwsgi_sock->recv_flag = ZMQ_NOBLOCK; #endif next: uwsgi_sock = uwsgi_sock->next; } } struct uwsgi_plugin mongrel2_plugin = { .name = "mongrel2", .options = mongrel2_options, .post_fork = mongrel2_connect, .on_load = mongrel2_register_proto, }; uwsgi-2.0.29/plugins/mongrel2/uwsgiplugin.py000066400000000000000000000001241477626554400211200ustar00rootroot00000000000000 NAME='mongrel2' CFLAGS = [] LDFLAGS = [] LIBS = ['-lzmq'] GCC_LIST = ['mongrel2'] uwsgi-2.0.29/plugins/mono/000077500000000000000000000000001477626554400154175ustar00rootroot00000000000000uwsgi-2.0.29/plugins/mono/mono_plugin.c000066400000000000000000000546561477626554400201310ustar00rootroot00000000000000#include #include #include #include #include #include #include #include /* Mono ASP.NET plugin there are various mode of operation (based on security needs) (the --mono-key maps to DOCUMENT_ROOT by default) 1) static application --mono-app will create an ApplicationHost on the specified the --mono-key will be searched for that directory the application runs on the main domain 2) dynamic applications the app is created on demand using the specified key as the physicalDirectory TODO: allows mounting apps under subpaths (currently all is mapped to "/") Thanks to: Robert Jordan for helping me understanding the ApplicationHost internals */ extern struct uwsgi_server uwsgi; struct uwsgi_plugin mono_plugin; struct uwsgi_mono { char *config; char *version; char *assembly_name ; struct uwsgi_string_list *key; struct uwsgi_string_list *index; // GC frequency uint64_t gc_freq; // a lock for dynamic apps pthread_mutex_t lock_loader; MonoDomain *main_domain; MonoMethod *create_application_host; MonoClass *application_class; MonoClass *api_class; MonoClass *byte_class; MonoClassField *filepath; // thunk void (*process_request)(MonoObject *, MonoException **); struct uwsgi_string_list *app; struct uwsgi_string_list *exec; } umono; struct uwsgi_option uwsgi_mono_options[] = { {"mono-app", required_argument, 0, "load a Mono asp.net app from the specified directory", uwsgi_opt_add_string_list, &umono.app, 0}, {"mono-gc-freq", required_argument, 0, "run the Mono GC every requests (default: run after every request)", uwsgi_opt_set_64bit, &umono.gc_freq, 0}, {"mono-key", required_argument, 0, "select the ApplicationHost based on the specified CGI var", uwsgi_opt_add_string_list, &umono.key, 0}, {"mono-version", required_argument, 0, "set the Mono jit version", uwsgi_opt_set_str, &umono.version, 0}, {"mono-config", required_argument, 0, "set the Mono config file", uwsgi_opt_set_str, &umono.config, 0}, {"mono-assembly", required_argument, 0, "load the specified main assembly (default: uwsgi.dll)", uwsgi_opt_set_str, &umono.assembly_name, 0}, {"mono-exec", required_argument, 0, "exec the specified assembly just before app loading", uwsgi_opt_add_string_list, &umono.exec, 0}, {"mono-index", required_argument, 0, "add an asp.net index file", uwsgi_opt_add_string_list, &umono.index, 0}, {0, 0, 0, 0, 0, 0, 0}, }; static MonoString *uwsgi_mono_method_GetFilePath(MonoObject *this) { MonoString *ret = NULL; // cache it !!! MonoObject *filepath = mono_field_get_value_object(mono_domain_get(), umono.filepath, this); if (filepath) { return (MonoString *) filepath; } struct wsgi_request *wsgi_req = current_wsgi_req(); struct uwsgi_app *app = &uwsgi_apps[wsgi_req->app_id]; char *path = uwsgi_concat3n(app->interpreter, strlen(app->interpreter), "/", 1, wsgi_req->path_info, wsgi_req->path_info_len); size_t path_len = strlen(app->interpreter) + 1 + wsgi_req->path_info_len; if (!uwsgi_file_exists(path)) { free(path); goto simple; } if (uwsgi_is_dir(path)) { struct uwsgi_string_list *usl = umono.index; while(usl) { char *index = uwsgi_concat3n(path, path_len, "/", 1 , usl->value, usl->len); if (uwsgi_file_exists(index)) { ret = mono_string_new(mono_domain_get(), index + strlen(app->interpreter)); free(path); free(index); mono_field_set_value(this, umono.filepath, ret); return ret; } free(index); usl = usl->next; } } free(path); simple: ret = mono_string_new_len(mono_domain_get(), wsgi_req->path_info, wsgi_req->path_info_len); mono_field_set_value(this, umono.filepath, ret); return ret; } static MonoString *uwsgi_mono_method_GetUriPath(MonoObject *this) { return uwsgi_mono_method_GetFilePath(this); } static MonoString *uwsgi_mono_method_MapPath(MonoObject *this, MonoString *virtualPath) { struct wsgi_request *wsgi_req = current_wsgi_req(); struct uwsgi_app *app = &uwsgi_apps[wsgi_req->app_id]; char *path = uwsgi_concat3n(app->interpreter, strlen(app->interpreter), "/", 1, mono_string_to_utf8(virtualPath), mono_string_length(virtualPath)); MonoString *ret = mono_string_new_len(mono_domain_get(), path, strlen(path)); free(path); return ret; } static MonoString *uwsgi_mono_method_GetQueryString(MonoObject *this) { struct wsgi_request *wsgi_req = current_wsgi_req(); return mono_string_new_len(mono_domain_get(), wsgi_req->query_string, wsgi_req->query_string_len); } static MonoString *uwsgi_mono_method_GetHttpVerbName(MonoObject *this) { struct wsgi_request *wsgi_req = current_wsgi_req(); return mono_string_new_len(mono_domain_get(), wsgi_req->method, wsgi_req->method_len); } static MonoString *uwsgi_mono_method_GetRawUrl(MonoObject *this) { struct wsgi_request *wsgi_req = current_wsgi_req(); return mono_string_new_len(mono_domain_get(), wsgi_req->uri, wsgi_req->uri_len); } static MonoString *uwsgi_mono_method_GetHttpVersion(MonoObject *this) { struct wsgi_request *wsgi_req = current_wsgi_req(); return mono_string_new_len(mono_domain_get(), wsgi_req->protocol, wsgi_req->protocol_len); } static MonoString *uwsgi_mono_method_GetRemoteAddress(MonoObject *this) { struct wsgi_request *wsgi_req = current_wsgi_req(); return mono_string_new_len(mono_domain_get(), wsgi_req->remote_addr, wsgi_req->remote_addr_len); } static void uwsgi_mono_method_SendStatus(MonoObject *this, int code, MonoString *msg) { struct wsgi_request *wsgi_req = current_wsgi_req(); char status_code[4]; uwsgi_num2str2n(code, status_code, 4); char *status_line = uwsgi_concat3n(status_code, 3, " ", 1, mono_string_to_utf8(msg), mono_string_length(msg)); uwsgi_response_prepare_headers(wsgi_req, status_line, 4 + mono_string_length(msg)); free(status_line); } static void uwsgi_mono_method_SendUnknownResponseHeader(MonoObject *this, MonoString *key, MonoString *value) { struct wsgi_request *wsgi_req = current_wsgi_req(); uwsgi_response_add_header(wsgi_req, mono_string_to_utf8(key), mono_string_length(key), mono_string_to_utf8(value), mono_string_length(value)); } static void uwsgi_mono_method_SendResponseFromMemory(MonoObject *this, MonoArray *byteArray, int len) { struct wsgi_request *wsgi_req = current_wsgi_req(); uwsgi_response_write_body_do(wsgi_req, mono_array_addr(byteArray, char, 0), len); } static void uwsgi_mono_method_FlushResponse(MonoObject *this, int is_final) { struct wsgi_request *wsgi_req = current_wsgi_req(); uwsgi_response_write_body_do(wsgi_req, "", 0); } static void uwsgi_mono_method_SendResponseFromFd(MonoObject *this, int fd, long offset, long len) { struct wsgi_request *wsgi_req = current_wsgi_req(); wsgi_req->sendfile_fd = fd; if (fd >= 0) { uwsgi_response_sendfile_do(wsgi_req, fd, offset, len); } wsgi_req->sendfile_fd = -1; } static void uwsgi_mono_method_SendResponseFromFile(MonoObject *this, MonoString *filename, long offset, long len) { struct wsgi_request *wsgi_req = current_wsgi_req(); int fd = open(mono_string_to_utf8(filename), O_RDONLY); if (fd >= 0) { uwsgi_response_sendfile_do(wsgi_req, fd, offset, len); } } static MonoString *uwsgi_mono_method_GetHeaderByName(MonoObject *this, MonoString *key) { struct wsgi_request *wsgi_req = current_wsgi_req(); uint16_t rlen = 0; char *value = uwsgi_get_header(wsgi_req, mono_string_to_utf8(key), mono_string_length(key), &rlen); if (value) { return mono_string_new_len(mono_domain_get(), value, rlen); } return mono_string_new(mono_domain_get(), ""); } static MonoString *uwsgi_mono_method_GetServerVariable(MonoObject *this, MonoString *key) { struct wsgi_request *wsgi_req = current_wsgi_req(); uint16_t rlen = 0; char *value = uwsgi_get_var(wsgi_req, mono_string_to_utf8(key), mono_string_length(key), &rlen); if (value) { return mono_string_new_len(mono_domain_get(), value, rlen); } return mono_string_new(mono_domain_get(), ""); } static int uwsgi_mono_method_ReadEntityBody(MonoObject *this, MonoArray *byteArray, int len) { struct wsgi_request *wsgi_req = current_wsgi_req(); char *buf = mono_array_addr(byteArray, char, 0); ssize_t rlen = 0; char *chunk = uwsgi_request_body_read(wsgi_req, len, &rlen); if (chunk == uwsgi.empty) { return 0; } if (chunk) { memcpy(buf, chunk, rlen); return rlen; } return -1; } static int uwsgi_mono_method_GetTotalEntityBodyLength(MonoObject *this) { struct wsgi_request *wsgi_req = current_wsgi_req(); return wsgi_req->post_cl; } static void uwsgi_mono_method_api_RegisterSignal(int signum, MonoString *target, MonoObject *func) { mono_gchandle_new(func, 1); if (uwsgi_register_signal(signum, mono_string_to_utf8(target), func, mono_plugin.modifier1)) { mono_raise_exception(mono_get_exception_invalid_operation("unable to register signal handler")); } } static void uwsgi_mono_method_api_Signal(int signum) { uwsgi_signal_send(uwsgi.signal_socket, signum); } static int uwsgi_mono_method_api_WorkerId() { return uwsgi.mywid; } static MonoArray *uwsgi_mono_method_api_CacheGet(MonoString *key, MonoString *cache) { char *c_key = mono_string_to_utf8(key); uint16_t c_keylen = mono_string_length(key); char *c_cache = NULL; if (cache) { c_cache = mono_string_to_utf8(cache); } uint64_t vallen = 0 ; char *value = uwsgi_cache_magic_get(c_key, c_keylen, &vallen, NULL, c_cache); if (value) { MonoArray *ret = mono_array_new(mono_domain_get(), umono.byte_class, vallen); char *buf = mono_array_addr(ret, char, 0); memcpy(buf, value, vallen); free(value); return ret; } return NULL; } static void uwsgi_mono_add_internal_calls() { // uWSGIRequest mono_add_internal_call("uwsgi.uWSGIRequest::SendResponseFromMemory", uwsgi_mono_method_SendResponseFromMemory); mono_add_internal_call("uwsgi.uWSGIRequest::SendStatus", uwsgi_mono_method_SendStatus); mono_add_internal_call("uwsgi.uWSGIRequest::SendUnknownResponseHeader", uwsgi_mono_method_SendUnknownResponseHeader); mono_add_internal_call("uwsgi.uWSGIRequest::FlushResponse", uwsgi_mono_method_FlushResponse); mono_add_internal_call("uwsgi.uWSGIRequest::GetQueryString", uwsgi_mono_method_GetQueryString); mono_add_internal_call("uwsgi.uWSGIRequest::MapPath", uwsgi_mono_method_MapPath); mono_add_internal_call("uwsgi.uWSGIRequest::GetHttpVerbName", uwsgi_mono_method_GetHttpVerbName); mono_add_internal_call("uwsgi.uWSGIRequest::GetRawUrl", uwsgi_mono_method_GetRawUrl); mono_add_internal_call("uwsgi.uWSGIRequest::GetFilePath", uwsgi_mono_method_GetFilePath); mono_add_internal_call("uwsgi.uWSGIRequest::GetUriPath", uwsgi_mono_method_GetUriPath); mono_add_internal_call("uwsgi.uWSGIRequest::SendResponseFromFile", uwsgi_mono_method_SendResponseFromFile); mono_add_internal_call("uwsgi.uWSGIRequest::SendResponseFromFd", uwsgi_mono_method_SendResponseFromFd); mono_add_internal_call("uwsgi.uWSGIRequest::GetHeaderByName", uwsgi_mono_method_GetHeaderByName); mono_add_internal_call("uwsgi.uWSGIRequest::ReadEntityBody", uwsgi_mono_method_ReadEntityBody); mono_add_internal_call("uwsgi.uWSGIRequest::GetTotalEntityBodyLength", uwsgi_mono_method_GetTotalEntityBodyLength); mono_add_internal_call("uwsgi.uWSGIRequest::GetHttpVersion", uwsgi_mono_method_GetHttpVersion); mono_add_internal_call("uwsgi.uWSGIRequest::GetServerVariable", uwsgi_mono_method_GetServerVariable); mono_add_internal_call("uwsgi.uWSGIRequest::GetRemoteAddress", uwsgi_mono_method_GetRemoteAddress); // api mono_add_internal_call("uwsgi.api::Signal", uwsgi_mono_method_api_Signal); mono_add_internal_call("uwsgi.api::WorkerId", uwsgi_mono_method_api_WorkerId); mono_add_internal_call("uwsgi.api::RegisterSignal", uwsgi_mono_method_api_RegisterSignal); mono_add_internal_call("uwsgi.api::CacheGet", uwsgi_mono_method_api_CacheGet); } static int uwsgi_mono_init() { if (!umono.version) { umono.version = "v4.0.30319"; } if (!umono.assembly_name) { umono.assembly_name = "uwsgi.dll"; } if (!umono.gc_freq) { umono.gc_freq = 1; } return 0; } static void uwsgi_mono_create_jit() { mono_config_parse(umono.config); umono.main_domain = mono_jit_init_version("uwsgi", umono.version); if (!umono.main_domain) { uwsgi_log("unable to initialize Mono JIT\n"); exit(1); } uwsgi_log("Mono JIT initialized on worker %d with version %s\n", uwsgi.mywid, umono.version); MonoAssembly *assembly = mono_domain_assembly_open(umono.main_domain, umono.assembly_name); if (!assembly) { uwsgi_log("%s not found trying in global gac...\n", umono.assembly_name); assembly = mono_assembly_load_with_partial_name(umono.assembly_name, NULL); if (!assembly) { if (!strcmp("uwsgi.dll", umono.assembly_name)) { assembly = mono_assembly_load_with_partial_name("uwsgi", NULL); } } } if (!assembly) { uwsgi_log("unable to load \"%s\" in the Mono domain\n", umono.assembly_name); exit(1); } uwsgi_mono_add_internal_calls(); MonoImage *image = mono_assembly_get_image(assembly); if (!image) { uwsgi_log("unable to get assembly image\n"); exit(1); } umono.application_class = mono_class_from_name(image, "uwsgi", "uWSGIApplication"); if (!umono.application_class) { uwsgi_log("unable to get reference to class uwsgi.uWSGIApplication\n"); exit(1); } umono.byte_class = mono_class_from_name(mono_get_corlib(), "System", "Byte"); if (!umono.byte_class) { uwsgi_log("unable to get reference to class System.Byte\n"); exit(1); } MonoClass *urequest = mono_class_from_name(image, "uwsgi", "uWSGIRequest"); if (!urequest) { uwsgi_log("unable to get reference to class uwsgi.uWSGIRequest\n"); exit(1); } umono.filepath = mono_class_get_field_from_name(urequest, "filepath"); if (!umono.filepath) { uwsgi_log("unable to get reference to field uwsgi.uWSGIRequest.filepath\n"); } umono.api_class = mono_class_from_name(image, "uwsgi", "api"); if (!umono.api_class) { uwsgi_log("unable to get reference to class uwsgi.api\n"); exit(1); } MonoMethodDesc *desc = mono_method_desc_new("uwsgi.uWSGIApplication:.ctor(string,string)", 1); if (!desc) { uwsgi_log("unable to create description for uwsgi.uWSGIApplication:.ctor(string,string)\n"); exit(1); } umono.create_application_host = mono_method_desc_search_in_class(desc, umono.application_class); if (!umono.create_application_host) { uwsgi_log("unable to find constructor in uWSGIApplication class\n"); exit(1); } mono_method_desc_free(desc); desc = mono_method_desc_new("uwsgi.uWSGIApplication:Request()", 1); if (!desc) { uwsgi_log("unable to create description for uwsgi.uWSGIApplication:Request()\n"); exit(1); } MonoMethod *process_request = mono_method_desc_search_in_class(desc, umono.application_class); if (!process_request) { uwsgi_log("unable to find ProcessRequest method in uwsgi_host class\n"); exit(1); } mono_method_desc_free(desc); umono.process_request = mono_method_get_unmanaged_thunk(process_request); struct uwsgi_string_list *usl = umono.exec; while(usl) { char *assembly_name = usl->value; char *argv = ""; char *colon = strchr(usl->value, ':'); if (colon) { argv = colon+1; assembly_name = uwsgi_concat2n(usl->value, colon-usl->value, "", 0); } MonoAssembly *assembly = mono_domain_assembly_open(umono.main_domain, assembly_name); if (!assembly) { uwsgi_log("unable to load assembly \"%s\"\n", assembly_name); exit(1); } mono_jit_exec(umono.main_domain, assembly, 1, &argv); if (assembly_name != usl->value) { free(assembly_name); } usl = usl->next; } } static int uwsgi_mono_create_app(char *key, uint16_t key_len, char *physicalDir, uint16_t physicalDir_len, int new_domain) { void *params[3]; params[2] = NULL; params[0] = mono_string_new(mono_domain_get(), "/"); params[1] = mono_string_new_len(mono_domain_get(), physicalDir, physicalDir_len); int id = uwsgi_apps_cnt; time_t now = uwsgi_now(); MonoObject *appHost = mono_object_new(mono_domain_get(), umono.application_class); if (!appHost) { uwsgi_log("unable to initialize asp.net ApplicationHost\n"); return -1; } MonoObject *exc = NULL; mono_runtime_invoke(umono.create_application_host, appHost, params, &exc); if (exc) { mono_print_unhandled_exception(exc); return -1; } struct uwsgi_app *app = uwsgi_add_app(id, mono_plugin.modifier1, key, key_len, uwsgi_concat2n(physicalDir, physicalDir_len, "", 0), appHost); app->started_at = now; app->startup_time = uwsgi_now() - now; // get a handlet to appHost mono_gchandle_new(app->callable, 1); uwsgi_log("Mono asp.net app %d (%.*s) loaded in %d seconds at %p (worker %d)\n", id, key_len, key, (int) app->startup_time, appHost, uwsgi.mywid); // set it as default app if needed if (uwsgi.default_app == -1) { uwsgi.default_app = id; } return id; } static void uwsgi_mono_init_apps() { if (!umono.main_domain) { uwsgi_mono_create_jit(); } struct uwsgi_string_list *usl = umono.app; while(usl) { char *mountpoint = usl->value; uint8_t mountpoint_len = usl->len; char *physicalDir = mountpoint; uint8_t physicalDir_len = mountpoint_len; char *equal = strchr(mountpoint, '='); if (equal) { physicalDir = equal+1; physicalDir_len = strlen(physicalDir); // ensure NULL char is at end (just for being backward compatible) mountpoint = uwsgi_concat2n(mountpoint, equal - mountpoint, "", 0); mountpoint_len = strlen(mountpoint); } int id = uwsgi_mono_create_app(mountpoint, mountpoint_len, physicalDir, physicalDir_len, 0); if (id == -1) { exit(1); } uwsgi_emulate_cow_for_apps(id); usl = usl->next; } } static int uwsgi_mono_request(struct wsgi_request *wsgi_req) { /* Standard ASP.NET request */ if (!wsgi_req->uh->pktsize) { uwsgi_log("Empty Mono/ASP.NET request. skip.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } char *key = wsgi_req->document_root; uint16_t key_len = wsgi_req->document_root_len; struct uwsgi_string_list *usl = umono.key; while(usl) { key = uwsgi_get_var(wsgi_req, usl->value, usl->len, &key_len); if (key) break; usl = usl->next; } // avoid unexpected values if (key == NULL) { key = ""; key_len = 0; } wsgi_req->app_id = uwsgi_get_app_id(NULL, key, key_len, mono_plugin.modifier1); // if it is -1, try to load a dynamic app if (wsgi_req->app_id == -1 && key_len > 0) { if (uwsgi.threads > 1) { pthread_mutex_lock(&umono.lock_loader); } // check if in the mean time, something changed wsgi_req->app_id = uwsgi_get_app_id(NULL, key, key_len, mono_plugin.modifier1); if (wsgi_req->app_id == -1) { wsgi_req->app_id = uwsgi_mono_create_app(key, key_len, key, key_len, 0); } if (uwsgi.threads > 1) { pthread_mutex_unlock(&umono.lock_loader); } } if (wsgi_req->app_id == -1) { if (!uwsgi.no_default_app && uwsgi.default_app > -1 && uwsgi_apps[uwsgi.default_app].modifier1 == mono_plugin.modifier1) { wsgi_req->app_id = uwsgi.default_app; } else { uwsgi_500(wsgi_req); uwsgi_log("--- unable to find Mono/ASP.NET application ---\n"); // nothing to clear/free return UWSGI_OK; } } struct uwsgi_app *app = &uwsgi_apps[wsgi_req->app_id]; app->requests++; // check for directory without slash char *path = uwsgi_concat3n(app->interpreter, strlen(app->interpreter), "/", 1, wsgi_req->path_info, wsgi_req->path_info_len); size_t path_len = strlen(app->interpreter) + 1 + wsgi_req->path_info_len; if (uwsgi_is_dir(path) && path[path_len-1] != '/') { free(path); uwsgi_redirect_to_slash(wsgi_req); return UWSGI_OK; } free(path); MonoException *exc = NULL; umono.process_request(app->callable, &exc); if (exc) { mono_print_unhandled_exception((MonoObject *)exc); } if ( uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].requests % umono.gc_freq == 0) { mono_gc_collect (mono_gc_max_generation()); } return UWSGI_OK; } static void uwsgi_mono_after_request(struct wsgi_request *wsgi_req) { log_request(wsgi_req); } static void uwsgi_mono_init_thread(int core_id) { mono_thread_attach(umono.main_domain); // SIGPWR, SIGXCPU: these are used internally by the GC and pthreads. sigset_t smask; sigemptyset(&smask); #if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__GNU_kFreeBSD__) sigaddset(&smask, SIGXFSZ); #else sigaddset(&smask, SIGPWR); #endif if (sigprocmask(SIG_UNBLOCK, &smask, NULL)) { uwsgi_error("uwsgi_mono_init_thread()/sigprocmask()"); } } static void uwsgi_mono_pthread_prepare(void) { pthread_mutex_lock(&umono.lock_loader); } static void uwsgi_mono_pthread_parent(void) { pthread_mutex_unlock(&umono.lock_loader); } static void uwsgi_mono_pthread_child(void) { pthread_mutex_init(&umono.lock_loader, NULL); } static void uwsgi_mono_enable_threads(void) { pthread_mutex_init(&umono.lock_loader, NULL); pthread_atfork(uwsgi_mono_pthread_prepare, uwsgi_mono_pthread_parent, uwsgi_mono_pthread_child); } static void uwsgi_mono_post_fork() { // yes, Mono is not fork-friendly, so we initialize it in the post_fork hook uwsgi_mono_init_apps(); MonoMethodDesc *desc = mono_method_desc_new("uwsgi.api:RunPostForkHook()", 1); if (!desc) { return; } MonoMethod *method = mono_method_desc_search_in_class(desc, umono.api_class); mono_method_desc_free(desc); if (!method) { return; } MonoObject *exc = NULL; mono_runtime_invoke(method, NULL, NULL, &exc); if (exc) { mono_print_unhandled_exception(exc); } } static int uwsgi_mono_signal_handler(uint8_t sig, void *handler) { void *params[2]; int signum = sig; params[0] = &signum; params[1] = NULL; MonoObject *exc = NULL; mono_runtime_delegate_invoke((MonoObject *) handler, params, &exc); if (exc) { mono_print_unhandled_exception(exc); return -1; } return 0; } struct uwsgi_plugin mono_plugin = { .name = "mono", .modifier1 = 15, .options = uwsgi_mono_options, .init = uwsgi_mono_init, .request = uwsgi_mono_request, .after_request = uwsgi_mono_after_request, .init_thread = uwsgi_mono_init_thread, .enable_threads = uwsgi_mono_enable_threads, .post_fork = uwsgi_mono_post_fork, .signal_handler = uwsgi_mono_signal_handler, }; uwsgi-2.0.29/plugins/mono/uwsgi.cs000066400000000000000000000116231477626554400171070ustar00rootroot00000000000000using System; using System.IO; using System.Net; using System.Web; using System.Web.Hosting; using System.Text; using System.Runtime.CompilerServices; [assembly: System.Reflection.AssemblyVersion ("0.0.0.1")] namespace uwsgi { public delegate void uWSGIHook(); public delegate void uWSGIHook1(int signum); public class api { static uWSGIHook postfork_hook = null; [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public static void RegisterSignal(int signum, string target, uWSGIHook1 func); public static void PostFork(uWSGIHook func) { postfork_hook = func; } public static void RunPostForkHook() { if (postfork_hook != null) { postfork_hook(); } } [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public static int WorkerId(); [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public static void Signal(int signum); [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public static byte[] CacheGet(string key, string cache=null); } class uWSGIRequest: HttpWorkerRequest { private String filepath = null; public override string GetAppPath() { return "/"; } [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public override string GetServerVariable(string name); public override bool IsEntireEntityBodyIsPreloaded() { return false; } public override string GetUnknownRequestHeader(string name) { return GetHeaderByName(name); } public override byte[] GetPreloadedEntityBody() { return null; } [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public string GetHeaderByName(string name); public override string GetKnownRequestHeader(int index) { return GetHeaderByName(GetKnownRequestHeaderName(index)); } [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public override int GetTotalEntityBodyLength(); [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public override int ReadEntityBody(byte[] buffer, int size); [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public override string GetFilePath(); [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public override string MapPath(string virtualPath); public override void EndOfRequest() { } [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public override void FlushResponse(bool finalFlush); [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public override string GetHttpVerbName(); [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public override string GetHttpVersion(); public override string GetLocalAddress() { return GetServerVariable("SERVER_ADDR"); } public override int GetLocalPort() { return Convert.ToInt32(GetServerVariable("SERVER_PORT")); } [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public override string GetQueryString(); [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public override string GetRawUrl(); [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public override string GetRemoteAddress(); public override int GetRemotePort() { return Convert.ToInt32(GetServerVariable("REMOTE_PORT")); } [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public override string GetUriPath(); public override void SendKnownResponseHeader (int index, string value) { string headerName = HttpWorkerRequest.GetKnownResponseHeaderName (index); SendUnknownResponseHeader (headerName, value); } [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public override void SendResponseFromMemory(byte[] chunk, int length); [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public void SendResponseFromFd(int fd, long offset, long length); public override void SendResponseFromFile (IntPtr handle, long offset, long length) { SendResponseFromFd(handle.ToInt32(), offset, length); } [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public override void SendResponseFromFile(string filename, long offset, long length); [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public override void SendStatus(int status, string msg); [MethodImplAttribute(MethodImplOptions.InternalCall)] extern public override void SendUnknownResponseHeader (string name, string value); public string hack_current_filename() { return filepath; } } public class uWSGIApplicationHost: MarshalByRefObject { public void ProcessRequest() { uWSGIRequest ur = new uWSGIRequest(); HttpRuntime.ProcessRequest(ur); } } public class uWSGIApplication { public uWSGIApplicationHost appHost; public uWSGIApplication(string virtualPath, string physicalPath) { appHost = (uWSGIApplicationHost)ApplicationHost.CreateApplicationHost(typeof(uWSGIApplicationHost), virtualPath, physicalPath); } public void Request() { appHost.ProcessRequest(); } } } uwsgi-2.0.29/plugins/mono/uwsgiplugin.py000066400000000000000000000012171477626554400203470ustar00rootroot00000000000000import os import subprocess NAME = 'mono' CFLAGS = os.popen('pkg-config --cflags mono-2').read().rstrip().split() LDFLAGS = [] LIBS = os.popen('pkg-config --libs mono-2').read().rstrip().split() GCC_LIST = ['mono_plugin'] if os.uname()[0] == 'Darwin': LIBS.append('-framework Foundation') def post_build(config): if subprocess.call("sn -k plugins/mono/uwsgi.key", shell=True) != 0: os._exit(1) if subprocess.call("mcs /target:library /r:System.Web.dll /keyfile:plugins/mono/uwsgi.key plugins/mono/uwsgi.cs", shell=True) != 0: os._exit(1) print("*** uwsgi.dll available in %s/plugins/mono/uwsgi.dll ***" % os.getcwd()) uwsgi-2.0.29/plugins/msgpack/000077500000000000000000000000001477626554400160745ustar00rootroot00000000000000uwsgi-2.0.29/plugins/msgpack/msgpack.c000066400000000000000000000276171477626554400177020ustar00rootroot00000000000000#include extern struct uwsgi_server uwsgi; /* msgpack utilities */ enum { MSGPACK_NIL = 0, MSGPACK_TRUE, MSGPACK_FALSE, MSGPACK_INT, MSGPACK_FLOAT, MSGPACK_STR, MSGPACK_BIN, MSGPACK_ARRAY, MSGPACK_MAP, MSGPACK_EXT, MSGPACK_MAGIC, }; struct uwsgi_msgpack_item { uint8_t type; char *str; uint32_t str_len; int64_t num; double fnum; int (*func)(char *); struct uwsgi_msgpack_item *next; }; struct uwsgi_msgpack_item *uwsgi_msgpack_item_add(struct uwsgi_msgpack_item **list, uint8_t type) { struct uwsgi_msgpack_item *old_umi = NULL, *umi = *list; while(umi) { old_umi = umi; umi = umi->next; } umi = uwsgi_calloc(sizeof(struct uwsgi_msgpack_item)); umi->type = type; if (old_umi) { old_umi->next = umi; } else { *list = umi; } return umi; } int uwsgi_buffer_msgpack_map(struct uwsgi_buffer *ub, uint32_t len) { if (len <= 15) { return uwsgi_buffer_byte(ub, 0x80 + len); } else if (len <= 0xffff) { if (uwsgi_buffer_byte(ub, 0xDE)) return -1; return uwsgi_buffer_u16be(ub, (uint16_t) len); } if (uwsgi_buffer_byte(ub, 0xDF)) return -1; return uwsgi_buffer_u32be(ub, len); } int uwsgi_buffer_msgpack_array(struct uwsgi_buffer *ub, uint32_t len) { if (len <= 15) { return uwsgi_buffer_byte(ub, 0x90 + len); } else if (len <= 0xffff) { if (uwsgi_buffer_byte(ub, 0xDC)) return -1; return uwsgi_buffer_u16be(ub, (uint16_t) len); } if (uwsgi_buffer_byte(ub, 0xDD)) return -1; return uwsgi_buffer_u32be(ub, len); } int uwsgi_buffer_msgpack_str(struct uwsgi_buffer *ub, char *str, uint32_t len) { if (len <= 31) { if (uwsgi_buffer_byte(ub, 0xA0 + len)) return -1; } // this is annoying, D9 does not work for older SPEC :( /* else if (len <= 0xff) { if (uwsgi_buffer_byte(ub, 0xD9)) return -1; if (uwsgi_buffer_byte(ub, (uint8_t) len)) return -1; } */ else if (len <= 0xffff) { if (uwsgi_buffer_byte(ub, 0xDA)) return -1; if (uwsgi_buffer_u16be(ub, (uint16_t) len)) return -1; } else { if (uwsgi_buffer_byte(ub, 0xDB)) return -1; if (uwsgi_buffer_u32be(ub, len)) return -1; } return uwsgi_buffer_append(ub, str, len); } int uwsgi_buffer_msgpack_bin(struct uwsgi_buffer *ub, char *str, uint32_t len) { if (len <= 0xff) { if (uwsgi_buffer_byte(ub, 0xC4)) return -1; if (uwsgi_buffer_byte(ub, (uint8_t) len)) return -1; } else if (len <= 0xffff) { if (uwsgi_buffer_byte(ub, 0xC5)) return -1; if (uwsgi_buffer_u16be(ub, (uint16_t) len)) return -1; } else { if (uwsgi_buffer_byte(ub, 0xC6)) return -1; if (uwsgi_buffer_u32be(ub, len)) return -1; } return uwsgi_buffer_append(ub, str, len); } int uwsgi_buffer_msgpack_int(struct uwsgi_buffer *ub, int64_t num) { if (num > 0 && num <= 127) { return uwsgi_buffer_byte(ub, (uint8_t) num); } else if (num < 0 && num >= -31) { return uwsgi_buffer_byte(ub, 224 | (int8_t) num); } else if (num <= 127 && num >= -127) { if (uwsgi_buffer_byte(ub, 0xD0)) return -1; return uwsgi_buffer_byte(ub, (int8_t) num); } else if (num <= 32767 && num >= -32767) { if (uwsgi_buffer_byte(ub, 0xD1)) return -1; return uwsgi_buffer_u16be(ub, (uint16_t) num); } else if (num <= 2147483647LL && num >= -2147483648LL) { if (uwsgi_buffer_byte(ub, 0xD2)) return -1; return uwsgi_buffer_u32be(ub, (uint32_t) num); } if (uwsgi_buffer_byte(ub, 0xD3)) return -1; return uwsgi_buffer_u64be(ub, (uint64_t)num); } int uwsgi_buffer_msgpack_float(struct uwsgi_buffer *ub, double num) { if (num >= -126.0 && num <= 127.0) { if (uwsgi_buffer_byte(ub, 0xCA)) return -1; return uwsgi_buffer_f32be(ub, (float) num); } if (uwsgi_buffer_byte(ub, 0xCB)) return -1; return uwsgi_buffer_f64be(ub, num); } int uwsgi_buffer_msgpack_nil(struct uwsgi_buffer *ub) { return uwsgi_buffer_byte(ub, 0xC0); } int uwsgi_buffer_msgpack_true(struct uwsgi_buffer *ub) { return uwsgi_buffer_byte(ub, 0xC3); } int uwsgi_buffer_msgpack_false(struct uwsgi_buffer *ub) { return uwsgi_buffer_byte(ub, 0xC2); } static char *uwsgi_msgpack_log_encoder(struct uwsgi_log_encoder *ule, char *msg, size_t len, size_t *rlen) { char *buf = NULL; if (!ule->configured) { char *p, *ctx = NULL; uwsgi_foreach_token(ule->args, "|", p, ctx) { char *colon = strchr(p, ':'); if (colon) *colon = 0; // find the type of item if (!strcmp(p, "map")) { struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_MAP); if (colon) { new_umi->num = strtoull(colon+1, NULL, 10); } } else if (!strcmp(p, "array")) { struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_ARRAY); if (colon) { new_umi->num = strtoull(colon+1, NULL, 10); } } else if (!strcmp(p, "nil")) { uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_NIL); } else if (!strcmp(p, "true")) { uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_TRUE); } else if (!strcmp(p, "false")) { uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_FALSE); } else if (!strcmp(p, "int")) { struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_INT); if (colon) { new_umi->num = strtoll(colon+1, NULL, 10); } } else if (!strcmp(p, "float")) { struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_FLOAT); if (colon) { new_umi->fnum = strtod(colon+1, NULL); } } else if (!strcmp(p, "str")) { struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_STR); if (colon) { new_umi->str = colon+1; new_umi->str_len = strlen(colon+1); } else { new_umi->str = ""; } } else if (!strcmp(p, "bin")) { struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_BIN); if (colon) { new_umi->str = colon+1; new_umi->str_len = strlen(colon+1); } else { new_umi->str = ""; } } else if (!strcmp(p, "msg")) { uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_MAGIC); } else if (!strcmp(p, "msgbin")) { struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_MAGIC); new_umi->num = 1; } else if (!strcmp(p, "msgnl")) { struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_MAGIC); new_umi->num = 2; } else if (!strcmp(p, "msgbinnl")) { struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_MAGIC); new_umi->num = 3; } else if (!strcmp(p, "unix")) { struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_MAGIC); new_umi->num = 4; } else if (!strcmp(p, "micros")) { struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_MAGIC); new_umi->num = 5; } else if (!strcmp(p, "strftime")) { struct uwsgi_msgpack_item *new_umi = uwsgi_msgpack_item_add((struct uwsgi_msgpack_item**)&ule->data, MSGPACK_MAGIC); new_umi->num = 6; if (colon) { new_umi->str = colon+1; new_umi->str_len = strlen(colon+1); } else { new_umi->str = ""; } } if (colon) *colon = ':'; } ule->configured = 1; } struct uwsgi_buffer *ub = uwsgi_buffer_new(len + strlen(ule->args)); struct uwsgi_msgpack_item *umi = (struct uwsgi_msgpack_item*) ule->data; uint32_t tmp_len = 0; while(umi) { switch(umi->type) { case(MSGPACK_NIL): if (uwsgi_buffer_msgpack_nil(ub)) goto end; break; case(MSGPACK_TRUE): if (uwsgi_buffer_msgpack_true(ub)) goto end; break; case(MSGPACK_FALSE): if (uwsgi_buffer_msgpack_false(ub)) goto end; break; case(MSGPACK_STR): if (uwsgi_buffer_msgpack_str(ub, umi->str, umi->str_len)) goto end; break; case(MSGPACK_BIN): if (uwsgi_buffer_msgpack_bin(ub, umi->str, umi->str_len)) goto end; break; case(MSGPACK_MAP): if (uwsgi_buffer_msgpack_map(ub, umi->num)) goto end; break; case(MSGPACK_ARRAY): if (uwsgi_buffer_msgpack_array(ub, umi->num)) goto end; break; case(MSGPACK_INT): if (uwsgi_buffer_msgpack_int(ub, umi->num)) goto end; break; case(MSGPACK_FLOAT): if (uwsgi_buffer_msgpack_float(ub, umi->fnum)) goto end; break; case(MSGPACK_MAGIC): // msg tmp_len = len; if (umi->num == 0) { if (msg[len-1] == '\n') tmp_len--; if (uwsgi_buffer_msgpack_str(ub, msg, tmp_len)) goto end; } // msgbin else if (umi->num == 1) { if (msg[len-1] == '\n') tmp_len--; if (uwsgi_buffer_msgpack_bin(ub, msg, tmp_len)) goto end; } // msgnl if (umi->num == 2) { if (uwsgi_buffer_msgpack_str(ub, msg, tmp_len)) goto end; } // msgbinnl else if (umi->num == 3) { if (uwsgi_buffer_msgpack_bin(ub, msg, tmp_len)) goto end; } // unix else if (umi->num == 4) { if (uwsgi_buffer_msgpack_int(ub, (int64_t)uwsgi_now())) goto end; } // micros else if (umi->num == 5) { if (uwsgi_buffer_msgpack_int(ub, (int64_t)uwsgi_micros())) goto end; } // strftime else if (umi->num == 6) { char sftime[64]; time_t now = uwsgi_now(); int rlen = strftime(sftime, 64, umi->str, localtime(&now)); if (rlen > 0) { if (uwsgi_buffer_msgpack_str(ub, sftime, rlen)) goto end; } else { if (uwsgi_buffer_msgpack_str(ub, "", 0)) goto end; } } break; default: break; } umi = umi->next; } buf = ub->buf; *rlen = ub->pos; ub->buf = NULL; end: uwsgi_buffer_destroy(ub); return buf; } static void uwsgi_msgpack_register() { uwsgi_register_log_encoder("msgpack", uwsgi_msgpack_log_encoder); } struct uwsgi_plugin msgpack_plugin = { .name = "msgpack", .on_load = uwsgi_msgpack_register, }; uwsgi-2.0.29/plugins/msgpack/uwsgiplugin.py000066400000000000000000000001031477626554400210150ustar00rootroot00000000000000NAME='msgpack' CFLAGS=[] LDFLAGS=[] LIBS=[] GCC_LIST = ['msgpack'] uwsgi-2.0.29/plugins/nagios/000077500000000000000000000000001477626554400157275ustar00rootroot00000000000000uwsgi-2.0.29/plugins/nagios/nagios.c000066400000000000000000000031261477626554400173550ustar00rootroot00000000000000#include "../../uwsgi.h" extern struct uwsgi_server uwsgi; int use_nagios = 0; struct uwsgi_option nagios_options[] = { {"nagios", no_argument, 0, "nagios check", uwsgi_opt_true, &use_nagios, UWSGI_OPT_NO_INITIAL}, {0, 0, 0, 0, 0, 0, 0}, }; int nagios() { struct uwsgi_header uh; char *buf = NULL; if (!use_nagios) { return 1; } if (!uwsgi.sockets) { fprintf(stdout, "UWSGI UNKNOWN: you have specified an invalid socket\n"); exit(3); } int fd = uwsgi_connect(uwsgi.sockets->name, uwsgi.socket_timeout, 0); if (fd < 0) { fprintf(stdout, "UWSGI CRITICAL: could not connect() to workers %s\n", strerror(errno)); if (errno == EPERM || errno == EACCES) { exit(3); } exit(2); } uh.modifier1 = UWSGI_MODIFIER_PING; uh.pktsize = 0; uh.modifier2 = 0; if (write(fd, &uh, 4) != 4) { uwsgi_error("write()"); fprintf(stdout, "UWSGI CRITICAL: could not send ping packet to workers\n"); exit(2); } int ret = uwsgi_read_response(fd, &uh, uwsgi.socket_timeout, &buf); if (ret == -2) { fprintf(stdout, "UWSGI CRITICAL: timed out waiting for response\n"); exit(2); } else if (ret == -1) { fprintf(stdout, "UWSGI CRITICAL: error reading response\n"); exit(2); } else { if (uh.pktsize > 0 && buf) { fprintf(stdout, "UWSGI WARNING: %.*s\n", uh.pktsize, buf); exit(1); } else { fprintf(stdout, "UWSGI OK: armed and ready\n"); exit(0); } } // never here fprintf(stdout, "UWSGI UNKNOWN: probably you hit a bug of uWSGI !!!\n"); exit(3); } struct uwsgi_plugin nagios_plugin = { .name = "nagios", .options = nagios_options, .init = nagios, }; uwsgi-2.0.29/plugins/nagios/uwsgiplugin.py000066400000000000000000000001111477626554400206470ustar00rootroot00000000000000 NAME='nagios' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['nagios'] uwsgi-2.0.29/plugins/notfound/000077500000000000000000000000001477626554400163035ustar00rootroot00000000000000uwsgi-2.0.29/plugins/notfound/notfound.c000066400000000000000000000013441477626554400203050ustar00rootroot00000000000000#include static int uwsgi_notfound_log_enabled = 0; struct uwsgi_option uwsgi_notfound_options[] = { {"notfound-log", no_argument, 0, "log requests to the notfound plugin", uwsgi_opt_true, &uwsgi_notfound_log_enabled, 0}, {NULL, 0, 0, NULL, NULL, NULL, 0}, }; static int uwsgi_request_notfound(struct wsgi_request *wsgi_req) { if (uwsgi_parse_vars(wsgi_req)) { return -1; } uwsgi_404(wsgi_req); return UWSGI_OK; } static void uwsgi_notfound_log(struct wsgi_request *wsgi_req) { if (uwsgi_notfound_log_enabled) { log_request(wsgi_req); } } struct uwsgi_plugin notfound_plugin = { .name = "notfound", .options = uwsgi_notfound_options, .request = uwsgi_request_notfound, .after_request = uwsgi_notfound_log, }; uwsgi-2.0.29/plugins/notfound/uwsgiplugin.py000066400000000000000000000001141477626554400212260ustar00rootroot00000000000000NAME='notfound' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['notfound'] uwsgi-2.0.29/plugins/objc_gc/000077500000000000000000000000001477626554400160355ustar00rootroot00000000000000uwsgi-2.0.29/plugins/objc_gc/objc_gc.m000066400000000000000000000001221477626554400175740ustar00rootroot00000000000000#include struct uwsgi_plugin objc_gc_plugin = { .name = "objc_gc", }; uwsgi-2.0.29/plugins/objc_gc/uwsgiplugin.py000066400000000000000000000001161477626554400207620ustar00rootroot00000000000000NAME="objc_gc" CFLAGS=["-fobjc-gc"] LDFLAGS=[] LIBS=[] GCC_LIST=['objc_gc.m'] uwsgi-2.0.29/plugins/pam/000077500000000000000000000000001477626554400152245ustar00rootroot00000000000000uwsgi-2.0.29/plugins/pam/pam.c000066400000000000000000000031041477626554400161430ustar00rootroot00000000000000/* uWSGI pam plugin 20120809 Credits: Harry Percival (PythonAnywhere.com) */ #include "../../uwsgi.h" extern struct uwsgi_server uwsgi; #include char *uwsgi_pam_service = NULL; char *uwsgi_pam_user = NULL; struct uwsgi_option uwsgi_pam_options[] = { {"pam", required_argument, 0, "set the pam service name to use", uwsgi_opt_set_str, &uwsgi_pam_service, 0}, {"pam-user", required_argument, 0, "set a fake user for pam", uwsgi_opt_set_str, &uwsgi_pam_user, 0}, {0, 0, 0, 0, 0, 0 ,0}, }; static int uwsgi_pam_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) { int i; for(i=0;imsg); } return PAM_SUCCESS; } void uwsgi_setup_pam(void) { pam_handle_t *pamh = NULL; struct pam_conv pamc = { uwsgi_pam_conv, NULL }; if (uwsgi_pam_service) { if (!uwsgi_pam_user) { if (!uwsgi.uid) { uwsgi_log("you cannot use pam for root !!!\n"); exit(1); } struct passwd *pwd = getpwuid(uwsgi.uid); if (!pwd) { uwsgi_error("getpwuid()"); exit(1); } // no need to make a copy as we will use that only here uwsgi_pam_user = pwd->pw_name; } if (pam_start(uwsgi_pam_service, uwsgi_pam_user, &pamc, &pamh) != PAM_SUCCESS) { uwsgi_error("pam_start()"); exit(1); } if (pam_open_session(pamh, 0) != PAM_SUCCESS) { uwsgi_error("pam_open_session()"); exit(1); } } } struct uwsgi_plugin pam_plugin = { .name = "pam", .options = uwsgi_pam_options, .before_privileges_drop = uwsgi_setup_pam, }; uwsgi-2.0.29/plugins/pam/uwsgiplugin.py000066400000000000000000000001111477626554400201440ustar00rootroot00000000000000NAME='pam' CFLAGS = [] LDFLAGS = [] LIBS = ['-lpam'] GCC_LIST = ['pam'] uwsgi-2.0.29/plugins/php/000077500000000000000000000000001477626554400152365ustar00rootroot00000000000000uwsgi-2.0.29/plugins/php/common.h000066400000000000000000000003171477626554400167000ustar00rootroot00000000000000#include "php.h" #include "SAPI.h" #include "php_main.h" #include "php_variables.h" #include "ext/standard/info.h" #include "ext/session/php_session.h" #include "ext/standard/head.h" #include uwsgi-2.0.29/plugins/php/php_plugin.c000066400000000000000000001014121477626554400175460ustar00rootroot00000000000000#include "common.h" extern struct uwsgi_server uwsgi; static sapi_module_struct uwsgi_sapi_module; static int uwsgi_php_init(void); typedef size_t php_strlen_size; typedef zend_long php_long_size; struct uwsgi_php { struct uwsgi_string_list *allowed_docroot; struct uwsgi_string_list *allowed_ext; struct uwsgi_string_list *allowed_scripts; struct uwsgi_string_list *index; struct uwsgi_string_list *set; struct uwsgi_string_list *append_config; #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) struct uwsgi_regexp_list *app_bypass; #endif struct uwsgi_string_list *vars; struct uwsgi_string_list *constants; char *docroot; size_t docroot_len; char *app; char *app_qs; char *fallback; char *fallback2; char *fallback_qs; char *ini_entries; size_t ini_size; int dump_config; char *server_software; size_t server_software_len; struct uwsgi_string_list *exec_before; struct uwsgi_string_list *exec_after; char *sapi_name; HashTable user_config_cache; } uphp; void uwsgi_opt_php_ini(char *opt, char *value, void *foobar) { uwsgi_sapi_module.php_ini_path_override = uwsgi_str(value); uwsgi_sapi_module.php_ini_ignore = 1; } struct uwsgi_option uwsgi_php_options[] = { {"php-ini", required_argument, 0, "set php.ini path", uwsgi_opt_php_ini, NULL, 0}, {"php-config", required_argument, 0, "set php.ini path", uwsgi_opt_php_ini, NULL, 0}, {"php-ini-append", required_argument, 0, "set php.ini path (append mode)", uwsgi_opt_add_string_list, &uphp.append_config, 0}, {"php-config-append", required_argument, 0, "set php.ini path (append mode)", uwsgi_opt_add_string_list, &uphp.append_config, 0}, {"php-set", required_argument, 0, "set a php config directive", uwsgi_opt_add_string_list, &uphp.set, 0}, {"php-index", required_argument, 0, "list the php index files", uwsgi_opt_add_string_list, &uphp.index, 0}, {"php-docroot", required_argument, 0, "force php DOCUMENT_ROOT", uwsgi_opt_set_str, &uphp.docroot, 0}, {"php-allowed-docroot", required_argument, 0, "list the allowed document roots", uwsgi_opt_add_string_list, &uphp.allowed_docroot, 0}, {"php-allowed-ext", required_argument, 0, "list the allowed php file extensions", uwsgi_opt_add_string_list, &uphp.allowed_ext, 0}, {"php-allowed-script", required_argument, 0, "list the allowed php scripts (require absolute path)", uwsgi_opt_add_string_list, &uphp.allowed_scripts, 0}, {"php-server-software", required_argument, 0, "force php SERVER_SOFTWARE", uwsgi_opt_set_str, &uphp.server_software, 0}, {"php-app", required_argument, 0, "force the php file to run at each request", uwsgi_opt_set_str, &uphp.app, 0}, {"php-app-qs", required_argument, 0, "when in app mode force QUERY_STRING to the specified value + REQUEST_URI", uwsgi_opt_set_str, &uphp.app_qs, 0}, {"php-fallback", required_argument, 0, "run the specified php script when the requested one does not exist", uwsgi_opt_set_str, &uphp.fallback, 0}, {"php-fallback2", required_argument, 0, "run the specified php script relative to the document root when the requested one does not exist", uwsgi_opt_set_str, &uphp.fallback2, 0}, {"php-fallback-qs", required_argument, 0, "php-fallback with QUERY_STRING set", uwsgi_opt_set_str, &uphp.fallback_qs, 0}, #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) {"php-app-bypass", required_argument, 0, "if the regexp matches the uri the --php-app is bypassed", uwsgi_opt_add_regexp_list, &uphp.app_bypass, 0}, #endif {"php-var", required_argument, 0, "add/overwrite a CGI variable at each request", uwsgi_opt_add_string_list, &uphp.vars, 0}, {"php-constant", required_argument, 0, "define a php constant for each request", uwsgi_opt_add_string_list, &uphp.constants, 0}, {"php-dump-config", no_argument, 0, "dump php config (if modified via --php-set or append options)", uwsgi_opt_true, &uphp.dump_config, 0}, {"php-exec-before", required_argument, 0, "run specified php code before the requested script", uwsgi_opt_add_string_list, &uphp.exec_before, 0}, {"php-exec-begin", required_argument, 0, "run specified php code before the requested script", uwsgi_opt_add_string_list, &uphp.exec_before, 0}, {"php-exec-after", required_argument, 0, "run specified php code after the requested script", uwsgi_opt_add_string_list, &uphp.exec_after, 0}, {"php-exec-end", required_argument, 0, "run specified php code after the requested script", uwsgi_opt_add_string_list, &uphp.exec_after, 0}, {"php-sapi-name", required_argument, 0, "hack the sapi name (required for enabling zend opcode cache)", uwsgi_opt_set_str, &uphp.sapi_name, 0}, UWSGI_END_OF_OPTIONS }; static size_t sapi_uwsgi_ub_write(const char *str, size_t str_length) { struct wsgi_request *wsgi_req = (struct wsgi_request *) SG(server_context); uwsgi_response_write_body_do(wsgi_req, (char *) str, str_length); if (wsgi_req->write_errors > uwsgi.write_errors_tolerance) { php_handle_aborted_connection(); return -1; } return str_length; } static int sapi_uwsgi_send_headers(sapi_headers_struct *sapi_headers) { sapi_header_struct *h; zend_llist_position pos; if (SG(request_info).no_headers == 1) { return SAPI_HEADER_SENT_SUCCESSFULLY; } struct wsgi_request *wsgi_req = (struct wsgi_request *) SG(server_context); if (!SG(sapi_headers).http_status_line) { char status[4]; int hrc = SG(sapi_headers).http_response_code; if (!hrc) hrc = 200; uwsgi_num2str2n(hrc, status, 4); if (uwsgi_response_prepare_headers(wsgi_req, status, 3)) return SAPI_HEADER_SEND_FAILED; } else { char *sl = SG(sapi_headers).http_status_line; if (uwsgi_response_prepare_headers(wsgi_req, sl + 9 , strlen(sl + 9))) return SAPI_HEADER_SEND_FAILED; } h = zend_llist_get_first_ex(&sapi_headers->headers, &pos); while (h) { uwsgi_response_add_header(wsgi_req, NULL, 0, h->header, h->header_len); h = zend_llist_get_next_ex(&sapi_headers->headers, &pos); } return SAPI_HEADER_SENT_SUCCESSFULLY; } static size_t sapi_uwsgi_read_post(char *buffer, size_t count_bytes) { uint read_bytes = 0; struct wsgi_request *wsgi_req = (struct wsgi_request *) SG(server_context); count_bytes = MIN(count_bytes, wsgi_req->post_cl - SG(read_post_bytes)); while (read_bytes < count_bytes) { ssize_t rlen = 0; char *buf = uwsgi_request_body_read(wsgi_req, count_bytes - read_bytes, &rlen); if (buf == uwsgi.empty) break; if (buf) { memcpy(buffer, buf, rlen); read_bytes += rlen; continue; } break; } return read_bytes; } static char *sapi_uwsgi_read_cookies() { uint16_t len = 0; struct wsgi_request *wsgi_req = (struct wsgi_request *) SG(server_context); char *cookie = uwsgi_get_var(wsgi_req, (char *)"HTTP_COOKIE", 11, &len); if (cookie) { return estrndup(cookie, len); } return NULL; } static void sapi_uwsgi_register_variables(zval *track_vars_array) { int i; struct wsgi_request *wsgi_req = (struct wsgi_request *) SG(server_context); php_import_environment_variables(track_vars_array); if (uphp.server_software) { if (!uphp.server_software_len) uphp.server_software_len = strlen(uphp.server_software); php_register_variable_safe("SERVER_SOFTWARE", uphp.server_software, uphp.server_software_len, track_vars_array); } else { php_register_variable_safe("SERVER_SOFTWARE", "uWSGI", 5, track_vars_array); } for (i = 0; i < wsgi_req->var_cnt; i += 2) { php_register_variable_safe( estrndup(wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len), wsgi_req->hvec[i + 1].iov_base, wsgi_req->hvec[i + 1].iov_len, track_vars_array); } php_register_variable_safe("PATH_INFO", wsgi_req->path_info, wsgi_req->path_info_len, track_vars_array); if (wsgi_req->query_string_len > 0) { php_register_variable_safe("QUERY_STRING", wsgi_req->query_string, wsgi_req->query_string_len, track_vars_array); } php_register_variable_safe("SCRIPT_NAME", wsgi_req->script_name, wsgi_req->script_name_len, track_vars_array); php_register_variable_safe("SCRIPT_FILENAME", wsgi_req->file, wsgi_req->file_len, track_vars_array); php_register_variable_safe("DOCUMENT_ROOT", wsgi_req->document_root, wsgi_req->document_root_len, track_vars_array); if (wsgi_req->path_info_len) { char *path_translated = ecalloc(1, wsgi_req->file_len + wsgi_req->path_info_len + 1); memcpy(path_translated, wsgi_req->file, wsgi_req->file_len); memcpy(path_translated + wsgi_req->file_len, wsgi_req->path_info, wsgi_req->path_info_len); php_register_variable_safe("PATH_TRANSLATED", path_translated, wsgi_req->file_len + wsgi_req->path_info_len , track_vars_array); } else { php_register_variable_safe("PATH_TRANSLATED", "", 0, track_vars_array); } php_register_variable_safe("PHP_SELF", wsgi_req->script_name, wsgi_req->script_name_len, track_vars_array); struct uwsgi_string_list *usl = uphp.vars; while(usl) { char *equal = strchr(usl->value, '='); if (equal) { php_register_variable_safe( estrndup(usl->value, equal-usl->value), equal+1, strlen(equal+1), track_vars_array); } usl = usl->next; } } static sapi_module_struct uwsgi_sapi_module; void uwsgi_php_append_config(char *filename) { size_t file_size = 0; char *file_content = uwsgi_open_and_read(filename, &file_size, 1, NULL); uphp.ini_entries = realloc(uphp.ini_entries, uphp.ini_size + file_size); memcpy(uphp.ini_entries + uphp.ini_size, file_content, file_size); uphp.ini_size += file_size-1; free(file_content); uwsgi_sapi_module.ini_entries = uphp.ini_entries; } void uwsgi_php_set(char *opt) { uphp.ini_entries = realloc(uphp.ini_entries, uphp.ini_size + strlen(opt)+2); memcpy(uphp.ini_entries + uphp.ini_size, opt, strlen(opt)); uphp.ini_size += strlen(opt)+1; uphp.ini_entries[uphp.ini_size-1] = '\n'; uphp.ini_entries[uphp.ini_size] = 0; uwsgi_sapi_module.ini_entries = uphp.ini_entries; } extern ps_module ps_mod_uwsgi; PHP_MINIT_FUNCTION(uwsgi_php_minit) { php_session_register_module(&ps_mod_uwsgi); struct uwsgi_string_list *usl = uphp.constants; while(usl) { char *equal = strchr(usl->value, '='); if (equal) { size_t name_len = equal - usl->value; char *name = usl->value; char *strval = equal + 1; equal = NULL; zend_register_string_constant(name, name_len, strval, CONST_CS | CONST_PERSISTENT, module_number); } usl = usl->next; } return SUCCESS; } PHP_FUNCTION(uwsgi_version) { RETURN_STRING(UWSGI_VERSION); } PHP_FUNCTION(uwsgi_worker_id) { RETURN_LONG(uwsgi.mywid); } PHP_FUNCTION(uwsgi_masterpid) { if (uwsgi.master_process) { RETURN_LONG(uwsgi.workers[0].pid); } RETURN_LONG(0); } PHP_FUNCTION(uwsgi_cache_exists) { char *key = NULL; php_strlen_size keylen = 0; char *cache = NULL; php_strlen_size cachelen = 0; if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s", &key, &keylen, &cache, &cachelen) == FAILURE) { RETURN_NULL(); } if (uwsgi_cache_magic_exists(key, keylen, cache)) { RETURN_TRUE; } RETURN_NULL(); } PHP_FUNCTION(uwsgi_cache_clear) { char *cache = NULL; php_strlen_size cachelen = 0; if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &cache, &cachelen) == FAILURE) { RETURN_NULL(); } if (!uwsgi_cache_magic_clear(cache)) { RETURN_TRUE; } RETURN_NULL(); } PHP_FUNCTION(uwsgi_cache_del) { char *key = NULL; php_strlen_size keylen = 0; char *cache = NULL; php_strlen_size cachelen = 0; if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s", &key, &keylen, &cache, &cachelen) == FAILURE) { RETURN_NULL(); } if (!uwsgi_cache_magic_del(key, keylen, cache)) { RETURN_TRUE; } RETURN_NULL(); } PHP_FUNCTION(uwsgi_cache_get) { char *key = NULL; php_strlen_size keylen = 0; char *cache = NULL; php_strlen_size cachelen = 0; uint64_t valsize; if (!uwsgi.caches) RETURN_NULL(); if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s", &key, &keylen, &cache, &cachelen) == FAILURE) { RETURN_NULL(); } char *value = uwsgi_cache_magic_get(key, keylen, &valsize, NULL, cache); if (value) { char *ret = estrndup(value, valsize); free(value); RETURN_STRING(ret); } RETURN_NULL(); } PHP_FUNCTION(uwsgi_cache_set) { char *key = NULL; php_strlen_size keylen = 0; char *value = NULL; php_strlen_size vallen = 0; php_long_size expires = 0; char *cache = NULL; php_strlen_size cachelen = 0; if (!uwsgi.caches) RETURN_NULL(); if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|ls", &key, &keylen, &value, &vallen, &expires, &cache, &cachelen) == FAILURE) { RETURN_NULL(); } if (!uwsgi_cache_magic_set(key, keylen, value, vallen, expires, 0, cache)) { RETURN_TRUE; } RETURN_NULL(); } PHP_FUNCTION(uwsgi_cache_update) { char *key = NULL; php_strlen_size keylen = 0; char *value = NULL; php_strlen_size vallen = 0; php_long_size expires = 0; char *cache = NULL; php_strlen_size cachelen = 0; if (!uwsgi.caches) RETURN_NULL(); if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|ls", &key, &keylen, &value, &vallen, &expires, &cache, &cachelen) == FAILURE) { RETURN_NULL(); } if (!uwsgi_cache_magic_set(key, keylen, value, vallen, expires, UWSGI_CACHE_FLAG_UPDATE, cache)) { RETURN_TRUE; } RETURN_NULL(); } PHP_FUNCTION(uwsgi_rpc) { int num_args = 0; int i; char *node = NULL; char *func = NULL; zval ***varargs = NULL; zval *z_current_obj; char *argv[256]; uint16_t argvs[256]; uint64_t size = 0; if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &varargs, &num_args) == FAILURE) { RETURN_NULL(); } if (num_args < 2) goto clear; if (num_args > 256 + 2) goto clear; z_current_obj = *varargs[0]; if (Z_TYPE_P(z_current_obj) != IS_STRING) { goto clear; } node = Z_STRVAL_P(z_current_obj); z_current_obj = *varargs[1]; if (Z_TYPE_P(z_current_obj) != IS_STRING) { goto clear; } func = Z_STRVAL_P(z_current_obj); for(i=0;i<(num_args-2);i++) { z_current_obj = *varargs[i+2]; if (Z_TYPE_P(z_current_obj) != IS_STRING) { goto clear; } argv[i] = Z_STRVAL_P(z_current_obj); argvs[i] = Z_STRLEN_P(z_current_obj); } // response must always be freed char *response = uwsgi_do_rpc(node, func, num_args - 2, argv, argvs, &size); if (response) { // here we do not free varargs for performance reasons char *ret = estrndup(response, size); free(response); RETURN_STRING(ret); } clear: efree(varargs); RETURN_NULL(); } PHP_FUNCTION(uwsgi_setprocname) { char *name; int name_len; if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) { RETURN_NULL(); } uwsgi_set_processname(estrndup(name, name_len)); RETURN_NULL(); } PHP_FUNCTION(uwsgi_signal) { long long_signum; uint8_t signum = 0; if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &long_signum) == FAILURE) { RETURN_NULL(); } signum = (uint8_t) long_signum; uwsgi_signal_send(uwsgi.signal_socket, signum); RETURN_NULL(); } PHP_FUNCTION(uwsgi_disconnect) { struct wsgi_request *wsgi_req = (struct wsgi_request *) SG(server_context); php_output_end_all(); php_header(); uwsgi_disconnect(wsgi_req); php_output_set_status(PHP_OUTPUT_DISABLED); RETURN_NULL(); } ZEND_BEGIN_ARG_INFO_EX(arginfo_void, 0, 0, 0) ZEND_END_ARG_INFO() zend_function_entry uwsgi_php_functions[] = { PHP_FE(uwsgi_version, arginfo_void) PHP_FE(uwsgi_setprocname, arginfo_void) PHP_FE(uwsgi_worker_id, arginfo_void) PHP_FE(uwsgi_masterpid, arginfo_void) PHP_FE(uwsgi_signal, arginfo_void) PHP_FE(uwsgi_rpc, arginfo_void) PHP_FE(uwsgi_cache_get, arginfo_void) PHP_FE(uwsgi_cache_set, arginfo_void) PHP_FE(uwsgi_cache_update, arginfo_void) PHP_FE(uwsgi_cache_del, arginfo_void) PHP_FE(uwsgi_cache_clear, arginfo_void) PHP_FE(uwsgi_cache_exists, arginfo_void) PHP_FE(uwsgi_disconnect, arginfo_void) { NULL, NULL, NULL}, }; PHP_MINFO_FUNCTION(uwsgi_php_minfo) { php_info_print_table_start( ); php_info_print_table_row(2, "uwsgi api", "enabled"); if (uwsgi.caches) { php_info_print_table_row(2, "uwsgi cache", "enabled"); } else { php_info_print_table_row(2, "uwsgi cache", "disabled"); } php_info_print_table_end( ); } static zend_module_entry uwsgi_module_entry = { STANDARD_MODULE_HEADER, "uwsgi", uwsgi_php_functions, PHP_MINIT(uwsgi_php_minit), NULL, NULL, NULL, PHP_MINFO(uwsgi_php_minfo), UWSGI_VERSION, STANDARD_MODULE_PROPERTIES }; typedef struct _user_config_cache_entry { time_t expires; HashTable *user_config; } user_config_cache_entry; #if (PHP_MAJOR_VERSION >= 7) static void user_config_cache_entry_dtor(zval *el) { user_config_cache_entry *entry = (user_config_cache_entry *)Z_PTR_P(el); #else static void user_config_cache_entry_dtor(user_config_cache_entry *entry) { #endif zend_hash_destroy(entry->user_config); free(entry->user_config); free(entry); } static void activate_user_config(const char *filename, const char *doc_root, size_t doc_root_len) { char *ptr; user_config_cache_entry *new_entry, *entry; time_t request_time = (time_t)sapi_get_request_time(); // get dirname (path) from filename size_t path_len = (strrchr(filename, DEFAULT_SLASH) - filename) + 1; char path[path_len]; memcpy(path, filename, path_len); path[path_len] = '\0'; // get or create entry from cache #if (PHP_MAJOR_VERSION >= 7) if ((entry = zend_hash_str_find_ptr(&uphp.user_config_cache, path, path_len)) == NULL) { #else if (zend_hash_find(&uphp.user_config_cache, path, path_len + 1, (void **) &entry) == FAILURE) { #endif new_entry = pemalloc(sizeof(user_config_cache_entry), 1); new_entry->expires = 0; new_entry->user_config = (HashTable *) pemalloc(sizeof(HashTable), 1); // make zend_hash to store all user.ini settings. zend_hash_init(new_entry->user_config, 0, NULL, (dtor_func_t) config_zval_dtor, 1); #if (PHP_MAJOR_VERSION >= 7) entry = zend_hash_str_update_ptr(&uphp.user_config_cache, path, path_len, new_entry); #else zend_hash_update(&uphp.user_config_cache, path, path_len + 1, new_entry, sizeof(user_config_cache_entry), (void **) &entry); #endif } if (request_time > entry->expires) { // clear the expired config zend_hash_clean(entry->user_config); // set pointer to end of docroot ptr = path + (doc_root_len - 1); // parse all user.ini files starting from docroot. while ((ptr = strchr(ptr, DEFAULT_SLASH)) != NULL) { *ptr = 0; php_parse_user_ini_file(path, PG(user_ini_filename), entry->user_config); *ptr = '/'; ptr++; } // set (new) expiry time entry->expires = request_time + PG(user_ini_cache_ttl); } // activate all user.ini variables php_ini_activate_config(entry->user_config, PHP_INI_PERDIR, PHP_INI_STAGE_HTACCESS); } static int php_uwsgi_startup(sapi_module_struct *sapi_module) { #if ((PHP_MAJOR_VERSION >= 8) && (PHP_MINOR_VERSION >= 2)) if (php_module_startup(&uwsgi_sapi_module, &uwsgi_module_entry)==FAILURE) { #else if (php_module_startup(&uwsgi_sapi_module, &uwsgi_module_entry, 1)==FAILURE) { #endif return FAILURE; } else { return SUCCESS; } } #if (PHP_MAJOR_VERSION >= 8) static void sapi_uwsgi_log_message(const char *message, int syslog_type_int) { #elif ((PHP_MAJOR_VERSION == 7) && (PHP_MINOR_VERSION >= 1)) static void sapi_uwsgi_log_message(char *message, int syslog_type_int) { #else static void sapi_uwsgi_log_message(char *message) { #endif uwsgi_log("%s\n", message); } static sapi_module_struct uwsgi_sapi_module = { "uwsgi", "uWSGI/php", php_uwsgi_startup, php_module_shutdown_wrapper, NULL, /* activate */ NULL, /* deactivate */ sapi_uwsgi_ub_write, NULL, NULL, /* get uid */ NULL, /* getenv */ php_error, NULL, sapi_uwsgi_send_headers, NULL, sapi_uwsgi_read_post, sapi_uwsgi_read_cookies, sapi_uwsgi_register_variables, sapi_uwsgi_log_message, /* Log message */ NULL, /* Get request time */ NULL, /* Child terminate */ STANDARD_SAPI_MODULE_PROPERTIES }; int uwsgi_php_init(void) { struct uwsgi_string_list *pset = uphp.set; struct uwsgi_string_list *append_config = uphp.append_config; #ifdef ZTS tsrm_startup(1, 1, 0, NULL); #endif sapi_startup(&uwsgi_sapi_module); // applying custom options while(append_config) { uwsgi_php_append_config(append_config->value); append_config = append_config->next; } while(pset) { uwsgi_php_set(pset->value); pset = pset->next; } if (uphp.dump_config) { uwsgi_log("--- PHP custom config ---\n\n"); uwsgi_log("%s\n", uwsgi_sapi_module.ini_entries); uwsgi_log("--- end of PHP custom config ---\n"); } zend_hash_init(&uphp.user_config_cache, 0, NULL, (dtor_func_t) user_config_cache_entry_dtor, 1); // fix docroot if (uphp.docroot) { char *orig_docroot = uphp.docroot; uphp.docroot = uwsgi_expand_path(uphp.docroot, strlen(uphp.docroot), NULL); if (!uphp.docroot) { uwsgi_log("unable to set php docroot to %s\n", orig_docroot); exit(1); } uwsgi_log("PHP document root set to %s\n", uphp.docroot); uphp.docroot_len = strlen(uphp.docroot); } if (uphp.sapi_name) { uwsgi_sapi_module.name = uphp.sapi_name; } uwsgi_sapi_module.startup(&uwsgi_sapi_module); uwsgi_log("PHP %s initialized\n", PHP_VERSION); return 0; } int uwsgi_php_walk(struct wsgi_request *wsgi_req, char *full_path, char *docroot, size_t docroot_len, char **path_info) { // and now start walking... uint16_t i; char *ptr = wsgi_req->path_info; char *dst = full_path+docroot_len; char *part = ptr; int part_size = 0; struct stat st; if (wsgi_req->path_info_len == 0) return 0; if (ptr[0] == '/') part_size++; for(i=0;ipath_info_len;i++) { if (ptr[i] == '/') { memcpy(dst, part, part_size-1); *(dst+part_size-1) = 0; if (stat(full_path, &st)) { return -1; } // not a directory, stop walking if (!S_ISDIR(st.st_mode)) { if (i < (wsgi_req->path_info_len)-1) { *path_info = ptr + i; } return 0; } // check for buffer overflow !!! *(dst+part_size-1) = '/'; *(dst+part_size) = 0; dst += part_size ; part_size = 0; part = ptr + i + 1; } part_size++; } if (part < wsgi_req->path_info+wsgi_req->path_info_len) { memcpy(dst, part, part_size-1); *(dst+part_size-1) = 0; if (stat(full_path, &st)) { return -1; } } return 0; } int uwsgi_php_request(struct wsgi_request *wsgi_req) { char real_filename[PATH_MAX+1]; char *path_info = NULL; size_t real_filename_len = 0; struct stat php_stat; char *filename = NULL; int force_empty_script_name = 0; zend_file_handle file_handle; SG(server_context) = (void *) wsgi_req; if (uwsgi_parse_vars(wsgi_req)) { return -1; } char *orig_path_info = wsgi_req->path_info; uint16_t orig_path_info_len = wsgi_req->path_info_len; if (uphp.docroot) { wsgi_req->document_root = uphp.docroot; } // fallback to cwd else if (!wsgi_req->document_root_len) { wsgi_req->document_root = uwsgi.cwd; } else { // explode DOCUMENT_ROOT (both for security and sanity checks) // this memory will be cleared on request end char *sanitized_docroot = ecalloc(1, PATH_MAX+1); if (!uwsgi_expand_path(wsgi_req->document_root, wsgi_req->document_root_len, sanitized_docroot)) { efree(sanitized_docroot); return -1; } wsgi_req->document_root = sanitized_docroot; } // fix document_root_len wsgi_req->document_root_len = strlen(wsgi_req->document_root); if (uphp.app) { #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) struct uwsgi_regexp_list *bypass = uphp.app_bypass; while (bypass) { #ifdef UWSGI_PCRE2 if (uwsgi_regexp_match(bypass->pattern, wsgi_req->uri, wsgi_req->uri_len) >= 0) { #else if (uwsgi_regexp_match(bypass->pattern, bypass->pattern_extra, wsgi_req->uri, wsgi_req->uri_len) >= 0) { #endif goto oldstyle; } bypass = bypass->next; } #endif strcpy(real_filename, uphp.app); real_filename_len = strlen(real_filename); if (wsgi_req->path_info_len == 1 && wsgi_req->path_info[0] == '/') { goto appready; } if (uphp.app_qs) { size_t app_qs_len = strlen(uphp.app_qs); size_t qs_len = wsgi_req->path_info_len + app_qs_len; if (wsgi_req->query_string_len > 0) { qs_len += 1 + wsgi_req->query_string_len; } char *qs = ecalloc(1, qs_len+1); memcpy(qs, uphp.app_qs, app_qs_len); memcpy(qs+app_qs_len, wsgi_req->path_info, wsgi_req->path_info_len); if (wsgi_req->query_string_len > 0) { char *ptr = qs+app_qs_len+wsgi_req->path_info_len; *ptr = '&'; memcpy(ptr+1, wsgi_req->query_string, wsgi_req->query_string_len); } wsgi_req->query_string = qs; wsgi_req->query_string_len = qs_len; } appready: wsgi_req->path_info = ""; wsgi_req->path_info_len = 0; force_empty_script_name = 1; goto secure2; } #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) oldstyle: #endif filename = uwsgi_concat4n(wsgi_req->document_root, wsgi_req->document_root_len, "/", 1, wsgi_req->path_info, wsgi_req->path_info_len, "", 0); activate_user_config(filename, wsgi_req->document_root, wsgi_req->document_root_len); if (uwsgi_php_walk(wsgi_req, filename, wsgi_req->document_root, wsgi_req->document_root_len, &path_info)) { free(filename); if (uphp.fallback || uphp.fallback2) { if (uphp.fallback) { filename = uwsgi_str(uphp.fallback); } else { filename = uwsgi_concat2n(wsgi_req->document_root, strlen(wsgi_req->document_root), uphp.fallback2, strlen(uphp.fallback2)); wsgi_req->script_name = uphp.fallback2; wsgi_req->script_name_len = strlen(uphp.fallback2); } if (uphp.fallback_qs) { size_t fqs_len = strlen(uphp.fallback_qs); size_t new_qs_len = orig_path_info_len + fqs_len + 1 + wsgi_req->query_string_len; char *new_qs = ecalloc(1, new_qs_len + 1); memcpy(new_qs, uphp.fallback_qs, fqs_len); new_qs[fqs_len] = '='; memcpy(new_qs + fqs_len + 1, orig_path_info, orig_path_info_len); if (wsgi_req->query_string_len) { new_qs[fqs_len + 1 + orig_path_info_len] = '&'; memcpy(new_qs + fqs_len + 2 + orig_path_info_len, wsgi_req->query_string, wsgi_req->query_string_len); } wsgi_req->query_string = new_qs; wsgi_req->query_string_len = new_qs_len; } } else { uwsgi_404(wsgi_req); return -1; } } if (path_info) { wsgi_req->path_info = path_info; wsgi_req->path_info_len = orig_path_info_len - (path_info - orig_path_info); } else { wsgi_req->path_info = ""; wsgi_req->path_info_len = 0; } if (!realpath(filename, real_filename)) { free(filename); uwsgi_404(wsgi_req); return -1; } free(filename); real_filename_len = strlen(real_filename); // first check for valid doc roots if (uphp.allowed_docroot) { struct uwsgi_string_list *usl = uphp.allowed_docroot; while(usl) { if (!uwsgi_starts_with(real_filename, real_filename_len, usl->value, usl->len)) { goto secure; } usl = usl->next; } uwsgi_403(wsgi_req); uwsgi_log("PHP security error: %s is not under an allowed docroot\n", real_filename); return -1; } // then for default docroot (if any) else if (uphp.docroot) { if (!uwsgi_starts_with(real_filename, real_filename_len, uphp.docroot, uphp.docroot_len)) { goto secure; } uwsgi_403(wsgi_req); uwsgi_log("PHP security error: %s is not under the default docroot\n", real_filename); return -1; } secure: if (stat(real_filename, &php_stat)) { uwsgi_404(wsgi_req); return UWSGI_OK; } if (S_ISDIR(php_stat.st_mode)) { // add / to directories if (orig_path_info_len == 0 || (orig_path_info_len > 0 && orig_path_info[orig_path_info_len-1] != '/')) { wsgi_req->path_info = orig_path_info; wsgi_req->path_info_len = orig_path_info_len; uwsgi_redirect_to_slash(wsgi_req); return UWSGI_OK; } struct uwsgi_string_list *upi = uphp.index; real_filename[real_filename_len] = '/'; real_filename_len++; int found = 0; while(upi) { if (real_filename_len + upi->len + 1 < PATH_MAX) { // add + 1 to ensure null byte memcpy(real_filename+real_filename_len, upi->value, upi->len + 1); if (!access(real_filename, R_OK)) { found = 1; break; } } upi = upi->next; } if (!found) { uwsgi_404(wsgi_req); return UWSGI_OK; } real_filename_len = strlen(real_filename); } if (uphp.allowed_ext) { struct uwsgi_string_list *usl = uphp.allowed_ext; while(usl) { if (real_filename_len >= usl->len) { if (!uwsgi_strncmp(real_filename+(real_filename_len-usl->len), usl->len, usl->value, usl->len)) { goto secure2; } } usl = usl->next; } uwsgi_403(wsgi_req); uwsgi_log("PHP security error: %s does not end with an allowed extension\n", real_filename); return -1; } secure2: wsgi_req->file = real_filename; wsgi_req->file_len = strlen(wsgi_req->file); if (uphp.allowed_scripts) { struct uwsgi_string_list *usl = uphp.allowed_scripts; while(usl) { if (!uwsgi_strncmp(wsgi_req->file, wsgi_req->file_len, usl->value, usl->len)) { goto secure3; } usl = usl->next; } uwsgi_403(wsgi_req); uwsgi_log("PHP security error: %s is not an allowed script\n", real_filename); return -1; } secure3: if (force_empty_script_name) { wsgi_req->script_name = ""; wsgi_req->script_name_len = 0; } else if (!uphp.fallback2) { wsgi_req->script_name = orig_path_info; if (path_info) { wsgi_req->script_name_len = path_info - orig_path_info; } else { wsgi_req->script_name_len = orig_path_info_len; } } #ifdef UWSGI_DEBUG uwsgi_log("php filename = %s script_name = %.*s (%d) document_root = %.*s (%d)\n", real_filename, wsgi_req->script_name_len, wsgi_req->script_name, wsgi_req->script_name_len, wsgi_req->document_root_len, wsgi_req->document_root, wsgi_req->document_root_len); #endif // now check for allowed paths and extensions SG(request_info).request_uri = estrndup(wsgi_req->uri, wsgi_req->uri_len); SG(request_info).request_method = estrndup(wsgi_req->method, wsgi_req->method_len); SG(request_info).proto_num = 1001; SG(request_info).query_string = estrndup(wsgi_req->query_string, wsgi_req->query_string_len); SG(request_info).content_length = wsgi_req->post_cl; SG(request_info).content_type = estrndup(wsgi_req->content_type, wsgi_req->content_type_len); // reinitialize it at every request !!! SG(sapi_headers).http_response_code = 200; SG(request_info).path_translated = wsgi_req->file; #if PHP_VERSION_ID >= 80100 zend_string *handle_filename = zend_string_init(real_filename, real_filename_len, 0); #else const char *handle_filename = real_filename; #endif memset(&file_handle, 0, sizeof(zend_file_handle)); file_handle.type = ZEND_HANDLE_FILENAME; file_handle.filename = handle_filename; if (php_request_startup() == FAILURE) { uwsgi_500(wsgi_req); return -1; } struct uwsgi_string_list *usl=NULL; uwsgi_foreach(usl, uphp.exec_before) { if (zend_eval_string_ex(usl->value, NULL, "uWSGI php exec before", 1) == FAILURE) goto end; } php_execute_script(&file_handle); uwsgi_foreach(usl, uphp.exec_after) { if (zend_eval_string_ex(usl->value, NULL, "uWSGI php exec after", 1) == FAILURE) goto end; } end: php_request_shutdown(NULL); return 0; } void uwsgi_php_after_request(struct wsgi_request *wsgi_req) { log_request(wsgi_req); } SAPI_API struct uwsgi_plugin php_plugin = { .name = "php", .modifier1 = 14, .init = uwsgi_php_init, .request = uwsgi_php_request, .after_request = uwsgi_php_after_request, .options = uwsgi_php_options, }; uwsgi-2.0.29/plugins/php/session.c000066400000000000000000000017461477626554400170750ustar00rootroot00000000000000#include "common.h" PS_OPEN_FUNC(uwsgi) { PS_SET_MOD_DATA((char *)save_path); return SUCCESS; } PS_CLOSE_FUNC(uwsgi) { return SUCCESS; } PS_READ_FUNC(uwsgi) { char *cache = PS_GET_MOD_DATA(); uint64_t valsize = 0; char *value = uwsgi_cache_magic_get(key->val, key->len , &valsize, NULL, cache); if (!value) { *val = STR_EMPTY_ALLOC(); return SUCCESS; } *val = zend_string_init(value, valsize, 0); return SUCCESS; } PS_WRITE_FUNC(uwsgi) { char *cache = PS_GET_MOD_DATA(); if (val->len == 0) return SUCCESS; if (!uwsgi_cache_magic_set(key->val, key->len, val->val, val->len, 0, UWSGI_CACHE_FLAG_UPDATE, cache)) { return SUCCESS; } return FAILURE; } PS_DESTROY_FUNC(uwsgi) { char *cache = PS_GET_MOD_DATA(); if (!uwsgi_cache_magic_exists(key->val, key->len, cache)) return SUCCESS; if (!uwsgi_cache_magic_del(key->val, key->len, cache)) { return SUCCESS; } return FAILURE; } PS_GC_FUNC(uwsgi) { return SUCCESS; } ps_module ps_mod_uwsgi = { PS_MOD(uwsgi) }; uwsgi-2.0.29/plugins/php/uwsgiplugin.py000066400000000000000000000017321477626554400201700ustar00rootroot00000000000000import os NAME='php' ld_run_path = None PHPPATH = 'php-config' phpdir = os.environ.get('UWSGICONFIG_PHPDIR') if phpdir: ld_run_path = "%s/lib" % phpdir PHPPATH = "%s/bin/php-config" % phpdir PHPPATH = os.environ.get('UWSGICONFIG_PHPPATH', PHPPATH) php_version = os.popen(PHPPATH + ' --version').read().rstrip().split('.')[0] CFLAGS = [os.popen(PHPPATH + ' --includes').read().rstrip(), '-Wno-sign-compare'] LDFLAGS = os.popen(PHPPATH + ' --ldflags').read().rstrip().split() if ld_run_path: LDFLAGS.append('-L%s' % ld_run_path) os.environ['LD_RUN_PATH'] = ld_run_path # PHP8 and above does not add the version to the library # name if int(php_version) < 8: LIBS = [os.popen(PHPPATH + ' --libs').read().rstrip(), '-lphp' + php_version] else: LIBS = [os.popen(PHPPATH + ' --libs').read().rstrip(), '-lphp'] phplibdir = os.environ.get('UWSGICONFIG_PHPLIBDIR') if phplibdir: LIBS.append('-Wl,-rpath,%s' % phplibdir) GCC_LIST = ['php_plugin', 'session'] uwsgi-2.0.29/plugins/ping/000077500000000000000000000000001477626554400154045ustar00rootroot00000000000000uwsgi-2.0.29/plugins/ping/ping_plugin.c000066400000000000000000000036641477626554400200740ustar00rootroot00000000000000#include "../../uwsgi.h" extern struct uwsgi_server uwsgi; struct uwsgi_ping { char *ping; int ping_timeout; } uping; struct uwsgi_option uwsgi_ping_options[] = { {"ping", required_argument, 0, "ping specified uwsgi host", uwsgi_opt_set_str, &uping.ping, UWSGI_OPT_NO_INITIAL | UWSGI_OPT_NO_SERVER}, {"ping-timeout", required_argument, 0, "set ping timeout", uwsgi_opt_set_int, &uping.ping_timeout, 0}, { 0, 0, 0, 0, 0, 0, 0 } }; static void ping() { struct uwsgi_header uh; char *buf = NULL; // use a 3 secs timeout by default if (!uping.ping_timeout) uping.ping_timeout = 3; uwsgi_log("PING uwsgi host %s (timeout: %d)\n", uping.ping, uping.ping_timeout); int fd = uwsgi_connect(uping.ping, uping.ping_timeout, 0); if (fd < 0) { exit(1); } uh.modifier1 = UWSGI_MODIFIER_PING; uh.pktsize = 0; uh.modifier2 = 0; if (write(fd, &uh, 4) != 4) { uwsgi_error("write()"); exit(2); } int ret = uwsgi_read_response(fd, &uh, uping.ping_timeout, &buf); if (ret < 0) { exit(1); } else { if (uh.pktsize > 0) { uwsgi_log("[WARNING] node %s message: %.*s\n", uping.ping, uh.pktsize, buf); exit(2); } else { exit(0); } } } int ping_init() { if (uping.ping) { ping(); //never here } return 1; } /* uwsgi PING|100 */ int uwsgi_request_ping(struct wsgi_request *wsgi_req) { char len; uwsgi_log( "PING\n"); wsgi_req->uh->modifier2 = 1; wsgi_req->uh->pktsize = 0; wsgi_req->do_not_account = 1; len = strlen(uwsgi.shared->warning_message); if (len > 0) { // TODO: check endianess ? wsgi_req->uh->pktsize = len; } if (uwsgi_response_write_body_do(wsgi_req, (char *) wsgi_req->uh, 4)) { return -1; } if (len > 0) { if (uwsgi_response_write_body_do(wsgi_req, uwsgi.shared->warning_message, len)) { return -1; } } return UWSGI_OK; } struct uwsgi_plugin ping_plugin = { .name = "ping", .modifier1 = 100, .options = uwsgi_ping_options, .request = uwsgi_request_ping, .init = ping_init, }; uwsgi-2.0.29/plugins/ping/uwsgiplugin.py000066400000000000000000000001121477626554400203250ustar00rootroot00000000000000NAME='ping' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['ping_plugin'] uwsgi-2.0.29/plugins/psgi/000077500000000000000000000000001477626554400154115ustar00rootroot00000000000000uwsgi-2.0.29/plugins/psgi/psgi.h000066400000000000000000000042111477626554400165220ustar00rootroot00000000000000#undef __USE_GNU #include #ifdef __APPLE__ #define HAS_BOOL 1 #endif #include #include #include "XSUB.h" #define uwsgi_pl_check_write_errors if (wsgi_req->write_errors > 0 && uwsgi.write_errors_exception_only) {\ croak("error writing to client");\ }\ else if (wsgi_req->write_errors > uwsgi.write_errors_tolerance)\ struct uwsgi_perl { // path of the statically loaded main app char *psgi; // locallib path char *locallib; // perl argv for initialization char *embedding[3]; // check for Devel::StackTrace int no_die_catch; int stacktrace_available; char *argv_items; struct uwsgi_string_list *argv_item; // this is a pointer to the main list of interpreters (required for signals, rpc....); PerlInterpreter **main; // a lock for dynamic apps pthread_mutex_t lock_loader; // this fields must be heavy protected in threaded modes int tmp_current_i; HV **tmp_streaming_stash; HV **tmp_input_stash; HV **tmp_error_stash; CV **tmp_psgix_logger; CV **tmp_stream_responder; SV *postfork; SV *atexit; int loaded; struct uwsgi_string_list *exec; struct uwsgi_string_list *exec_post_fork; int auto_reload; time_t last_auto_reload; struct uwsgi_string_list *auto_reload_ignore; HV *auto_reload_hash; int enable_psgix_io; char *shell; int shell_oneshot; CV *spooler; int no_plack; }; void init_perl_embedded_module(void); void uwsgi_psgi_app(void); int psgi_response(struct wsgi_request *, AV*); #define psgi_xs(func) newXS("uwsgi::" #func, XS_##func, "uwsgi") #define psgi_check_args(x) if (items < x) Perl_croak(aTHX_ "Usage: uwsgi::%s takes %d arguments", __FUNCTION__ + 3, x) SV *uwsgi_perl_obj_call(SV *, char *); int uwsgi_perl_obj_can(SV *, char *, size_t); int uwsgi_perl_obj_isa(SV *, char *); int init_psgi_app(struct wsgi_request *, char *, uint16_t, PerlInterpreter **); PerlInterpreter *uwsgi_perl_new_interpreter(void); int uwsgi_perl_mule(char *); void uwsgi_perl_run_hook(SV *); void uwsgi_perl_exec(char *); void uwsgi_perl_check_auto_reload(void); void uwsgi_psgi_preinit_apps(void); extern struct uwsgi_perl uperl; uwsgi-2.0.29/plugins/psgi/psgi_loader.c000066400000000000000000000407041477626554400200520ustar00rootroot00000000000000#include "psgi.h" extern struct uwsgi_server uwsgi; extern struct uwsgi_plugin psgi_plugin; XS(XS_input_seek) { dXSARGS; struct wsgi_request *wsgi_req = current_wsgi_req(); psgi_check_args(2); uwsgi_request_body_seek(wsgi_req, SvIV(ST(1))); XSRETURN(0); } XS(XS_error) { dXSARGS; struct wsgi_request *wsgi_req = current_wsgi_req(); struct uwsgi_app *wi = &uwsgi_apps[wsgi_req->app_id]; psgi_check_args(0); if (uwsgi.threads > 1) { ST(0) = sv_bless(newRV_noinc(newSV(0)), ((HV **)wi->error)[wsgi_req->async_id]); } else { ST(0) = sv_bless(newRV_noinc(newSV(0)), ((HV **)wi->error)[0]); } sv_2mortal(ST(0)); XSRETURN(1); } XS(XS_input) { dXSARGS; struct wsgi_request *wsgi_req = current_wsgi_req(); struct uwsgi_app *wi = &uwsgi_apps[wsgi_req->app_id]; psgi_check_args(0); if (uwsgi.threads > 1) { ST(0) = sv_bless(newRV_noinc(newSV(0)), ((HV **)wi->input)[wsgi_req->async_id]); } else { ST(0) = sv_bless(newRV_noinc(newSV(0)), ((HV **)wi->input)[0]); } sv_2mortal(ST(0)); XSRETURN(1); } XS(XS_psgix_logger) { dXSARGS; psgi_check_args(1); HV *hv_args = (HV *) (SvRV(ST(0))); if (!hv_exists(hv_args, "level", 5) || !hv_exists(hv_args, "message", 7)) { Perl_croak(aTHX_ "psgix.logger requires both level and message items"); } char *level = SvPV_nolen(*(hv_fetch(hv_args, "level", 5, 0))); char *message = SvPV_nolen(*(hv_fetch(hv_args, "message", 7, 0))); uwsgi_log("[uwsgi-perl %s] %s\n", level, message); XSRETURN(0); } XS(XS_stream) { dXSARGS; struct wsgi_request *wsgi_req = current_wsgi_req(); struct uwsgi_app *wi = &uwsgi_apps[wsgi_req->app_id]; psgi_check_args(1); AV *response = (AV* ) SvREFCNT_inc(SvRV(ST(0))) ; if (av_len(response) == 2) { while (psgi_response(wsgi_req, response) != UWSGI_OK); } else if (av_len(response) == 1) { while (psgi_response(wsgi_req, response) != UWSGI_OK); SvREFCNT_dec(response); if (uwsgi.threads > 1) { ST(0) = sv_bless(newRV_noinc(newSV(0)), ((HV **)wi->stream)[wsgi_req->async_id]); } else { ST(0) = sv_bless(newRV_noinc(newSV(0)), ((HV **)wi->stream)[0]); } sv_2mortal(ST(0)); XSRETURN(1); } else { uwsgi_log("invalid PSGI response: array size %d\n", av_len(response)); } SvREFCNT_dec(response); XSRETURN(0); } XS(XS_input_read) { dXSARGS; struct wsgi_request *wsgi_req = current_wsgi_req(); psgi_check_args(3); SV *read_buf = ST(1); unsigned long arg_len = SvIV(ST(2)); long offset = 0; if (items > 3) { offset = (long) SvIV(ST(3)); } ssize_t rlen = 0; char *buf = uwsgi_request_body_read(wsgi_req, arg_len, &rlen); if (buf) { if (rlen > 0 && offset != 0) { STRLEN orig_len; // get data from original string char *orig = SvPV(read_buf, orig_len); size_t new_size = orig_len; // still valid ? if (offset > 0) { // if the new string is bigger than the old one, allocate a bigger chunk if ((size_t) rlen + offset > orig_len) { new_size = rlen + offset; } // if offset is bigger than orig_len, pad with "\0", so we use (slower) calloc char *new_buf = uwsgi_calloc(new_size); // put back older value memcpy(new_buf, orig, orig_len); // put the new value memcpy(new_buf + offset, buf, rlen); sv_setpvn(read_buf, new_buf, new_size); // free the new value free(new_buf); } // negative (a little bit more complex) else { long orig_offset = 0; // first of all get the new orig_len; offset = labs(offset); if (offset > (long) orig_len) { new_size = offset; orig_offset = offset - orig_len; offset = 0; } else { offset = orig_len - offset; } if ((size_t) rlen + offset > new_size) { new_size = rlen + offset; } char *new_buf = uwsgi_calloc(new_size); // put back older value memcpy(new_buf + orig_offset, orig, orig_len); // put the new value memcpy(new_buf + offset, buf, rlen); sv_setpvn(read_buf, new_buf, new_size); // free the new value free(new_buf); } } else { sv_setpvn(read_buf, buf, rlen); } goto ret; } // error ? if (rlen < 0) { croak("error during read(%lu) on psgi.input", arg_len); goto ret; } croak("timeout during read(%lu) on psgi.input", arg_len); ret: XSRETURN_IV(rlen); } XS(XS_streaming_close) { dXSARGS; psgi_check_args(0); XSRETURN(0); } XS(XS_streaming_write) { dXSARGS; struct wsgi_request *wsgi_req = current_wsgi_req(); STRLEN blen; char *body; psgi_check_args(2); body = SvPV(ST(1), blen); uwsgi_response_write_body_do(wsgi_req, body, blen); uwsgi_pl_check_write_errors { croak("error while streaming PSGI response"); } XSRETURN(0); } XS(XS_error_print) { dXSARGS; STRLEN blen; char *body; psgi_check_args(1); if (items > 1) { body = SvPV(ST(1), blen); uwsgi_log("%.*s", (int) blen, body); } XSRETURN(0); } /* automatically generated */ EXTERN_C void xs_init (pTHX); EXTERN_C void boot_DynaLoader (pTHX_ CV* cv); EXTERN_C void xs_init(pTHX) { char *file = __FILE__; dXSUB_SYS; HV *stash; /* DynaLoader is a special case */ newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file); if (!uperl.tmp_input_stash) goto nonworker; newXS("uwsgi::input::new", XS_input, "uwsgi::input"); newXS("uwsgi::input::read", XS_input_read, "uwsgi::input"); newXS("uwsgi::input::seek", XS_input_seek, "uwsgi::input"); uperl.tmp_input_stash[uperl.tmp_current_i] = gv_stashpv("uwsgi::input", 0); newXS("uwsgi::error::new", XS_error, "uwsgi::error"); newXS("uwsgi::error::print", XS_error_print, "uwsgi::print"); uperl.tmp_error_stash[uperl.tmp_current_i] = gv_stashpv("uwsgi::error", 0); uperl.tmp_psgix_logger[uperl.tmp_current_i] = newXS("uwsgi::psgix_logger", XS_psgix_logger, "uwsgi"); uperl.tmp_stream_responder[uperl.tmp_current_i] = newXS("uwsgi::stream", XS_stream, "uwsgi"); newXS("uwsgi::streaming::write", XS_streaming_write, "uwsgi::streaming"); newXS("uwsgi::streaming::close", XS_streaming_close, "uwsgi::streaming"); uperl.tmp_streaming_stash[uperl.tmp_current_i] = gv_stashpv("uwsgi::streaming", 0); nonworker: stash = gv_stashpv("uwsgi", 1); newCONSTSUB(stash, "VERSION", newSVpv(UWSGI_VERSION, 0)); newCONSTSUB(stash, "SPOOL_OK", newSViv(-2)); newCONSTSUB(stash, "SPOOL_RETRY", newSViv(-1)); newCONSTSUB(stash, "SPOOL_IGNORE", newSViv(0)); HV *_opts = newHV(); int i; for (i = 0; i < uwsgi.exported_opts_cnt; i++) { if (hv_exists(_opts, uwsgi.exported_opts[i]->key, strlen(uwsgi.exported_opts[i]->key))) { SV **value = hv_fetch(_opts, uwsgi.exported_opts[i]->key, strlen(uwsgi.exported_opts[i]->key), 0); // last resort !!! if (!value) { uwsgi_log("[perl] WARNING !!! unable to build uwsgi::opt hash !!!\n"); goto end; } if (SvROK(*value) && SvTYPE(SvRV(*value)) == SVt_PVAV) { if (uwsgi.exported_opts[i]->value == NULL) { av_push((AV *)SvRV(*value), newSViv(1)); } else { av_push((AV *)SvRV(*value), newSVpv(uwsgi.exported_opts[i]->value, 0)); } } else { AV *_opt_a = newAV(); av_push(_opt_a, SvREFCNT_inc(*value)); if (uwsgi.exported_opts[i]->value == NULL) { av_push(_opt_a, newSViv(1)); } else { av_push(_opt_a, newSVpv(uwsgi.exported_opts[i]->value, 0)); } (void ) hv_store(_opts, uwsgi.exported_opts[i]->key, strlen(uwsgi.exported_opts[i]->key), newRV_inc((SV *) _opt_a), 0); } } else { if (uwsgi.exported_opts[i]->value == NULL) { (void )hv_store(_opts, uwsgi.exported_opts[i]->key, strlen(uwsgi.exported_opts[i]->key), newSViv(1), 0); } else { (void)hv_store(_opts, uwsgi.exported_opts[i]->key, strlen(uwsgi.exported_opts[i]->key), newSVpv(uwsgi.exported_opts[i]->value, 0), 0); } } } newCONSTSUB(stash, "opt", newRV_inc((SV *) _opts)); end: init_perl_embedded_module(); } /* end of automagically generated part */ PerlInterpreter *uwsgi_perl_new_interpreter(void) { PerlInterpreter *pi = perl_alloc(); if (!pi) { uwsgi_log("unable to allocate perl interpreter\n"); return NULL; } PERL_SET_CONTEXT(pi); PL_perl_destruct_level = 2; PL_origalen = 1; perl_construct(pi); // over-engeneering PL_origalen = 1; return pi; } static void uwsgi_perl_free_stashes(void) { free(uperl.tmp_streaming_stash); free(uperl.tmp_input_stash); free(uperl.tmp_error_stash); free(uperl.tmp_stream_responder); free(uperl.tmp_psgix_logger); } int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, PerlInterpreter **interpreters) { int i; SV **callables; time_t now = uwsgi_now(); char *app_name = uwsgi_concat2n(app, app_len, "", 0); if (uwsgi_file_exists(app_name)) { // prepare for $0 (if the file is local) uperl.embedding[1] = app_name; } // the first (default) app, should always be loaded in the main interpreter if (interpreters == NULL) { if (uwsgi_apps_cnt) { interpreters = uwsgi_calloc(sizeof(PerlInterpreter *) * uwsgi.threads); interpreters[0] = uwsgi_perl_new_interpreter(); if (!interpreters[0]) { uwsgi_log("unable to create new perl interpreter\n"); free(interpreters); goto clear2; } } else { interpreters = uperl.main; } } if (!interpreters) goto clear2; callables = uwsgi_calloc(sizeof(SV *) * uwsgi.threads); uperl.tmp_streaming_stash = uwsgi_calloc(sizeof(HV *) * uwsgi.threads); uperl.tmp_input_stash = uwsgi_calloc(sizeof(HV *) * uwsgi.threads); uperl.tmp_error_stash = uwsgi_calloc(sizeof(HV *) * uwsgi.threads); uperl.tmp_stream_responder = uwsgi_calloc(sizeof(CV *) * uwsgi.threads); uperl.tmp_psgix_logger = uwsgi_calloc(sizeof(CV *) * uwsgi.threads); for(i=0;i 0 && interpreters != uperl.main) { interpreters[i] = uwsgi_perl_new_interpreter(); if (!interpreters[i]) { uwsgi_log("unable to create new perl interpreter\n"); // what to do here ? i hope no-one will use threads with dynamic apps...but clear the whole stuff... free(callables); uwsgi_perl_free_stashes(); while(i>=0) { perl_destruct(interpreters[i]); perl_free(interpreters[i]); goto clear2; } } } PERL_SET_CONTEXT(interpreters[i]); uperl.tmp_current_i = i; // We need to initialize the interpreter to execute // our xs_init hook, but we're *not* calling it with // uperl.embedding as an argument so we won't execute // BEGIN blocks in app_name twice. { char *perl_e_arg = uwsgi_concat2("#line 0 ", app_name); char *perl_init_arg[] = { "", "-e", perl_e_arg }; if (perl_parse(interpreters[i], xs_init, 3, perl_init_arg, NULL)) { // what to do here ? i hope no-one will use threads with dynamic apps... but clear the whole stuff... free(callables); free(perl_e_arg); uwsgi_perl_free_stashes(); goto clear; } else { free(perl_e_arg); } } if (uperl.locallib) { uwsgi_log("using %s as local::lib directory\n", uperl.locallib); char *local_lib_use = uwsgi_concat3("use local::lib qw(", uperl.locallib, ");"); perl_eval_pv(local_lib_use, 1); free(local_lib_use); } perl_eval_pv("use IO::Handle;", 1); perl_eval_pv("use IO::File;", 1); perl_eval_pv("use IO::Socket;", 1); perl_eval_pv("use Scalar::Util;", 1); if (uperl.argv_items || uperl.argv_item) { AV *uperl_argv = GvAV(PL_argvgv); if (uperl.argv_items) { char *argv_list = uwsgi_str(uperl.argv_items); char *p, *ctx = NULL; uwsgi_foreach_token(argv_list, " ", p, ctx) { av_push(uperl_argv, newSVpv(p, 0)); } } struct uwsgi_string_list *usl = uperl.argv_item; while(usl) { av_push(uperl_argv, newSVpv(usl->value, usl->len)); usl = usl->next; } } SV *dollar_zero = get_sv("0", GV_ADD); sv_setsv(dollar_zero, newSVpv(app, app_len)); SV *has_plack = NULL; if (!uperl.no_plack) { has_plack = perl_eval_pv("use Plack::Util;", 0); } if (!has_plack || SvTRUE(ERRSV)) { if (!uperl.no_plack) { uwsgi_log("Plack::Util is not installed, using \"do\" instead of \"load_psgi\"\n"); } perl_eval_pv("use File::Spec;", 1); char *code = uwsgi_concat3("my $app = do File::Spec->rel2abs('", app_name, "'); if ( !$app && ( my $error = $@ || $! )) { die $error; }; $app"); callables[i] = perl_eval_pv(code, 0); free(code); } else { char *code = uwsgi_concat3("Plack::Util::load_psgi '", app_name , "';"); callables[i] = perl_eval_pv(code, 0); free(code); } if (!callables[i] || SvTYPE(callables[i]) == SVt_NULL || SvTRUE(ERRSV)) { if (SvTRUE(ERRSV)) { uwsgi_log("%s", SvPV_nolen(ERRSV)); } uwsgi_log("unable to find PSGI function entry point.\n"); // what to do here ? i hope no-one will use threads with dynamic apps... free(callables); uwsgi_perl_free_stashes(); goto clear; } if (!uperl.no_die_catch) { perl_eval_pv("use Devel::StackTrace; $SIG{__DIE__} = sub { print Devel::StackTrace->new()->as_string() };", 0); if(SvTRUE(ERRSV)) { uwsgi_log("%s", SvPV_nolen(ERRSV)); } } PERL_SET_CONTEXT(interpreters[0]); } if (uwsgi_apps_cnt >= uwsgi.max_apps) { uwsgi_log("ERROR: you cannot load more than %d apps in a worker\n", uwsgi.max_apps); goto clear; } int id = uwsgi_apps_cnt; struct uwsgi_app *wi = NULL; if (wsgi_req) { // we need a copy of app_id wi = uwsgi_add_app(id, psgi_plugin.modifier1, uwsgi_concat2n(wsgi_req->appid, wsgi_req->appid_len, "", 0), wsgi_req->appid_len, interpreters, callables); } else { wi = uwsgi_add_app(id, psgi_plugin.modifier1, "", 0, interpreters, callables); } wi->started_at = now; wi->startup_time = uwsgi_now() - now; uwsgi_log("PSGI app %d (%s) loaded in %d seconds at %p (interpreter %p)\n", id, app_name, (int) wi->startup_time, callables[0], interpreters[0]); free(app_name); // copy global data to app-specific areas wi->stream = uperl.tmp_streaming_stash; wi->input = uperl.tmp_input_stash; wi->error = uperl.tmp_error_stash; wi->responder0 = uperl.tmp_stream_responder; wi->responder1 = uperl.tmp_psgix_logger; uwsgi_emulate_cow_for_apps(id); // restore context if required if (interpreters != uperl.main) { PERL_SET_CONTEXT(uperl.main[0]); } uperl.loaded = 1; return id; clear: if (interpreters != uperl.main) { for(i=0;ivalue, usl->len)); uwsgi_perl_exec(usl->value); } } } void uwsgi_psgi_app() { if (uperl.psgi) { //load app in the main interpreter list init_psgi_app(NULL, uperl.psgi, strlen(uperl.psgi), uperl.main); } // create a perl environment (if needed) else if (!uperl.exec && uperl.shell) { PERL_SET_CONTEXT(uperl.main[0]); perl_parse(uperl.main[0], xs_init, 3, uperl.embedding, NULL); } } int uwsgi_perl_mule(char *opt) { if (uwsgi_endswith(opt, ".pl")) { PERL_SET_CONTEXT(uperl.main[0]); uperl.embedding[1] = opt; if (perl_parse(uperl.main[0], xs_init, 3, uperl.embedding, NULL)) { return 0; } perl_run(uperl.main[0]); return 1; } return 0; } void uwsgi_perl_exec(char *filename) { size_t size = 0; char *buf = uwsgi_open_and_read(filename, &size, 1, NULL); perl_eval_pv(buf, 1); free(buf); } uwsgi-2.0.29/plugins/psgi/psgi_plugin.c000066400000000000000000000645151477626554400201100ustar00rootroot00000000000000#include "psgi.h" extern char **environ; extern struct uwsgi_server uwsgi; struct uwsgi_perl uperl; struct uwsgi_plugin psgi_plugin; static void uwsgi_opt_plshell(char *opt, char *value, void *foobar) { uwsgi.honour_stdin = 1; if (value) { uperl.shell = value; } else { uperl.shell = ""; } if (!strcmp("plshell-oneshot", opt)) { uperl.shell_oneshot = 1; } } struct uwsgi_option uwsgi_perl_options[] = { {"psgi", required_argument, 0, "load a psgi app", uwsgi_opt_set_str, &uperl.psgi, 0}, {"psgi-enable-psgix-io", no_argument, 0, "enable psgix.io support", uwsgi_opt_true, &uperl.enable_psgix_io, 0}, {"perl-no-die-catch", no_argument, 0, "do not catch $SIG{__DIE__}", uwsgi_opt_true, &uperl.no_die_catch, 0}, {"perl-local-lib", required_argument, 0, "set perl locallib path", uwsgi_opt_set_str, &uperl.locallib, 0}, #ifdef PERL_VERSION_STRING {"perl-version", no_argument, 0, "print perl version", uwsgi_opt_print, PERL_VERSION_STRING, UWSGI_OPT_IMMEDIATE}, #endif {"perl-args", required_argument, 0, "add items (space separated) to @ARGV", uwsgi_opt_set_str, &uperl.argv_items, 0}, {"perl-arg", required_argument, 0, "add an item to @ARGV", uwsgi_opt_add_string_list, &uperl.argv_item, 0}, {"perl-exec", required_argument, 0, "exec the specified perl file before fork()", uwsgi_opt_add_string_list, &uperl.exec, 0}, {"perl-exec-post-fork", required_argument, 0, "exec the specified perl file after fork()", uwsgi_opt_add_string_list, &uperl.exec_post_fork, 0}, {"perl-auto-reload", required_argument, 0, "enable perl auto-reloader with the specified frequency", uwsgi_opt_set_int, &uperl.auto_reload, UWSGI_OPT_MASTER}, {"perl-auto-reload-ignore", required_argument, 0, "ignore the specified files when auto-reload is enabled", uwsgi_opt_add_string_list, &uperl.auto_reload_ignore, UWSGI_OPT_MASTER}, {"plshell", optional_argument, 0, "run a perl interactive shell", uwsgi_opt_plshell, NULL, 0}, {"plshell-oneshot", no_argument, 0, "run a perl interactive shell (one shot)", uwsgi_opt_plshell, NULL, 0}, {"perl-no-plack", no_argument, 0, "force the use of do instead of Plack::Util::load_psgi", uwsgi_opt_true, &uperl.no_plack, 0}, {0, 0, 0, 0, 0, 0, 0}, }; int uwsgi_perl_check_mtime(time_t now, HV *list, SV *key) { // insert item with the current time if (!hv_exists_ent(list, key, 0)) { // useless if... if (hv_store_ent(list, key, newSViv(now), 0)) return 0; } else { // compare mtime struct stat st; if (stat(SvPV_nolen(key), &st)) return 0; HE *mtime = hv_fetch_ent(list, key, 0, 0); if (!mtime) return 0; if (st.st_mtime > SvIV(HeVAL(mtime))) { uwsgi_log_verbose("[perl-auto-reloader] %s has been modified !!!\n", SvPV_nolen(key)); kill(uwsgi.workers[0].pid, SIGHUP); return 1; } } return 0; } void uwsgi_perl_check_auto_reload() { time_t now = uwsgi_now(); HE *he; if (!uperl.auto_reload_hash) { uperl.auto_reload_hash = newHV(); // useless return value if (!SvREFCNT_inc(uperl.auto_reload_hash)) return; } GV *gv_inc = gv_fetchpv("INC", TRUE, SVt_PV); if (!gv_inc) return; HV *inc = GvHV(gv_inc); hv_iterinit(inc); while((he = hv_iternext(inc))) { SV *filename = hv_iterval(inc, he); struct uwsgi_string_list *usl; int found = 0; uwsgi_foreach(usl, uperl.auto_reload_ignore) { if (!strcmp(usl->value, SvPV_nolen(filename))) { found = 1; break; } } if (found) continue; if (uwsgi_perl_check_mtime(now, uperl.auto_reload_hash, filename)) return; } } SV *uwsgi_perl_obj_new(char *class, size_t class_len) { SV *newobj; dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv( class, class_len))); PUTBACK; call_method( "new", G_SCALAR); SPAGAIN; newobj = SvREFCNT_inc(POPs); PUTBACK; FREETMPS; LEAVE; return newobj; } SV *uwsgi_perl_obj_new_from_fd(char *class, size_t class_len, int fd) { SV *newobj; dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv( class, class_len))); XPUSHs(sv_2mortal(newSViv( fd ))); XPUSHs(sv_2mortal(newSVpv( "w", 1 ))); PUTBACK; call_method( "new_from_fd", G_SCALAR); SPAGAIN; newobj = SvREFCNT_inc(POPs); PUTBACK; FREETMPS; LEAVE; return newobj; } SV *uwsgi_perl_call_stream(SV *func) { SV *ret = NULL; struct wsgi_request *wsgi_req = current_wsgi_req(); struct uwsgi_app *wi = &uwsgi_apps[wsgi_req->app_id]; dSP; ENTER; SAVETMPS; PUSHMARK(SP); if (uwsgi.threads > 1) { XPUSHs( sv_2mortal(newRV((SV*) ((SV **)wi->responder0)[wsgi_req->async_id]))); } else { XPUSHs( sv_2mortal(newRV((SV*) ((SV **)wi->responder0)[0]))); } PUTBACK; call_sv( func, G_SCALAR | G_EVAL); SPAGAIN; if(SvTRUE(ERRSV)) { uwsgi_log("[uwsgi-perl error] %s", SvPV_nolen(ERRSV)); } else { ret = SvREFCNT_inc(POPs); } PUTBACK; FREETMPS; LEAVE; return ret; } int uwsgi_perl_obj_can(SV *obj, char *method, size_t len) { int ret; dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(obj); XPUSHs(sv_2mortal(newSVpv(method, len))); PUTBACK; call_method( "can", G_SCALAR|G_EVAL); SPAGAIN; if(SvTRUE(ERRSV)) { uwsgi_log("%s", SvPV_nolen(ERRSV)); } ret = SvROK(POPs); PUTBACK; FREETMPS; LEAVE; return ret; } int uwsgi_perl_obj_isa(SV *obj, char *class) { int ret = 0; dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(obj); PUTBACK; call_pv( "Scalar::Util::reftype", G_SCALAR|G_EVAL); SPAGAIN; char *reftype = POPp; if (reftype && !strcmp(reftype, class)) { ret = 1; } PUTBACK; FREETMPS; LEAVE; return ret; } SV *uwsgi_perl_obj_call(SV *obj, char *method) { SV *ret = NULL; dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(obj); PUTBACK; call_method( method, G_SCALAR | G_EVAL); SPAGAIN; if(SvTRUE(ERRSV)) { uwsgi_log("%s", SvPV_nolen(ERRSV)); } else { ret = SvREFCNT_inc(POPs); } PUTBACK; FREETMPS; LEAVE; return ret; } AV *psgi_call(struct wsgi_request *wsgi_req, SV *psgi_func, SV *env) { AV *ret = NULL; dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(env); PUTBACK; call_sv(psgi_func, G_SCALAR | G_EVAL); SPAGAIN; if(SvTRUE(ERRSV)) { uwsgi_500(wsgi_req); uwsgi_log("[uwsgi-perl error] %s", SvPV_nolen(ERRSV)); } else { SV *r = POPs; if (SvROK(r)) { ret = (AV *) SvREFCNT_inc(SvRV(r)); } } PUTBACK; FREETMPS; LEAVE; return (AV *)ret; } SV *build_psgi_env(struct wsgi_request *wsgi_req) { int i; struct uwsgi_app *wi = &uwsgi_apps[wsgi_req->app_id]; HV *env = newHV(); // fill perl hash for(i=0;ivar_cnt;i++) { if (wsgi_req->hvec[i+1].iov_len > 0) { // check for multiline header if (hv_exists(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len)) { SV **already_avalable_header = hv_fetch(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, 0); STRLEN hlen; char *old_value = SvPV(*already_avalable_header, hlen ); char *multiline_header = uwsgi_concat3n(old_value, hlen, ", ", 2, wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len); if (!hv_store(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, newSVpv(multiline_header, hlen+wsgi_req->hvec[i+1].iov_len+2), 0)) { free(multiline_header); goto clear;} free(multiline_header); } else { if (!hv_store(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, newSVpv(wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len), 0)) goto clear; } } else { if (!hv_store(env, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, newSVpv("", 0), 0)) goto clear; } //uwsgi_log("%.*s = %.*s\n", wsgi_req->hvec[i].iov_len, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i+1].iov_len, wsgi_req->hvec[i+1].iov_base); i++; } // psgi.version AV *av = newAV(); av_store( av, 0, newSViv(1)); av_store( av, 1, newSViv(1)); if (!hv_store(env, "psgi.version", 12, newRV_noinc((SV *)av ), 0)) goto clear; if (uwsgi.numproc > 1) { if (!hv_store(env, "psgi.multiprocess", 17, newSViv(1), 0)) goto clear; } else { if (!hv_store(env, "psgi.multiprocess", 17, newSViv(0), 0)) goto clear; } if (uwsgi.threads > 1) { if (!hv_store(env, "psgi.multithread", 16, newSViv(1), 0)) goto clear; } else { if (!hv_store(env, "psgi.multithread", 16, newSViv(0), 0)) goto clear; } if (!hv_store(env, "psgi.run_once", 13, newSViv(0), 0)) goto clear; if (uwsgi.async > 1) { if (!hv_store(env, "psgi.nonblocking", 16, newSViv(1), 0)) goto clear; } else { if (!hv_store(env, "psgi.nonblocking", 16, newSViv(0), 0)) goto clear; } if (!hv_store(env, "psgi.streaming", 14, newSViv(1), 0)) goto clear; SV *us; // psgi.url_scheme, honour HTTPS var or UWSGI_SCHEME if (wsgi_req->scheme_len > 0) { us = newSVpv(wsgi_req->scheme, wsgi_req->scheme_len); } else if (wsgi_req->https_len > 0) { if (!strncasecmp(wsgi_req->https, "on", 2) || wsgi_req->https[0] == '1') { us = newSVpv("https", 5); } else { us = newSVpv("http", 4); } } else { us = newSVpv("http", 4); } if (!hv_store(env, "psgi.url_scheme", 15, us, 0)) goto clear; SV *pi = uwsgi_perl_obj_new("uwsgi::input", 12); if (!hv_store(env, "psgi.input", 10, pi, 0)) goto clear; if (!hv_store(env, "psgix.input.buffered", 20, newSViv(uwsgi.post_buffering), 0)) goto clear; if (uwsgi.threads > 1) { if (!hv_store(env, "psgix.logger", 12,newRV((SV*) ((SV **)wi->responder1)[wsgi_req->async_id]) ,0)) goto clear; } else { if (!hv_store(env, "psgix.logger", 12,newRV((SV*) ((SV **)wi->responder1)[0]) ,0)) goto clear; } if (uwsgi.master_process) { if (!hv_store(env, "psgix.harakiri", 14, newSViv(1), 0)) goto clear; } if (!hv_store(env, "psgix.cleanup", 13, newSViv(1), 0)) goto clear; // cleanup handlers array av = newAV(); if (!hv_store(env, "psgix.cleanup.handlers", 22, newRV_noinc((SV *)av ), 0)) goto clear; // this call requires a bunch of syscalls, so it hurts performance if (uperl.enable_psgix_io) { SV *io = uwsgi_perl_obj_new_from_fd("IO::Socket", 10, wsgi_req->fd); if (!hv_store(env, "psgix.io", 8, io, 0)) goto clear; } SV *pe = uwsgi_perl_obj_new("uwsgi::error", 12); if (!hv_store(env, "psgi.errors", 11, pe, 0)) goto clear; (void) hv_delete(env, "HTTP_CONTENT_LENGTH", 19, G_DISCARD); (void) hv_delete(env, "HTTP_CONTENT_TYPE", 17, G_DISCARD); return newRV_noinc((SV *)env); clear: SvREFCNT_dec((SV *)env); return NULL; } int uwsgi_perl_init(){ int argc; int i; uperl.embedding[0] = ""; uperl.embedding[1] = "-e"; uperl.embedding[2] = "0"; #ifndef USE_ITHREADS if (uwsgi.threads > 1) { uwsgi_log("your Perl environment does not support threads\n"); exit(1); } #endif if (setenv("PLACK_ENV", "uwsgi", 0)) { uwsgi_error("setenv()"); } if (setenv("PLACK_SERVER", "uwsgi", 0)) { uwsgi_error("setenv()"); } argc = 3; PERL_SYS_INIT3(&argc, (char ***) &uperl.embedding, &environ); uperl.main = uwsgi_calloc(sizeof(PerlInterpreter *) * uwsgi.threads); uperl.main[0] = uwsgi_perl_new_interpreter(); if (!uperl.main[0]) { return -1; } for(i=1;iasync_status == UWSGI_AGAIN) { return psgi_response(wsgi_req, wsgi_req->async_placeholder); } /* Standard PSGI request */ if (!wsgi_req->uh->pktsize) { uwsgi_log("Empty PSGI request. skip.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } if (wsgi_req->dynamic) { if (uwsgi.threads > 1) { pthread_mutex_lock(&uperl.lock_loader); } } wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, psgi_plugin.modifier1); // if it is -1, try to load a dynamic app if (wsgi_req->app_id == -1) { if (wsgi_req->dynamic) { if (wsgi_req->script_len > 0) { wsgi_req->app_id = init_psgi_app(wsgi_req, wsgi_req->script, wsgi_req->script_len, NULL); } else if (wsgi_req->file_len > 0) { wsgi_req->app_id = init_psgi_app(wsgi_req, wsgi_req->file, wsgi_req->file_len, NULL); } } if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) { if (uwsgi_apps[uwsgi.default_app].modifier1 == psgi_plugin.modifier1) { wsgi_req->app_id = uwsgi.default_app; } } } if (wsgi_req->dynamic) { if (uwsgi.threads > 1) { pthread_mutex_unlock(&uperl.lock_loader); } } if (wsgi_req->app_id == -1) { uwsgi_500(wsgi_req); uwsgi_log("--- unable to find perl application ---\n"); // nothing to clear/free return UWSGI_OK; } struct uwsgi_app *wi = &uwsgi_apps[wsgi_req->app_id]; wi->requests++; if (uwsgi.threads < 2) { if (((PerlInterpreter **)wi->interpreter)[0] != uperl.main[0]) { PERL_SET_CONTEXT(((PerlInterpreter **)wi->interpreter)[0]); } } else { if (((PerlInterpreter **)wi->interpreter)[wsgi_req->async_id] != uperl.main[wsgi_req->async_id]) { PERL_SET_CONTEXT(((PerlInterpreter **)wi->interpreter)[wsgi_req->async_id]); } } ENTER; SAVETMPS; wsgi_req->async_environ = build_psgi_env(wsgi_req); if (!wsgi_req->async_environ) goto clear; if (uwsgi.threads > 1) { wsgi_req->async_result = psgi_call(wsgi_req, ((SV **)wi->callable)[wsgi_req->async_id], wsgi_req->async_environ); } else { wsgi_req->async_result = psgi_call(wsgi_req, ((SV **)wi->callable)[0], wsgi_req->async_environ); } if (!wsgi_req->async_result) goto clear; if (SvTYPE((AV *)wsgi_req->async_result) == SVt_PVCV) { SV *stream_result = uwsgi_perl_call_stream((SV*)wsgi_req->async_result); if (!stream_result) { uwsgi_500(wsgi_req); } else { SvREFCNT_dec(stream_result); } goto clear2; } while (psgi_response(wsgi_req, wsgi_req->async_result) != UWSGI_OK) { if (uwsgi.async > 1) { FREETMPS; LEAVE; return UWSGI_AGAIN; } } clear2: // clear response SvREFCNT_dec(wsgi_req->async_result); clear: FREETMPS; LEAVE; // restore main interpreter if needed if (uwsgi.threads > 1) { if (((PerlInterpreter **)wi->interpreter)[wsgi_req->async_id] != uperl.main[wsgi_req->async_id]) { PERL_SET_CONTEXT(uperl.main[wsgi_req->async_id]); } } else { if (((PerlInterpreter **)wi->interpreter)[0] != uperl.main[0]) { PERL_SET_CONTEXT(uperl.main[0]); } } return UWSGI_OK; } static void psgi_call_cleanup_hook(SV *hook, SV *env) { dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(env); PUTBACK; call_sv(hook, G_DISCARD); if(SvTRUE(ERRSV)) { uwsgi_log("[uwsgi-perl error] %s", SvPV_nolen(ERRSV)); } FREETMPS; LEAVE; } void uwsgi_perl_after_request(struct wsgi_request *wsgi_req) { log_request(wsgi_req); // We may be called after an early exit in XS_coroae_accept_request, // before the environ is set up. if (!wsgi_req->async_environ) return; // we need to restore the context in case of multiple interpreters struct uwsgi_app *wi = &uwsgi_apps[wsgi_req->app_id]; if (uwsgi.threads < 2) { if (((PerlInterpreter **)wi->interpreter)[0] != uperl.main[0]) { PERL_SET_CONTEXT(((PerlInterpreter **)wi->interpreter)[0]); } } else { if (((PerlInterpreter **)wi->interpreter)[wsgi_req->async_id] != uperl.main[wsgi_req->async_id]) { PERL_SET_CONTEXT(((PerlInterpreter **)wi->interpreter)[wsgi_req->async_id]); } } // dereference %env SV *env = SvRV((SV *) wsgi_req->async_environ); // check for cleanup handlers if (hv_exists((HV *)env, "psgix.cleanup.handlers", 22)) { SV **cleanup_handlers = hv_fetch((HV *)env, "psgix.cleanup.handlers", 22, 0); if (SvROK(*cleanup_handlers)) { if (SvTYPE(SvRV(*cleanup_handlers)) == SVt_PVAV) { I32 n = av_len((AV *)SvRV(*cleanup_handlers)); I32 i; for(i=0;i<=n;i++) { SV **hook = av_fetch((AV *)SvRV(*cleanup_handlers), i, 0); psgi_call_cleanup_hook(*hook, (SV *) wsgi_req->async_environ); } } } } // check for psgix.harakiri if (hv_exists((HV *)env, "psgix.harakiri.commit", 21)) { SV **harakiri = hv_fetch((HV *)env, "psgix.harakiri.commit", 21, 0); if (SvTRUE(*harakiri)) wsgi_req->async_plagued = 1; } // Free the $env hash SvREFCNT_dec(wsgi_req->async_environ); // async plagued could be defined in other areas... if (wsgi_req->async_plagued) { uwsgi_log("*** psgix.harakiri.commit requested ***\n"); // Before we call exit(0) we'll run the // uwsgi_perl_atexit() hook which'll properly tear // down the interpreter. // mark the request as ended (otherwise the atexit hook will be skipped) uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 0; goodbye_cruel_world(); } // now we can check for changed files if (uperl.auto_reload) { time_t now = uwsgi_now(); if (now - uperl.last_auto_reload > uperl.auto_reload) { uwsgi_perl_check_auto_reload(); } } // restore main interpreter if needed if (uwsgi.threads > 1) { if (((PerlInterpreter **)wi->interpreter)[wsgi_req->async_id] != uperl.main[wsgi_req->async_id]) { PERL_SET_CONTEXT(uperl.main[wsgi_req->async_id]); } } else { if (((PerlInterpreter **)wi->interpreter)[0] != uperl.main[0]) { PERL_SET_CONTEXT(uperl.main[0]); } } } int uwsgi_perl_magic(char *mountpoint, char *lazy) { if (!strcmp(lazy+strlen(lazy)-5, ".psgi")) { uperl.psgi = lazy; return 1; } else if (!strcmp(lazy+strlen(lazy)-3, ".pl")) { uperl.psgi = lazy; return 1; } return 0; } // taken from Torsten Foertsch AfterFork.xs void uwsgi_perl_post_fork() { GV *tmpgv = gv_fetchpv("$", TRUE, SVt_PV); if (tmpgv) { SvREADONLY_off(GvSV(tmpgv)); sv_setiv(GvSV(tmpgv), (IV)getpid()); SvREADONLY_on(GvSV(tmpgv)); } struct uwsgi_string_list *usl; uwsgi_foreach(usl, uperl.exec_post_fork) { SV *dollar_zero = get_sv("0", GV_ADD); sv_setsv(dollar_zero, newSVpv(usl->value, usl->len)); uwsgi_perl_exec(usl->value); } if (uperl.postfork) { uwsgi_perl_run_hook(uperl.postfork); } } int uwsgi_perl_mount_app(char *mountpoint, char *app) { if (uwsgi_endswith(app, ".pl") || uwsgi_endswith(app, ".psgi")) { uwsgi.wsgi_req->appid = mountpoint; uwsgi.wsgi_req->appid_len = strlen(mountpoint); return init_psgi_app(uwsgi.wsgi_req, app, strlen(app), NULL); } return -1; } void uwsgi_perl_init_thread(int core_id) { #ifdef USE_ITHREADS PERL_SET_CONTEXT(uperl.main[core_id]); #endif } void uwsgi_perl_pthread_prepare(void) { pthread_mutex_lock(&uperl.lock_loader); } void uwsgi_perl_pthread_parent(void) { pthread_mutex_unlock(&uperl.lock_loader); } void uwsgi_perl_pthread_child(void) { pthread_mutex_init(&uperl.lock_loader, NULL); } void uwsgi_perl_enable_threads(void) { #ifdef USE_ITHREADS pthread_mutex_init(&uperl.lock_loader, NULL); pthread_atfork(uwsgi_perl_pthread_prepare, uwsgi_perl_pthread_parent, uwsgi_perl_pthread_child); #endif } static int uwsgi_perl_signal_handler(uint8_t sig, void *handler) { int ret = 0; dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs( sv_2mortal(newSViv(sig))); PUTBACK; call_sv( SvRV((SV*)handler), G_DISCARD); SPAGAIN; if(SvTRUE(ERRSV)) { uwsgi_log("[uwsgi-perl error] %s", SvPV_nolen(ERRSV)); ret = -1; } PUTBACK; FREETMPS; LEAVE; return ret; } void uwsgi_perl_run_hook(SV *hook) { dSP; ENTER; SAVETMPS; PUSHMARK(SP); PUTBACK; call_sv( SvRV(hook), G_DISCARD); SPAGAIN; if(SvTRUE(ERRSV)) { uwsgi_log("[uwsgi-perl error] %s", SvPV_nolen(ERRSV)); return; } PUTBACK; FREETMPS; LEAVE; } static void uwsgi_perl_atexit() { int i; if (uwsgi.mywid == 0) goto realstuff; // if hijacked do not run atexit hooks -- TODO: explain why // not. if (uwsgi.workers[uwsgi.mywid].hijacked) goto destroyperl; // if busy do not run atexit hooks (as this part could be called in a signal handler // while a subroutine is running) if (uwsgi_worker_is_busy(uwsgi.mywid)) return; realstuff: if (uperl.atexit) { uwsgi_perl_run_hook(uperl.atexit); } // For the reasons explained in // https://github.com/unbit/uwsgi/issues/1384, tearing down // the interpreter can be very expensive. if (uwsgi.skip_atexit_teardown) return; destroyperl: // We must free our perl context(s) so any DESTROY hooks // etc. will run. for(i=0;i 0) { *buffer = uwsgi_malloc(rlen); memcpy(*buffer, value, rlen); ret = rlen; } } PUTBACK; FREETMPS; LEAVE; return ret; } static void uwsgi_perl_hijack(void) { if (uperl.shell_oneshot && uwsgi.workers[uwsgi.mywid].hijacked_count > 0) { uwsgi.workers[uwsgi.mywid].hijacked = 0; return; } if (uperl.shell && uwsgi.mywid == 1) { uwsgi.workers[uwsgi.mywid].hijacked = 1; uwsgi.workers[uwsgi.mywid].hijacked_count++; // re-map stdin to stdout and stderr if we are logging to a file if (uwsgi.logfile) { if (dup2(0, 1) < 0) { uwsgi_error("dup2()"); } if (dup2(0, 2) < 0) { uwsgi_error("dup2()"); } } if (uperl.shell[0] != 0) { perl_eval_pv(uperl.shell, 0); } else { perl_eval_pv("use Devel::REPL;my $repl = Devel::REPL->new;$repl->run;", 0); } if (uperl.shell_oneshot) { exit(UWSGI_DE_HIJACKED_CODE); } exit(0); } } static void uwsgi_perl_add_item(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) { HV *spool_dict = (HV*) data; (void)hv_store(spool_dict, key, keylen, newSVpv(val, vallen), 0); } static int uwsgi_perl_spooler(char *filename, char *buf, uint16_t len, char *body, size_t body_len) { int ret = -1; if (!uperl.spooler) return 0; dSP; ENTER; SAVETMPS; PUSHMARK(SP); HV *spool_dict = newHV(); if (uwsgi_hooked_parse(buf, len, uwsgi_perl_add_item, (void *) spool_dict)) { return 0; } (void) hv_store(spool_dict, "spooler_task_name", 18, newSVpv(filename, 0), 0); if (body && body_len > 0) { (void) hv_store(spool_dict, "body", 4, newSVpv(body, body_len), 0); } XPUSHs( sv_2mortal((SV*)newRV_noinc((SV*)spool_dict)) ); PUTBACK; call_sv( SvRV((SV*)uperl.spooler), G_SCALAR|G_EVAL); SPAGAIN; if(SvTRUE(ERRSV)) { uwsgi_log("[uwsgi-spooler-perl error] %s", SvPV_nolen(ERRSV)); ret = -1; } else { ret = POPi; } PUTBACK; FREETMPS; LEAVE; return ret; } struct uwsgi_plugin psgi_plugin = { .name = "psgi", .modifier1 = 5, .init = uwsgi_perl_init, .options = uwsgi_perl_options, .preinit_apps = uwsgi_psgi_preinit_apps, .init_apps = uwsgi_psgi_app, .mount_app = uwsgi_perl_mount_app, .init_thread = uwsgi_perl_init_thread, .signal_handler = uwsgi_perl_signal_handler, .rpc = uwsgi_perl_rpc, .mule = uwsgi_perl_mule, .hijack_worker = uwsgi_perl_hijack, .post_fork = uwsgi_perl_post_fork, .request = uwsgi_perl_request, .after_request = uwsgi_perl_after_request, .enable_threads = uwsgi_perl_enable_threads, .atexit = uwsgi_perl_atexit, .magic = uwsgi_perl_magic, .spooler = uwsgi_perl_spooler, }; uwsgi-2.0.29/plugins/psgi/psgi_response.c000066400000000000000000000131131477626554400204340ustar00rootroot00000000000000#include "psgi.h" extern struct uwsgi_server uwsgi; int psgi_response(struct wsgi_request *wsgi_req, AV *response) { SV **status_code, **hitem ; AV *headers, *body =NULL; STRLEN hlen, hlen2; int i; char *chitem, *chitem2; SV **harakiri; if (wsgi_req->async_force_again) { wsgi_req->async_force_again = 0; wsgi_req->switches++; SV *chunk = uwsgi_perl_obj_call(wsgi_req->async_placeholder, "getline"); if (!chunk) { uwsgi_500(wsgi_req); return UWSGI_OK; } chitem = SvPV( chunk, hlen); if (hlen <= 0) { SvREFCNT_dec(chunk); if (wsgi_req->async_force_again) { return UWSGI_AGAIN; } SV *closed = uwsgi_perl_obj_call(wsgi_req->async_placeholder, "close"); if (closed) { SvREFCNT_dec(closed); } // check for psgix.harakiri harakiri = hv_fetch((HV*)SvRV( (SV*)wsgi_req->async_environ), "psgix.harakiri.commit", 21, 0); if (harakiri) { if (SvTRUE(*harakiri)) wsgi_req->async_plagued = 1; } SvREFCNT_dec(wsgi_req->async_result); return UWSGI_OK; } uwsgi_response_write_body_do(wsgi_req, chitem, hlen); uwsgi_pl_check_write_errors { SvREFCNT_dec(chunk); return UWSGI_OK; } SvREFCNT_dec(chunk); wsgi_req->async_force_again = 1; return UWSGI_AGAIN; } if (SvTYPE(response) != SVt_PVAV) { uwsgi_log("invalid PSGI response type\n"); return UWSGI_OK; } if (av_len(response) == -1) { // deliberately empty response wsgi_req->status = 101; // don't actually close socket, it must be closed by application itself wsgi_req->fd_closed = 1; return UWSGI_OK; } status_code = av_fetch(response, 0, 0); if (!status_code) { uwsgi_log("invalid PSGI status code\n"); return UWSGI_OK;} char *status_str = SvPV(*status_code, hlen); if (uwsgi_response_prepare_headers(wsgi_req, status_str, hlen)) return UWSGI_OK; hitem = av_fetch(response, 1, 0); if (!hitem || !SvRV(*hitem) || SvTYPE(SvRV(*hitem)) != SVt_PVAV) { uwsgi_log("invalid PSGI headers\n"); return UWSGI_OK;} headers = (AV *) SvRV(*hitem); if (!headers) { uwsgi_log("invalid PSGI headers\n"); return UWSGI_OK;} // generate headers int headers_len = (int) av_len(headers); for(i=0; i<=headers_len; i++) { hitem = av_fetch(headers,i,0); if (!*hitem) { uwsgi_log("invalid PSGI headers\n"); return UWSGI_OK; } chitem = SvPV(*hitem, hlen); if (i+1 > headers_len) { uwsgi_log("invalid PSGI headers\n"); return UWSGI_OK; } hitem = av_fetch(headers,i+1,0); if (!*hitem) { uwsgi_log("invalid PSGI headers\n"); return UWSGI_OK; } chitem2 = SvPV(*hitem, hlen2); if (uwsgi_response_add_header(wsgi_req, chitem, hlen, chitem2, hlen2)) return UWSGI_OK; i++; } hitem = av_fetch(response, 2, 0); if (!hitem) { return UWSGI_OK; } if (!SvRV(*hitem)) { uwsgi_log("invalid PSGI response body\n") ; return UWSGI_OK; } if (!SvROK(*hitem)) goto unsupported; if (SvTYPE(SvRV(*hitem)) == SVt_PVGV || SvTYPE(SvRV(*hitem)) == SVt_PVHV || SvTYPE(SvRV(*hitem)) == SVt_PVMG) { // check for fileno() method, IO class or GvIO if (uwsgi_perl_obj_can(*hitem, "fileno", 6) || uwsgi_perl_obj_isa(*hitem, "IO") || (uwsgi_perl_obj_isa(*hitem, "GLOB") && GvIO(SvRV(*hitem))) ) { SV *fn = uwsgi_perl_obj_call(*hitem, "fileno"); if (fn) { if (SvTYPE(fn) == SVt_IV && SvIV(fn) >= 0) { wsgi_req->sendfile_fd = SvIV(fn); SvREFCNT_dec(fn); uwsgi_response_sendfile_do(wsgi_req, wsgi_req->sendfile_fd, 0, 0); // no need to close here as perl GC will do the close() uwsgi_pl_check_write_errors { // noop } return UWSGI_OK; } SvREFCNT_dec(fn); } } // check for path method if (uwsgi_perl_obj_can(*hitem, "path", 4)) { SV *p = uwsgi_perl_obj_call(*hitem, "path"); int fd = open(SvPV_nolen(p), O_RDONLY); SvREFCNT_dec(p); // the following function will close fd uwsgi_response_sendfile_do(wsgi_req, fd, 0, 0); uwsgi_pl_check_write_errors { // noop } return UWSGI_OK; } for(;;) { wsgi_req->switches++; SV *chunk = uwsgi_perl_obj_call(*hitem, "getline"); if (!chunk) { uwsgi_500(wsgi_req); break; } chitem = SvPV( chunk, hlen); if (hlen <= 0) { SvREFCNT_dec(chunk); if (uwsgi.async > 1 && wsgi_req->async_force_again) { wsgi_req->async_placeholder = (SV *) *hitem; return UWSGI_AGAIN; } break; } uwsgi_response_write_body_do(wsgi_req, chitem, hlen); uwsgi_pl_check_write_errors { SvREFCNT_dec(chunk); break; } SvREFCNT_dec(chunk); if (uwsgi.async > 1) { wsgi_req->async_placeholder = (SV *) *hitem; wsgi_req->async_force_again = 1; return UWSGI_AGAIN; } } SV *closed = uwsgi_perl_obj_call(*hitem, "close"); if (closed) { SvREFCNT_dec(closed); } } else if (SvTYPE(SvRV(*hitem)) == SVt_PVAV) { body = (AV *) SvRV(*hitem); for(i=0; i<=av_len(body); i++) { hitem = av_fetch(body,i,0); chitem = SvPV(*hitem, hlen); uwsgi_response_write_body_do(wsgi_req, chitem, hlen); uwsgi_pl_check_write_errors { break; } } } else { unsupported: uwsgi_log("unsupported response body type: %d\n", SvTYPE(SvRV(*hitem))); } return UWSGI_OK; } uwsgi-2.0.29/plugins/psgi/uwsgi_plmodule.c000066400000000000000000000470221477626554400206210ustar00rootroot00000000000000#include "psgi.h" extern struct uwsgi_server uwsgi; extern struct uwsgi_plugin psgi_plugin; extern struct uwsgi_perl uperl; XS(XS_async_sleep) { dXSARGS; int timeout ; psgi_check_args(1); struct wsgi_request *wsgi_req = current_wsgi_req(); timeout = SvIV(ST(0)); if (timeout >= 0) { async_add_timeout(wsgi_req, timeout); } wsgi_req->async_force_again = 1; XSRETURN_UNDEF; } XS(XS_wait_fd_read) { dXSARGS; int fd, timeout = 0; psgi_check_args(1); struct wsgi_request *wsgi_req = current_wsgi_req(); fd = SvIV(ST(0)); if (items > 1) { timeout = SvIV(ST(1)); } if (async_add_fd_read(wsgi_req, fd, timeout)) { croak("unable to add fd %d to the event queue", fd); } wsgi_req->async_force_again = 1; XSRETURN_UNDEF; } XS(XS_wait_fd_write) { dXSARGS; int fd, timeout = 0; psgi_check_args(1); struct wsgi_request *wsgi_req = current_wsgi_req(); fd = SvIV(ST(0)); if (items > 1) { timeout = SvIV(ST(1)); } if (async_add_fd_write(wsgi_req, fd, timeout)) { croak("unable to add fd %d to the event queue", fd); } wsgi_req->async_force_again = 1; XSRETURN_UNDEF; } XS(XS_signal) { dXSARGS; psgi_check_args(1); uwsgi_signal_send(uwsgi.signal_socket, SvIV(ST(0))); XSRETURN_UNDEF; } XS(XS_set_user_harakiri) { dXSARGS; psgi_check_args(1); set_user_harakiri( SvIV(ST(0)) ); XSRETURN_UNDEF; } XS(XS_reload) { dXSARGS; psgi_check_args(0); if (kill(uwsgi.workers[0].pid, SIGHUP)) { uwsgi_error("kill()"); XSRETURN_NO; } XSRETURN_YES; } XS(XS_cache_set) { dXSARGS; char *key, *val; STRLEN keylen; STRLEN vallen; uint64_t expires = 0; char *cache = NULL; psgi_check_args(2); key = SvPV(ST(0), keylen); val = SvPV(ST(1), vallen); if (items > 2) { expires = SvIV(ST(2)); if (items > 3) { cache = SvPV_nolen(ST(3)); } } if (!uwsgi_cache_magic_set(key, (uint16_t) keylen, val, (uint64_t) vallen, expires, 0, cache)) { XSRETURN_YES; } XSRETURN_UNDEF; } XS(XS_cache_get) { dXSARGS; char *key; char *cache = NULL; STRLEN keylen; uint64_t vallen = 0; psgi_check_args(1); key = SvPV(ST(0), keylen); if (items > 1) { cache = SvPV_nolen(ST(1)); } char *value = uwsgi_cache_magic_get(key, (uint16_t) keylen, &vallen, NULL, cache); if (value) { ST(0) = newSVpv(value, vallen); free(value); sv_2mortal(ST(0)); XSRETURN(1); } XSRETURN_UNDEF; } XS(XS_cache_exists) { dXSARGS; char *key; char *cache = NULL; STRLEN keylen; psgi_check_args(1); key = SvPV(ST(0), keylen); if (items > 1) { cache = SvPV_nolen(ST(1)); } if (uwsgi_cache_magic_exists(key, (uint16_t) keylen, cache)) { XSRETURN_YES; } XSRETURN_UNDEF; } XS(XS_cache_del) { dXSARGS; char *key; char *cache = NULL; STRLEN keylen; psgi_check_args(1); key = SvPV(ST(0), keylen); if (items > 1) { cache = SvPV_nolen(ST(1)); } if (!uwsgi_cache_magic_del(key, (uint16_t) keylen, cache)) { XSRETURN_YES; } XSRETURN_UNDEF; } XS(XS_cache_clear) { dXSARGS; char *cache = NULL; psgi_check_args(1); cache = SvPV_nolen(ST(0)); if (!uwsgi_cache_magic_clear(cache)) { XSRETURN_YES; } XSRETURN_UNDEF; } XS(XS_register_signal) { dXSARGS; if (!uwsgi.master_process) { XSRETURN_NO; } psgi_check_args(3); uint8_t signum = SvIV(ST(0)); STRLEN kindlen; char *kind = SvPV(ST(1), kindlen); if (uwsgi_register_signal(signum, kind, (void *) newRV_inc(ST(2)), psgi_plugin.modifier1)) { XSRETURN_NO; } XSRETURN_YES; } XS(XS_spooler) { dXSARGS; psgi_check_args(1); uperl.spooler = (CV *) newRV_inc(ST(0)); XSRETURN_YES; } XS(XS_register_rpc) { dXSARGS; psgi_check_args(2); char *name = SvPV_nolen(ST(0)); if (uwsgi_register_rpc(name, &psgi_plugin, 0, (void *) newRV_inc(ST(1)))) { XSRETURN_NO; } XSRETURN_YES; } XS(XS_postfork) { dXSARGS; psgi_check_args(1); uperl.postfork = newRV_inc(ST(0)); XSRETURN_YES; } XS(XS_atexit) { dXSARGS; psgi_check_args(1); uperl.atexit = newRV_inc(ST(0)); XSRETURN_YES; } XS(XS_log) { dXSARGS; psgi_check_args(1); uwsgi_log("%s", SvPV_nolen(ST(0))); XSRETURN_UNDEF; } XS(XS_alarm) { dXSARGS; char *alarm; char *msg; STRLEN msg_len; psgi_check_args(2); alarm = SvPV_nolen(ST(0)); msg = SvPV(ST(1), msg_len); uwsgi_alarm_trigger(alarm, msg, msg_len); XSRETURN_UNDEF; } XS(XS_worker_id) { dXSARGS; psgi_check_args(0); ST(0) = newSViv(uwsgi.mywid); XSRETURN(1); } XS(XS_async_connect) { dXSARGS; psgi_check_args(1); ST(0) = newSViv(uwsgi_connect(SvPV_nolen(ST(0)), 0, 1)); XSRETURN(1); } XS(XS_ready_fd) { dXSARGS; psgi_check_args(0); struct wsgi_request *wsgi_req = current_wsgi_req(); ST(0) = newSViv(uwsgi_ready_fd(wsgi_req)); XSRETURN(1); } XS(XS_call) { dXSARGS; char *func; uint64_t size = 0; int i; char *argv[256]; uint16_t argvs[256]; STRLEN arg_len; psgi_check_args(1); func = SvPV_nolen(ST(0)); for(i=0;i<(items-1);i++) { argv[i] = SvPV(ST(i+1), arg_len); argvs[i] = arg_len; } // response must be always freed char *response = uwsgi_do_rpc(NULL, func, items-1, argv, argvs, &size); if (response) { ST(0) = newSVpv(response, size); sv_2mortal(ST(0)); free(response); XSRETURN(1); } XSRETURN_UNDEF; } XS(XS_rpc) { dXSARGS; char *node; char *func; uint64_t size = 0; int i; char *argv[256]; uint16_t argvs[256]; STRLEN arg_len; psgi_check_args(2); node = SvPV_nolen(ST(0)); func = SvPV_nolen(ST(1)); for(i=0;i<(items-2);i++) { argv[i] = SvPV(ST(i+2), arg_len); argvs[i] = arg_len; } // response must be always freed char *response = uwsgi_do_rpc(node, func, items-2, argv, argvs, &size); if (response) { ST(0) = newSVpv(response, size); sv_2mortal(ST(0)); free(response); XSRETURN(1); } XSRETURN_UNDEF; } XS(XS_suspend) { dXSARGS; psgi_check_args(0); struct wsgi_request *wsgi_req = current_wsgi_req(); wsgi_req->async_force_again = 0; if (uwsgi.schedule_to_main) uwsgi.schedule_to_main(wsgi_req); XSRETURN_UNDEF; } XS(XS_signal_wait) { dXSARGS; psgi_check_args(0); struct wsgi_request *wsgi_req = current_wsgi_req(); int received_signal = -1; wsgi_req->signal_received = -1; if (items > 0) { received_signal = uwsgi_signal_wait(SvIV(ST(0))); } else { received_signal = uwsgi_signal_wait(-1); } if (received_signal < 0) { XSRETURN_NO; } wsgi_req->signal_received = received_signal; XSRETURN_YES; } #ifdef UWSGI_SSL XS(XS_i_am_the_lord) { dXSARGS; psgi_check_args(1); if (uwsgi_legion_i_am_the_lord(SvPV_nolen(ST(0)))) { XSRETURN_YES; } XSRETURN_NO; } #endif XS(XS_connection_fd) { dXSARGS; psgi_check_args(0); struct wsgi_request *wsgi_req = current_wsgi_req(); ST(0) = newSViv(wsgi_req->fd); sv_2mortal(ST(0)); XSRETURN(1); } XS(XS_websocket_handshake) { dXSARGS; char *key = NULL; STRLEN key_len = 0; char *origin = NULL; STRLEN origin_len = 0; char *proto = NULL; STRLEN proto_len = 0; psgi_check_args(0); if (items > 0) { key = SvPV(ST(0), key_len); if (items > 1) { origin = SvPV(ST(1), origin_len); if (items > 2) { proto = SvPV(ST(2), proto_len); } } } struct wsgi_request *wsgi_req = current_wsgi_req(); if (uwsgi_websocket_handshake(wsgi_req, key, key_len, origin, origin_len, proto, proto_len)) { croak("unable to complete websocket handshake"); } XSRETURN_UNDEF; } XS(XS_websocket_send) { dXSARGS; char *message = NULL; STRLEN message_len = 0; psgi_check_args(1); message = SvPV(ST(0), message_len); struct wsgi_request *wsgi_req = current_wsgi_req(); if (uwsgi_websocket_send(wsgi_req, message, message_len)) { croak("unable to send websocket message"); } XSRETURN_UNDEF; } XS(XS_websocket_send_from_sharedarea) { dXSARGS; psgi_check_args(2); int id = SvIV(ST(0)); uint64_t pos = SvIV(ST(1)); uint64_t len = 0; if (items > 2) { len = SvIV(ST(2)); } struct wsgi_request *wsgi_req = current_wsgi_req(); if (uwsgi_websocket_send_from_sharedarea(wsgi_req, id, pos, len)) { croak("unable to send websocket message from sharedarea"); } XSRETURN_UNDEF; } XS(XS_websocket_send_binary) { dXSARGS; char *message = NULL; STRLEN message_len = 0; psgi_check_args(1); message = SvPV(ST(0), message_len); struct wsgi_request *wsgi_req = current_wsgi_req(); if (uwsgi_websocket_send_binary(wsgi_req, message, message_len)) { croak("unable to send websocket binary message"); } XSRETURN_UNDEF; } XS(XS_websocket_send_binary_from_sharedarea) { dXSARGS; psgi_check_args(2); int id = SvIV(ST(0)); uint64_t pos = SvIV(ST(1)); uint64_t len = 0; if (items > 2) { len = SvIV(ST(2)); } struct wsgi_request *wsgi_req = current_wsgi_req(); if (uwsgi_websocket_send_binary_from_sharedarea(wsgi_req, id, pos, len)) { croak("unable to send websocket binary message from sharedarea"); } XSRETURN_UNDEF; } XS(XS_websocket_recv) { dXSARGS; psgi_check_args(0); struct wsgi_request *wsgi_req = current_wsgi_req(); struct uwsgi_buffer *ub = uwsgi_websocket_recv(wsgi_req); if (!ub) { croak("unable to receive websocket message"); XSRETURN_UNDEF; } ST(0) = newSVpv(ub->buf, ub->pos); uwsgi_buffer_destroy(ub); sv_2mortal(ST(0)); XSRETURN(1); } XS(XS_websocket_recv_nb) { dXSARGS; psgi_check_args(0); struct wsgi_request *wsgi_req = current_wsgi_req(); struct uwsgi_buffer *ub = uwsgi_websocket_recv_nb(wsgi_req); if (!ub) { croak("unable to receive websocket message"); XSRETURN_UNDEF; } ST(0) = newSVpv(ub->buf, ub->pos); uwsgi_buffer_destroy(ub); sv_2mortal(ST(0)); XSRETURN(1); } XS(XS_add_timer) { dXSARGS; psgi_check_args(2); uint8_t uwsgi_signal = SvIV(ST(0)); int seconds = SvIV(ST(1)); if (uwsgi_add_timer(uwsgi_signal, seconds)) { croak("unable to register timer"); XSRETURN_UNDEF; } XSRETURN(1); } XS(XS_add_rb_timer) { dXSARGS; psgi_check_args(2); uint8_t uwsgi_signal = SvIV(ST(0)); int seconds = SvIV(ST(1)); int iterations = 0; if (items > 2) { iterations = SvIV(ST(2)); } if (uwsgi_signal_add_rb_timer(uwsgi_signal, seconds, iterations)) { croak("unable to register rb timer"); XSRETURN_UNDEF; } XSRETURN(1); } XS(XS_metric_inc) { dXSARGS; char *metric = NULL; STRLEN metric_len = 0; int64_t value = 1; psgi_check_args(1); metric = SvPV(ST(0), metric_len); if (items > 1) { value = (int64_t) SvIV(ST(1)); } if (uwsgi_metric_inc(metric, NULL, value)) { croak("unable to update metric"); XSRETURN_UNDEF; } XSRETURN_YES; } XS(XS_metric_dec) { dXSARGS; char *metric = NULL; STRLEN metric_len = 0; int64_t value = 1; psgi_check_args(1); metric = SvPV(ST(0), metric_len); if (items > 1) { value = (int64_t) SvIV(ST(1)); } if (uwsgi_metric_dec(metric, NULL, value)) { croak("unable to update metric"); XSRETURN_UNDEF; } XSRETURN_YES; } XS(XS_metric_mul) { dXSARGS; char *metric = NULL; STRLEN metric_len = 0; int64_t value = 1; psgi_check_args(1); metric = SvPV(ST(0), metric_len); if (items > 1) { value = (int64_t) SvIV(ST(1)); } if (uwsgi_metric_mul(metric, NULL, value)) { croak("unable to update metric"); XSRETURN_UNDEF; } XSRETURN_YES; } XS(XS_metric_div) { dXSARGS; char *metric = NULL; STRLEN metric_len = 0; int64_t value = 1; psgi_check_args(1); metric = SvPV(ST(0), metric_len); if (items > 1) { value = (int64_t) SvIV(ST(1)); } if (uwsgi_metric_div(metric, NULL, value)) { croak("unable to update metric"); XSRETURN_UNDEF; } XSRETURN_YES; } XS(XS_metric_set) { dXSARGS; char *metric = NULL; STRLEN metric_len = 0; int64_t value = 0; psgi_check_args(2); metric = SvPV(ST(0), metric_len); value = (int64_t) SvIV(ST(1)); if (uwsgi_metric_set(metric, NULL, value)) { croak("unable to update metric"); XSRETURN_UNDEF; } XSRETURN_YES; } XS(XS_metric_get) { dXSARGS; char *metric = NULL; STRLEN metric_len = 0; psgi_check_args(1); metric = SvPV(ST(0), metric_len); ST(0) = newSViv(uwsgi_metric_get(metric, NULL)); sv_2mortal(ST(0)); XSRETURN(1); } XS(XS_sharedarea_wait) { dXSARGS; int id; int freq = 0; int timeout = 0; psgi_check_args(1); id = SvIV(ST(0)); if (items > 1) { freq = SvIV(ST(1)); if (items > 2) { timeout = SvIV(ST(2)); } } if (uwsgi_sharedarea_wait(id, freq, timeout)) { croak("unable to wait for sharedarea %d", id); XSRETURN_UNDEF; } XSRETURN_YES; } XS(XS_sharedarea_read) { dXSARGS; int id; uint64_t pos; uint64_t len = 0; psgi_check_args(2); id = SvIV(ST(0)); pos = SvIV(ST(1)); if (items > 2) { len = SvIV(ST(2)); } else { struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, pos); if (!sa) { croak("unable to read from sharedarea %d", id); XSRETURN_UNDEF; } len = (sa->max_pos+1)-pos; } char *buf = uwsgi_malloc(len); int64_t rlen = uwsgi_sharedarea_read(id, pos, buf, len); if (rlen < 0) { free(buf); croak("unable to read from sharedarea %d", id); XSRETURN_UNDEF; } ST(0) = sv_newmortal(); sv_usepvn(ST(0), buf, rlen); XSRETURN(1); } XS(XS_sharedarea_readfast) { dXSARGS; int id; uint64_t pos; uint64_t len = 0; psgi_check_args(3); id = SvIV(ST(0)); pos = SvIV(ST(1)); char *buf = SvPV_nolen(ST(2)); if (items > 3) { len = SvIV(ST(3)); } if (uwsgi_sharedarea_read(id, pos, buf, len)) { croak("unable to (fast) read from sharedarea %d", id); XSRETURN_UNDEF; } XSRETURN_YES; } XS(XS_sharedarea_write) { dXSARGS; int id; uint64_t pos; STRLEN vallen; psgi_check_args(3); id = SvIV(ST(0)); pos = SvIV(ST(1)); char *value = SvPV(ST(2), vallen); if (uwsgi_sharedarea_write(id, pos, value, vallen)) { croak("unable to write to sharedarea %d", id); XSRETURN_UNDEF; } XSRETURN_YES; } XS(XS_chunked_read) { dXSARGS; int timeout = 0; size_t len = 0; psgi_check_args(0); if (items > 0) { timeout = SvIV(ST(0)); } struct wsgi_request *wsgi_req = current_wsgi_req(); char *chunk = uwsgi_chunked_read(wsgi_req, &len, timeout, 0); if (!chunk) { croak("unable to receive chunked part"); XSRETURN_UNDEF; } ST(0) = newSVpvn(chunk, len); sv_2mortal(ST(0)); XSRETURN(1); } XS(XS_chunked_read_nb) { dXSARGS; size_t len = 0; psgi_check_args(0); struct wsgi_request *wsgi_req = current_wsgi_req(); char *chunk = uwsgi_chunked_read(wsgi_req, &len, 0, 1); if (!chunk) { if (uwsgi_is_again()) XSRETURN_UNDEF; croak("unable to receive chunked part"); XSRETURN_UNDEF; } ST(0) = newSVpvn(chunk, len); sv_2mortal(ST(0)); XSRETURN(1); } XS(XS_spool) { dXSARGS; psgi_check_args(1); SV *arg = ST(0); HV *env = NULL; char *body = NULL; STRLEN body_len = 0; if (SvROK(arg)) { env = (HV *) SvRV(arg); } else { croak("spool argument must be a hashref"); XSRETURN_UNDEF; } if (SvTYPE(env) != SVt_PVHV) { croak("spool argument must be a hashref"); XSRETURN_UNDEF; } if (hv_exists(env, "body", 4)) { SV **body_sv = hv_fetch(env, "body", 4, 0); body = SvPV(*body_sv, body_len); (void)hv_delete(env, "body", 4, 0); } struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); HE *he; hv_iterinit(env); while((he = hv_iternext(env))) { I32 klen; STRLEN vlen; char *key = hv_iterkey(he, &klen); char *value = SvPV(hv_iterval(env, he), vlen); if (uwsgi_buffer_append_keyval(ub, key, klen, value, vlen)) { croak("unable to serialize hash to spool file"); uwsgi_buffer_destroy(ub); XSRETURN_UNDEF; } } char *filename = uwsgi_spool_request(NULL, ub->buf, ub->pos, body, body_len); uwsgi_buffer_destroy(ub); if (filename) { ST(0) = newSVpv(filename, strlen(filename)); free(filename); XSRETURN(1); } croak("unable to spool request"); XSRETURN_UNDEF; } XS(XS_add_var) { dXSARGS; psgi_check_args(2); struct wsgi_request *wsgi_req = current_wsgi_req(); STRLEN keylen; char *key = SvPV(ST(0), keylen); STRLEN vallen; char *val = SvPV(ST(1), vallen); if (!uwsgi_req_append(wsgi_req, key, keylen, val, vallen)) { croak("unable to add request var, check your buffer size"); XSRETURN_UNDEF; } XSRETURN_YES; } void init_perl_embedded_module() { psgi_xs(reload); psgi_xs(cache_get); psgi_xs(cache_exists); psgi_xs(cache_set); psgi_xs(cache_del); psgi_xs(cache_clear); psgi_xs(call); psgi_xs(rpc); psgi_xs(wait_fd_read); psgi_xs(wait_fd_write); psgi_xs(async_sleep); psgi_xs(ready_fd); psgi_xs(log); psgi_xs(async_connect); psgi_xs(suspend); psgi_xs(signal); psgi_xs(register_signal); psgi_xs(register_rpc); psgi_xs(signal_wait); #ifdef UWSGI_SSL psgi_xs(i_am_the_lord); #endif psgi_xs(connection_fd); psgi_xs(alarm); psgi_xs(websocket_handshake); psgi_xs(websocket_recv); psgi_xs(websocket_recv_nb); psgi_xs(websocket_send); psgi_xs(websocket_send_from_sharedarea); psgi_xs(websocket_send_binary); psgi_xs(websocket_send_binary_from_sharedarea); psgi_xs(postfork); psgi_xs(atexit); psgi_xs(add_timer); psgi_xs(add_rb_timer); psgi_xs(set_user_harakiri); psgi_xs(metric_inc); psgi_xs(metric_dec); psgi_xs(metric_mul); psgi_xs(metric_div); psgi_xs(metric_get); psgi_xs(metric_set); psgi_xs(chunked_read); psgi_xs(chunked_read_nb); psgi_xs(sharedarea_read); psgi_xs(sharedarea_readfast); psgi_xs(sharedarea_write); psgi_xs(sharedarea_wait); psgi_xs(spooler); psgi_xs(spool); psgi_xs(add_var); psgi_xs(worker_id); } uwsgi-2.0.29/plugins/psgi/uwsgiplugin.py000066400000000000000000000006641477626554400203460ustar00rootroot00000000000000import os,sys NAME='psgi' CFLAGS = os.popen('perl -MExtUtils::Embed -e ccopts').read().rstrip().split() LDFLAGS = os.popen('perl -MExtUtils::Embed -e ldopts').read().rstrip().split() LIBS = [] for lib in LDFLAGS: if lib.startswith('-l'): LIBS.append(lib) GCC_LIST = ['uwsgi_plmodule', 'psgi_loader', 'psgi_response', 'psgi_plugin'] for item in LDFLAGS: if item.endswith('DynaLoader.a'): GCC_LIST.append(item) uwsgi-2.0.29/plugins/pty/000077500000000000000000000000001477626554400152635ustar00rootroot00000000000000uwsgi-2.0.29/plugins/pty/pty.c000066400000000000000000000232371477626554400162520ustar00rootroot00000000000000#include #if defined(__linux__) || defined(__GNU_kFreeBSD__) || defined(__HURD__) #include #elif defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__) #include #elif defined(__FreeBSD__) || defined(__DragonFly__) #include #endif #if !defined(__FreeBSD__) && !defined(__DragonFly__) #include #endif extern struct uwsgi_server uwsgi; struct uwsgi_pty_client { int fd; struct uwsgi_pty_client *prev; struct uwsgi_pty_client *next; }; static struct uwsgi_pty { char *addr; char *remote; char *uremote; int queue; int server_fd; int master_fd; int slave_fd; int log; int original_log; int input; int original_input; int no_isig; char *command; pid_t command_pid; struct uwsgi_pty_client *head; struct uwsgi_pty_client *tail; } upty; static struct uwsgi_pty_client *uwsgi_pty_client_new(int fd) { struct uwsgi_pty_client *upc = uwsgi_calloc(sizeof(struct uwsgi_pty_client)); upc->fd = fd; if (upty.tail) { upc->prev = upty.tail; upty.tail->next = upc; } upty.tail = upc; if (!upty.head) upty.head = upc; return upc; } static void uwsgi_pty_client_remove(struct uwsgi_pty_client *upc) { struct uwsgi_pty_client *prev = upc->prev; struct uwsgi_pty_client *next = upc->next; if (prev) { prev->next = next; } if (next) { next->prev = prev; } if (upc == upty.head) { upty.head = next; } if (upc == upty.tail) { upty.tail = prev; } close(upc->fd); free(upc); } static struct uwsgi_option uwsgi_pty_options[] = { {"pty-socket", required_argument, 0, "bind the pty server on the specified address", uwsgi_opt_set_str, &upty.addr, 0}, {"pty-log", no_argument, 0, "send stdout/stderr to the log engine too", uwsgi_opt_true, &upty.log, 0}, {"pty-input", no_argument, 0, "read from original stdin in addition to pty", uwsgi_opt_true, &upty.input, 0}, {"pty-connect", required_argument, 0, "connect the current terminal to a pty server", uwsgi_opt_set_str, &upty.remote, UWSGI_OPT_NO_INITIAL}, {"pty-uconnect", required_argument, 0, "connect the current terminal to a pty server (using uwsgi protocol)", uwsgi_opt_set_str, &upty.uremote, UWSGI_OPT_NO_INITIAL}, {"pty-no-isig", no_argument, 0, "disable ISIG terminal attribute in client mode", uwsgi_opt_true, &upty.no_isig, 0}, {"pty-exec", required_argument, 0, "run the specified command soon after the pty thread is spawned", uwsgi_opt_set_str, &upty.command, 0}, {0, 0, 0, 0, 0, 0, 0}, }; void uwsgi_pty_setterm(int fd) { struct termios tio; tcgetattr(fd, &tio); tio.c_iflag |= IGNPAR; tio.c_iflag &= ~(ISTRIP | IMAXBEL | BRKINT | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF); #ifdef IUCLC tio.c_iflag &= ~IUCLC; #endif tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL); if (upty.no_isig) { tio.c_lflag &= ~(ISIG); } #ifdef IEXTEN tio.c_lflag &= ~IEXTEN; #endif tio.c_oflag &= ~OPOST; tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; #ifdef B38400 cfsetispeed(&tio, B38400); cfsetospeed(&tio, B38400); #endif tcsetattr(fd, TCSANOW, &tio); } static void *uwsgi_pty_loop(void *arg) { /* if slave is ready there is something to send to the clients (and logs) if client is ready we have something to write to the master pty */ // block signals on this thread sigset_t smask; sigfillset(&smask); #ifndef UWSGI_DEBUG sigdelset(&smask, SIGSEGV); #endif pthread_sigmask(SIG_BLOCK, &smask, NULL); for(;;) { char buf[8192]; int interesting_fd = -1; int ret = event_queue_wait(upty.queue, -1, &interesting_fd); if (ret == 0) continue; if (ret < 0) continue; if (upty.input && interesting_fd == upty.original_input) { ssize_t rlen = read(upty.original_input, buf, 8192); if (rlen <= 0) continue; if (write(upty.master_fd, buf, rlen) != rlen) { // what to do ? } continue; } if (interesting_fd == upty.master_fd) { ssize_t rlen = read(upty.master_fd, buf, 8192); if (rlen == 0) exit(1); if (rlen < 0) { uwsgi_error("uwsgi_pty_loop()/read()"); continue; } if (upty.log && upty.original_log >= 0) { if (write(upty.original_log, buf, rlen) != rlen) { // what to do ? } } struct uwsgi_pty_client *upc = upty.head; while(upc) { if (write(upc->fd, buf, rlen) != rlen) { struct uwsgi_pty_client *tmp_upc = upc->next; uwsgi_pty_client_remove(upc); upc = tmp_upc; continue; } upc = upc->next; } continue; } if (interesting_fd == upty.server_fd) { struct sockaddr_un client_src; memset(&client_src, 0, sizeof(struct sockaddr_un)); socklen_t client_src_len = 0; int client_fd = accept(upty.server_fd, (struct sockaddr *) &client_src, &client_src_len); if (client_fd < 0) { uwsgi_error("accept()"); continue; } struct uwsgi_pty_client *upc = uwsgi_pty_client_new(client_fd); event_queue_add_fd_read(upty.queue, upc->fd); continue; } struct uwsgi_pty_client *upc = upty.head; while(upc) { if (interesting_fd == upc->fd) { ssize_t rlen = read(upc->fd, buf, 8192); if (rlen <= 0) { uwsgi_pty_client_remove(upc); break; } if (write(upty.master_fd, buf, rlen) != rlen) { } break; } upc = upc->next; } continue; } } static void uwsgi_pty_init() { if (!upty.addr) return; if (!uwsgi.master_process) return; if (uwsgi.mywid > 1) return; char *tcp_port = strrchr(upty.addr, ':'); if (tcp_port) { // disable deferred accept for this socket int current_defer_accept = uwsgi.no_defer_accept; uwsgi.no_defer_accept = 1; upty.server_fd = bind_to_tcp(upty.addr, uwsgi.listen_queue, tcp_port); uwsgi.no_defer_accept = current_defer_accept; } else { upty.server_fd = bind_to_unix(upty.addr, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); } if (upty.log) { upty.original_log = dup(1); } if (upty.input) { upty.original_input = dup(0); } if (openpty(&upty.master_fd, &upty.slave_fd, NULL, NULL, NULL)) { uwsgi_error("uwsgi_pty_init()/openpty()"); exit(1); } uwsgi_log("pty server %s (fd: %d) enabled on %s master: %d slave: %d\n", upty.addr, upty.server_fd, ttyname(upty.slave_fd), upty.master_fd, upty.slave_fd); upty.queue = event_queue_init(); event_queue_add_fd_read(upty.queue, upty.master_fd); event_queue_add_fd_read(upty.queue, upty.server_fd); if (upty.input) { event_queue_add_fd_read(upty.queue, upty.original_input); uwsgi_pty_setterm(upty.original_input); } login_tty(upty.slave_fd); if (upty.command) { upty.command_pid = uwsgi_run_command(upty.command, NULL, -1); } pthread_t t; pthread_create(&t, NULL, uwsgi_pty_loop, NULL); } static void uwsgi_pty_winch() { // 2 uwsgi packets char uwsgi_pkt[8]; #ifdef TIOCGWINSZ struct winsize w; ioctl(0, TIOCGWINSZ, &w); uwsgi_pkt[0] = 0; uwsgi_pkt[1] = (uint8_t) (w.ws_row & 0xff); uwsgi_pkt[2] = (uint8_t) ((w.ws_row >> 8) & 0xff); uwsgi_pkt[3] = 100; uwsgi_pkt[4] = 0; uwsgi_pkt[5] = (uint8_t) (w.ws_col & 0xff); uwsgi_pkt[6] = (uint8_t) ((w.ws_col >> 8) & 0xff); uwsgi_pkt[7] = 101; #endif if (write(upty.server_fd, uwsgi_pkt, 8) != 8) { uwsgi_error("uwsgi_pty_winch()/write()"); exit(1); } } static int uwsgi_pty_client() { if (!upty.remote && !upty.uremote) return 0; char *remote = upty.uremote ? upty.uremote : upty.remote; uwsgi_log("[pty] connecting to %s ...\n", remote); // save current terminal settings if (!tcgetattr(0, &uwsgi.termios)) { uwsgi.restore_tc = 1; } upty.server_fd = uwsgi_connect(remote, uwsgi.socket_timeout, 0); if (upty.server_fd < 0) { uwsgi_error("uwsgi_pty_client()/connect()"); exit(1); } //uwsgi_socket_nb(upty.server_fd); //uwsgi_socket_nb(0); uwsgi_log("[pty] connected.\n"); uwsgi_pty_setterm(0); if (upty.uremote) { signal(SIGWINCH, uwsgi_pty_winch); // send current terminal size uwsgi_pty_winch(); } upty.queue = event_queue_init(); event_queue_add_fd_read(upty.queue, upty.server_fd); event_queue_add_fd_read(upty.queue, 0); for(;;) { char buf[8192]; int interesting_fd = -1; int ret = event_queue_wait(upty.queue, -1, &interesting_fd); if (ret == 0) break; if (ret < 0) { if (errno == EINTR) continue; break; } if (interesting_fd == 0) { ssize_t rlen = read(0, buf, 8192); if (rlen <= 0) break; if (upty.uremote) { struct uwsgi_header uh; uh.modifier1 = 0; uh.pktsize = rlen; uh.modifier2 = 0; if (write(upty.server_fd, &uh, 4) != 4) break; } if (write(upty.server_fd, buf, rlen) != rlen) break; continue; } if (interesting_fd == upty.server_fd) { ssize_t rlen = read(upty.server_fd, buf, 8192); if (rlen <= 0) break; if (write(0, buf, rlen) != rlen) break; continue; } } exit(0); // never here return 0; } struct uwsgi_plugin pty_plugin = { .name = "pty", .options = uwsgi_pty_options, .init = uwsgi_pty_client, .post_fork = uwsgi_pty_init, }; uwsgi-2.0.29/plugins/pty/uwsgiplugin.py000066400000000000000000000003111477626554400202050ustar00rootroot00000000000000NAME='pty' import os uwsgi_os = os.uname()[0] CFLAGS = [] LDFLAGS = [] if uwsgi_os in ('Linux', 'FreeBSD', 'GNU', 'NetBSD', 'DragonFly'): LIBS = ['-lutil'] else: LIBS = [] GCC_LIST = ['pty'] uwsgi-2.0.29/plugins/pypy/000077500000000000000000000000001477626554400154505ustar00rootroot00000000000000uwsgi-2.0.29/plugins/pypy/README000066400000000000000000000026751477626554400163420ustar00rootroot00000000000000This is a bit convoluted, but you run it (so far) this way: You have to compile PyPy with strange options. I'll explain them below. In the pypy checkout, run: ./rpython/bin/rpython -Ojit --shared --gcrootfinder=shadowstack pypy/goal/targetpypystandalone Options: -Ojit - standard PyPy build with JIT --shared - as expected, creates a .so --gcrootfinder - on linux, the default rootfinder is asmgcc which has trouble with position independent code. This option is not needed on OS X or windows. If for some strange/dangerous/wrong reason your uWSGI binary is linked with cpython you could have name collisions with pypy cpyext. In such crazy case you can remove cpyext support with: ./rpython/bin/rpython -Ojit --shared --gcrootfinder=shadowstack pypy/goal/targetpypystandalone --withoutmod-cpyext By default the pypy uWSGI plugin will load the libpypy-c.so library. You should have it in the LD_LIBRARY_PATH, otherwise you can set its path with --pypy-lib option (pass an absolute path to it) You have to specify the pypy home too, you can use the --pypy-home option or the PYPY_HOME var PYPY_HOME=/home/user/pypy/lib_pypy uwsgi --pypy-lib /opt/pypy/libpypy-c.so --http-socket :9090 --pypy-wsgi werkzeug.testapp:test_app The funny part about the uWSGI pypy plugin is that it is mainly written in python. The pypy_setup.py script is linked to the plugin, but you can override it with the --pypy-setup option uwsgi-2.0.29/plugins/pypy/pypy_plugin.c000066400000000000000000000265131477626554400202020ustar00rootroot00000000000000/******************************************************************* This is the C part of the PyPy plugin (with the main logic being in Python, see pypy_setup.py). Idea and initial implementation by Maciej Fijalkowski *******************************************************************/ #include struct uwsgi_pypy { void *handler; char *lib; char *setup; char *home; char *wsgi; char *wsgi_file; char *paste; struct uwsgi_string_list *eval; struct uwsgi_string_list *eval_post_fork; struct uwsgi_string_list *exec; struct uwsgi_string_list *exec_post_fork; struct uwsgi_string_list *pp; pthread_mutex_t attach_thread_lock; } upypy; // the functions exposed by libpypy-c char *(*u_rpython_startup_code)(void); int (*u_pypy_setup_home)(char *, int); int (*u_pypy_execute_source)(char *); void (*u_pypy_thread_attach)(void); void (*u_pypy_init_threads)(void); // the hooks you can override with pypy void (*uwsgi_pypy_hook_execute_source)(char *); void (*uwsgi_pypy_hook_loader)(char *); void (*uwsgi_pypy_hook_file_loader)(char *); void (*uwsgi_pypy_hook_paste_loader)(char *); void (*uwsgi_pypy_hook_pythonpath)(char *); void (*uwsgi_pypy_hook_request)(void *, int); void (*uwsgi_pypy_post_fork_hook)(void); extern struct uwsgi_server uwsgi; struct uwsgi_plugin pypy_plugin; static int uwsgi_pypy_init() { size_t rlen = 0; char *buffer = NULL; void *is_cpython_loaded = dlsym(RTLD_DEFAULT, "Py_Initialize"); if (is_cpython_loaded) { uwsgi_log("!!! Loading both PyPy and CPython in the same process IS PURE EVIL AND IT IS NOT SUPPORTED !!!\n"); exit(1); } if (dlsym(RTLD_DEFAULT, "rpython_startup_code")) { uwsgi_log("PyPy runtime detected, skipping libpypy-c loading\n"); goto ready; } else if (upypy.lib) { upypy.handler = dlopen(upypy.lib, RTLD_NOW | RTLD_GLOBAL); } else { if (upypy.home) { // first try with /bin way: #ifdef __CYGWIN__ char *libpath = uwsgi_concat2(upypy.home, "/bin/libpypy-c.dll"); #elif defined(__APPLE__) char *libpath = uwsgi_concat2(upypy.home, "/bin/libpypy-c.dylib"); #else char *libpath = uwsgi_concat2(upypy.home, "/bin/libpypy-c.so"); #endif if (uwsgi_file_exists(libpath)) { upypy.handler = dlopen(libpath, RTLD_NOW | RTLD_GLOBAL); } free(libpath); // fallback to old-style way if (!upypy.handler) { #ifdef __CYGWIN__ char *libpath = uwsgi_concat2(upypy.home, "/libpypy-c.dll"); #elif defined(__APPLE__) char *libpath = uwsgi_concat2(upypy.home, "/libpypy-c.dylib"); #else char *libpath = uwsgi_concat2(upypy.home, "/libpypy-c.so"); #endif if (uwsgi_file_exists(libpath)) { upypy.handler = dlopen(libpath, RTLD_NOW | RTLD_GLOBAL); } free(libpath); } } // fallback to standard library search path if (!upypy.handler) { #ifdef __CYGWIN__ upypy.handler = dlopen("libpypy-c.dll", RTLD_NOW | RTLD_GLOBAL); #elif defined(__APPLE__) upypy.handler = dlopen("libpypy-c.dylib", RTLD_NOW | RTLD_GLOBAL); #else upypy.handler = dlopen("libpypy-c.so", RTLD_NOW | RTLD_GLOBAL); #endif } } if (!upypy.handler) { uwsgi_log("unable to load pypy library: %s\n", dlerror()); exit(1); } u_rpython_startup_code = dlsym(upypy.handler, "rpython_startup_code"); if (!u_rpython_startup_code) { uwsgi_log("unable to find rpython_startup_code() symbol\n"); exit(1); } u_pypy_setup_home = dlsym(upypy.handler, "pypy_setup_home"); if (!u_pypy_setup_home) { uwsgi_log("unable to find pypy_setup_home() symbol\n"); exit(1); } u_pypy_init_threads = dlsym(upypy.handler, "pypy_init_threads"); if (!u_pypy_init_threads) { uwsgi_log("!!! WARNING your libpypy-c does not export pypy_init_threads, multithreading will not work !!!\n"); } u_rpython_startup_code(); if (!upypy.home) { upypy.home = getenv("PYPY_HOME"); if (!upypy.home) { uwsgi_log("you have to specify a pypy home with --pypy-home\n"); exit(1); } } if (u_pypy_setup_home(upypy.home, 0)) { char *retry = uwsgi_concat2(upypy.home, "/lib_pypy"); if (uwsgi_is_dir(retry)) { // this time we use debug if (!u_pypy_setup_home(retry, 1)) { free(retry); goto ready; } } uwsgi_log("unable to set pypy home to \"%s\"\n", upypy.home); exit(1); } ready: u_pypy_execute_source = dlsym(upypy.handler, "pypy_execute_source"); if (!u_pypy_execute_source) { uwsgi_log("unable to find pypy_execute_source() symbol\n"); exit(1); } u_pypy_thread_attach = dlsym(upypy.handler, "pypy_thread_attach"); if (!u_pypy_thread_attach) { uwsgi_log("!!! WARNING your libpypy-c does not export pypy_thread_attach, multithreading will not work !!!\n"); } if (upypy.setup) { buffer = uwsgi_open_and_read(upypy.setup, &rlen, 1, NULL); } else { char *start = dlsym(RTLD_DEFAULT, "uwsgi_pypy_setup_start"); if (!start) { start = dlsym(RTLD_DEFAULT, "_uwsgi_pypy_setup_start"); } char *end = dlsym(RTLD_DEFAULT, "uwsgi_pypy_setup_end"); if (!end) { end = dlsym(RTLD_DEFAULT, "_uwsgi_pypy_setup_end"); } if (start && end) { buffer = uwsgi_concat2n(start, end-start, "", 0); } } if (!buffer) { uwsgi_log("you have to load a pypy setup file with --pypy-setup\n"); exit(1); } if (u_pypy_execute_source(buffer)) { exit(1); } free(buffer); // add items to the pythonpath struct uwsgi_string_list *usl = upypy.pp; while(usl) { if (uwsgi_pypy_hook_pythonpath) { uwsgi_pypy_hook_pythonpath(usl->value); } usl = usl->next; } return 0; } static void uwsgi_pypy_preinit_apps() { if (!uwsgi_pypy_hook_execute_source) { uwsgi_log("*** WARNING your pypy setup code does not expose a callback for \"execute_source\" ***\n"); return; } struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, upypy.eval) { uwsgi_pypy_hook_execute_source(usl->value); } uwsgi_foreach(usl, upypy.exec) { size_t rlen = 0; char *buffer = uwsgi_open_and_read(usl->value, &rlen, 1, NULL); uwsgi_pypy_hook_execute_source(buffer); free(buffer); } } static int uwsgi_pypy_request(struct wsgi_request *wsgi_req) { /* Standard WSGI request */ if (!wsgi_req->uh->pktsize) { uwsgi_log( "Empty pypy request. skip.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } if (uwsgi_pypy_hook_request) { uwsgi_pypy_hook_request(wsgi_req, wsgi_req->async_id); } return UWSGI_OK; } static void uwsgi_pypy_after_request(struct wsgi_request *wsgi_req) { log_request(wsgi_req); } static void uwsgi_pypy_init_apps() { if (uwsgi_pypy_hook_loader && upypy.wsgi) { uwsgi_pypy_hook_loader(upypy.wsgi); } if (uwsgi_pypy_hook_file_loader && upypy.wsgi_file) { uwsgi_pypy_hook_file_loader(upypy.wsgi_file); } if (uwsgi_pypy_hook_paste_loader && upypy.paste) { uwsgi_pypy_hook_paste_loader(upypy.paste); } } /* static void uwsgi_pypy_atexit() { if (pypy_debug_file) fflush(pypy_debug_file); } */ static void uwsgi_opt_pypy_ini_paste(char *opt, char *value, void *foobar) { uwsgi_opt_load_ini(opt, value, NULL); upypy.paste = value; } static struct uwsgi_option uwsgi_pypy_options[] = { {"pypy-lib", required_argument, 0, "set the path/name of the pypy library", uwsgi_opt_set_str, &upypy.lib, 0}, {"pypy-setup", required_argument, 0, "set the path of the python setup script", uwsgi_opt_set_str, &upypy.setup, 0}, {"pypy-home", required_argument, 0, "set the home of pypy library", uwsgi_opt_set_str, &upypy.home, 0}, {"pypy-wsgi", required_argument, 0, "load a WSGI module", uwsgi_opt_set_str, &upypy.wsgi, 0}, {"pypy-wsgi-file", required_argument, 0, "load a WSGI/mod_wsgi file", uwsgi_opt_set_str, &upypy.wsgi_file, 0}, {"pypy-ini-paste", required_argument, 0, "load a paste.deploy config file containing uwsgi section", uwsgi_opt_pypy_ini_paste, NULL, UWSGI_OPT_IMMEDIATE}, {"pypy-paste", required_argument, 0, "load a paste.deploy config file", uwsgi_opt_set_str, &upypy.paste, 0}, {"pypy-eval", required_argument, 0, "evaluate pypy code before fork()", uwsgi_opt_add_string_list, &upypy.eval, 0}, {"pypy-eval-post-fork", required_argument, 0, "evaluate pypy code soon after fork()", uwsgi_opt_add_string_list, &upypy.eval_post_fork, 0}, {"pypy-exec", required_argument, 0, "execute pypy code from file before fork()", uwsgi_opt_add_string_list, &upypy.exec, 0}, {"pypy-exec-post-fork", required_argument, 0, "execute pypy code from file soon after fork()", uwsgi_opt_add_string_list, &upypy.exec_post_fork, 0}, {"pypy-pp", required_argument, 0, "add an item to the pythonpath", uwsgi_opt_add_string_list, &upypy.pp, 0}, {"pypy-python-path", required_argument, 0, "add an item to the pythonpath", uwsgi_opt_add_string_list, &upypy.pp, 0}, {"pypy-pythonpath", required_argument, 0, "add an item to the pythonpath", uwsgi_opt_add_string_list, &upypy.pp, 0}, {0, 0, 0, 0, 0, 0, 0}, }; static void uwsgi_pypy_enable_threads() { if (u_pypy_init_threads) { u_pypy_init_threads(); } } static void uwsgi_pypy_init_thread(int sig) { if (u_pypy_thread_attach) { pthread_mutex_lock(&upypy.attach_thread_lock); u_pypy_thread_attach(); pthread_mutex_unlock(&upypy.attach_thread_lock); } } static int uwsgi_pypy_signal_handler(uint8_t sig, void *handler) { void (*pypy_func)(int) = (void(*)(int)) handler; pypy_func(sig); return 0; } static uint64_t uwsgi_pypy_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char **buffer) { int iargvs[UMAX8]; int i; int (*pypy_func)(int, char **, int*, char **) = (int (*)(int, char **, int*, char **)) func; // we convert 16bit to int for(i=0;ivalue); } uwsgi_foreach(usl, upypy.exec_post_fork) { size_t rlen = 0; char *buffer = uwsgi_open_and_read(usl->value, &rlen, 1, NULL); uwsgi_pypy_hook_execute_source(buffer); free(buffer); } if (uwsgi_pypy_post_fork_hook) { uwsgi_pypy_post_fork_hook(); } } static void uwsgi_pypy_onload() { #ifdef UWSGI_PYPY_HOME upypy.home = UWSGI_PYPY_HOME; #endif uwsgi.has_threads = 1; } static int uwsgi_pypy_mule(char *opt) { if (!uwsgi_pypy_hook_execute_source) { uwsgi_log("!!! no \"execute_source\" callback in your pypy setup code !!!\n"); exit(1); } if (uwsgi_endswith(opt, ".py")) { size_t rlen = 0; char *buffer = uwsgi_open_and_read(opt, &rlen, 1, NULL); uwsgi_pypy_hook_execute_source(buffer); free(buffer); return 1; } return 0; } struct uwsgi_plugin pypy_plugin = { .name = "pypy", .modifier1 = 0, .on_load = uwsgi_pypy_onload, .init = uwsgi_pypy_init, .request = uwsgi_pypy_request, .after_request = uwsgi_pypy_after_request, .options = uwsgi_pypy_options, .preinit_apps = uwsgi_pypy_preinit_apps, .init_apps = uwsgi_pypy_init_apps, .init_thread = uwsgi_pypy_init_thread, .signal_handler = uwsgi_pypy_signal_handler, .enable_threads = uwsgi_pypy_enable_threads, .rpc = uwsgi_pypy_rpc, .post_fork = uwsgi_pypy_post_fork, .mule = uwsgi_pypy_mule, }; uwsgi-2.0.29/plugins/pypy/pypy_setup.py000066400000000000000000000743471477626554400202620ustar00rootroot00000000000000import sys import os sys.path.insert(0, '.') sys.path.extend(os.environ.get('PYTHONPATH', '').split(os.pathsep)) import imp import traceback __name__ = '__main__' mainmodule = type(sys)('__main__') sys.modules['__main__'] = mainmodule import cffi # this is a list holding object we do not want to be freed (like callback and handlers) uwsgi_gc = [] # the main ffi ffi = cffi.FFI() # the hooks we need to patch hooks = ''' void free(void *); ssize_t read(int, void *, size_t); ssize_t write(int, const void *, size_t); int close(int); extern void (*uwsgi_pypy_hook_execute_source)(char *); extern void (*uwsgi_pypy_hook_loader)(char *); extern void (*uwsgi_pypy_hook_file_loader)(char *); extern void (*uwsgi_pypy_hook_paste_loader)(char *); extern void (*uwsgi_pypy_hook_pythonpath)(char *); extern void (*uwsgi_pypy_hook_request)(struct wsgi_request *); extern void (*uwsgi_pypy_post_fork_hook)(void); ''' # here we load CFLAGS and uwsgi.h from the binary defines0 = ''' char *uwsgi_get_cflags(); char *uwsgi_get_dot_h(); ''' ffi.cdef(defines0) lib0 = ffi.verify(defines0) # this is ugly, we should find a better approach # basically it build a list of #define from binary CFLAGS uwsgi_cdef = [] uwsgi_defines = [] uwsgi_cflags = ffi.string(lib0.uwsgi_get_cflags()).split() for cflag in uwsgi_cflags: if cflag.startswith(b'-D'): line = cflag[2:].decode() if '=' in line: (key, value) = line.split('=', 1) uwsgi_cdef.append('#define %s ...' % key) uwsgi_defines.append('#define %s %s' % (key, value.replace('\\"', '"').replace('""', '"'))) else: uwsgi_cdef.append('#define %s ...' % line) uwsgi_defines.append('#define %s 1' % line) uwsgi_dot_h = ffi.string(lib0.uwsgi_get_dot_h()) # uwsgi definitions cdefines = ''' %s struct iovec { void *iov_base; size_t iov_len; ...; }; struct uwsgi_header { uint8_t modifier1; ...; }; struct wsgi_request { int fd; int async_id; uint16_t var_cnt; struct iovec *hvec; int async_ready_fd; int async_last_ready_fd; int suspended; struct uwsgi_header *uh; ...; }; struct uwsgi_opt { char *key; char *value; ...; }; struct uwsgi_worker { int id; int pid; uint64_t requests; uint64_t delta_requests; uint64_t signals; int cheaped; int suspended; int sig; uint8_t signum; uint64_t running_time; uint64_t avg_response_time; uint64_t tx; ...; }; struct uwsgi_plugin { uint8_t modifier1; void (*suspend) (struct wsgi_request *); void (*resume) (struct wsgi_request *); ...; }; struct uwsgi_buffer { char *buf; size_t pos; ...; }; struct uwsgi_lock_item { ...; }; struct uwsgi_cache { struct uwsgi_lock_item *lock; ...; }; struct uwsgi_cache_item { uint64_t keysize; ...; }; struct uwsgi_server { char hostname[]; int mywid; int muleid; int master_process; struct uwsgi_opt **exported_opts; int exported_opts_cnt; struct uwsgi_worker *workers; int signal_socket; int numproc; int async; void (*schedule_to_main) (struct wsgi_request *); void (*schedule_to_req) (void); struct wsgi_request *(*current_wsgi_req) (void); struct wsgi_request *wsgi_req; struct uwsgi_plugin *p[]; ...; }; extern struct uwsgi_server uwsgi; extern struct uwsgi_plugin pypy_plugin; extern const char *uwsgi_pypy_version; char *uwsgi_binary_path(); void *uwsgi_malloc(size_t); struct uwsgi_logvar { char key[256]; uint8_t keylen; char val[256]; uint8_t vallen; struct uwsgi_logvar *next; }; struct uwsgi_logvar *uwsgi_logvar_get(struct wsgi_request *, char *, uint8_t); void uwsgi_logvar_add(struct wsgi_request *, char *, uint8_t, char *, uint8_t); int uwsgi_response_prepare_headers(struct wsgi_request *, char *, size_t); int uwsgi_response_add_header(struct wsgi_request *, char *, uint16_t, char *, uint16_t); int uwsgi_response_write_body_do(struct wsgi_request *, char *, size_t); int uwsgi_response_sendfile_do_can_close(struct wsgi_request *, int, size_t, size_t, int); char *uwsgi_request_body_read(struct wsgi_request *, ssize_t , ssize_t *); char *uwsgi_request_body_readline(struct wsgi_request *, ssize_t, ssize_t *); void uwsgi_buffer_destroy(struct uwsgi_buffer *); int uwsgi_is_again(); int uwsgi_register_rpc(char *, struct uwsgi_plugin *, uint8_t, void *); int uwsgi_register_signal(uint8_t, char *, void *, uint8_t); char *uwsgi_do_rpc(char *, char *, uint8_t, char **, uint16_t *, uint64_t *); void uwsgi_set_processname(char *); int uwsgi_signal_send(int, uint8_t); uint64_t uwsgi_worker_exceptions(int); int uwsgi_worker_is_busy(int); char *uwsgi_cache_magic_get(char *, uint16_t, uint64_t *, uint64_t *, char *); int uwsgi_cache_magic_set(char *, uint16_t, char *, uint64_t, uint64_t, uint64_t, char *); int uwsgi_cache_magic_del(char *, uint16_t, char *); int uwsgi_cache_magic_exists(char *, uint16_t, char *); int uwsgi_cache_magic_clear(char *); struct uwsgi_cache *uwsgi_cache_by_name(char *); void uwsgi_cache_rlock(struct uwsgi_cache *); void uwsgi_cache_rwunlock(struct uwsgi_cache *); char *uwsgi_cache_item_key(struct uwsgi_cache_item *); struct uwsgi_cache_item *uwsgi_cache_keys(struct uwsgi_cache *, uint64_t *, struct uwsgi_cache_item **); int uwsgi_add_file_monitor(uint8_t, char *); int uwsgi_add_timer(uint8_t, int); int uwsgi_signal_add_rb_timer(uint8_t, int, int); int uwsgi_user_lock(int); int uwsgi_user_unlock(int); int uwsgi_signal_registered(uint8_t); int uwsgi_signal_add_cron(uint8_t, int, int, int, int, int); void uwsgi_alarm_trigger(char *, char *, size_t); void async_schedule_to_req_green(void); void async_add_timeout(struct wsgi_request *, int); int async_add_fd_write(struct wsgi_request *, int, int); int async_add_fd_read(struct wsgi_request *, int, int); int uwsgi_connect(char *, int, int); int uwsgi_websocket_handshake(struct wsgi_request *, char *, uint16_t, char *, uint16_t, char *, uint16_t); int uwsgi_websocket_send(struct wsgi_request *, char *, size_t); struct uwsgi_buffer *uwsgi_websocket_recv(struct wsgi_request *); struct uwsgi_buffer *uwsgi_websocket_recv_nb(struct wsgi_request *); char *uwsgi_chunked_read(struct wsgi_request *, size_t *, int, int); void uwsgi_disconnect(struct wsgi_request *); int uwsgi_ready_fd(struct wsgi_request *); void set_user_harakiri(int); int uwsgi_metric_set(char *, char *, int64_t); int uwsgi_metric_inc(char *, char *, int64_t); int uwsgi_metric_dec(char *, char *, int64_t); int uwsgi_metric_mul(char *, char *, int64_t); int uwsgi_metric_div(char *, char *, int64_t); int64_t uwsgi_metric_get(char *, char *); %s ''' % ('\n'.join(uwsgi_cdef), hooks) cverify = ''' %s const char *uwsgi_pypy_version = UWSGI_VERSION; %s extern struct uwsgi_server uwsgi; extern struct uwsgi_plugin pypy_plugin; %s ''' % ('\n'.join(uwsgi_defines), uwsgi_dot_h.decode(), hooks) ffi.cdef(cdefines) lib = ffi.verify(cverify) libc = ffi.dlopen(None) """ this is a global object point the the WSGI callable it sucks, i will fix it in the near future... """ wsgi_application = None # fix argv if needed if len(sys.argv) == 0: sys.argv.insert(0, ffi.string(lib.uwsgi_binary_path()).decode()) @ffi.callback("void(char *)") def uwsgi_pypy_execute_source(s): """ execute source, we expose it as cffi callback to avoid deadlocks after GIL initialization """ source = ffi.string(s) exec(source) @ffi.callback("void(char *)") def uwsgi_pypy_loader(module): """ load a wsgi module """ global wsgi_application m = ffi.string(module).decode() c = 'application' if ':' in m: m, c = m.split(':') if '.' in m: mod = __import__(m, None, None, '*') else: mod = __import__(m) wsgi_application = getattr(mod, c) @ffi.callback("void(char *)") def uwsgi_pypy_file_loader(filename): """ load a mod_wsgi compliant .wsgi file """ global wsgi_application w = ffi.string(filename) c = 'application' mod = imp.load_source('uwsgi_file_wsgi', w.decode()) wsgi_application = getattr(mod, c) @ffi.callback("void(char *)") def uwsgi_pypy_paste_loader(config): """ load a .ini paste app """ global wsgi_application c = ffi.string(config).decode() if c.startswith('config:'): c = c[7:] if c[0] != '/': c = os.getcwd() + '/' + c try: from logging.config import fileConfig fileConfig(c) except ImportError: print("PyPy WARNING: unable to load logging.config") from paste.deploy import loadapp wsgi_application = loadapp('config:%s' % c) @ffi.callback("void()") def uwsgi_pypy_post_fork_hook(): """ .post_fork_hook """ import uwsgi if hasattr(uwsgi, 'post_fork_hook'): uwsgi.post_fork_hook() @ffi.callback("void(char *)") def uwsgi_pypy_pythonpath(item): """ add an item to the pythonpath """ path = ffi.string(item).decode() sys.path.append(path) print("added %s to pythonpath" % path) class WSGIfilewrapper(object): """ class implementing wsgi.file_wrapper """ def __init__(self, wsgi_req, f, chunksize=0): self.wsgi_req = wsgi_req self.f = f self.chunksize = chunksize if hasattr(f, 'close'): self.close = f.close def __iter__(self): return self def __next__(self): if self.chunksize: data = self.f.read(self.chunksize) else: data = self.f.read() if data: return data raise StopIteration() next = __next__ def sendfile(self): if hasattr(self.f, 'fileno'): lib.uwsgi_response_sendfile_do_can_close(self.wsgi_req, self.f.fileno(), 0, 0, 0) elif hasattr(self.f, 'read'): if self.chunksize == 0: chunk = self.f.read() if len(chunk) > 0: lib.uwsgi_response_write_body_do(self.wsgi_req, ffi.new("char[]", chunk), len(chunk)) return while True: chunk = self.f.read(self.chunksize) if chunk is None or len(chunk) == 0: break lib.uwsgi_response_write_body_do(self.wsgi_req, ffi.new("char[]", chunk), len(chunk)) class WSGIinput(object): """ class implementing wsgi.input """ def __init__(self, wsgi_req): self.wsgi_req = wsgi_req def read(self, size=0): rlen = ffi.new('ssize_t*') chunk = lib.uwsgi_request_body_read(self.wsgi_req, size, rlen) if chunk != ffi.NULL: return ffi.buffer(chunk, rlen[0])[:] if rlen[0] < 0: raise IOError("error reading wsgi.input") raise IOError("error waiting for wsgi.input") def getline(self, hint=0): rlen = ffi.new('ssize_t*') chunk = lib.uwsgi_request_body_readline(self.wsgi_req, hint, rlen) if chunk != ffi.NULL: return ffi.buffer(chunk, rlen[0])[:] if rlen[0] < 0: raise IOError("error reading line from wsgi.input") raise IOError("error waiting for line on wsgi.input") def readline(self, hint=0): return self.getline(hint) def readlines(self, hint=0): lines = [] while True: chunk = self.getline(hint) if len(chunk) == 0: break lines.append(chunk) return lines def __iter__(self): return self def __next__(self): chunk = self.getline() if len(chunk) == 0: raise StopIteration return chunk @ffi.callback("void(struct wsgi_request *)") def uwsgi_pypy_wsgi_handler(wsgi_req): """ the WSGI request handler """ import uwsgi global wsgi_application def writer(data): lib.uwsgi_response_write_body_do(wsgi_req, ffi.new("char[]", data), len(data)) def start_response(status, headers, exc_info=None): if exc_info: traceback.print_exception(*exc_info) status = status.encode() lib.uwsgi_response_prepare_headers(wsgi_req, ffi.new("char[]", status), len(status)) for hh in headers: hh = (hh[0].encode(), hh[1].encode()) lib.uwsgi_response_add_header(wsgi_req, ffi.new("char[]", hh[0]), len(hh[0]), ffi.new("char[]", hh[1]), len(hh[1])) return writer environ = {} iov = wsgi_req.hvec for i in range(0, wsgi_req.var_cnt, 2): environ[ffi.string(ffi.cast("char*", iov[i].iov_base), iov[i].iov_len).decode()] = ffi.string(ffi.cast("char*", iov[i+1].iov_base), iov[i+1].iov_len).decode() environ['wsgi.version'] = (1, 0) scheme = 'http' if 'HTTPS' in environ: if environ['HTTPS'] in ('on', 'ON', 'On', '1', 'true', 'TRUE', 'True'): scheme = 'https' environ['wsgi.url_scheme'] = environ.get('UWSGI_SCHEME', scheme) environ['wsgi.input'] = WSGIinput(wsgi_req) environ['wsgi.errors'] = sys.stderr environ['wsgi.run_once'] = False environ['wsgi.file_wrapper'] = lambda f, chunksize=0: WSGIfilewrapper(wsgi_req, f, chunksize) environ['wsgi.multithread'] = True environ['wsgi.multiprocess'] = True environ['uwsgi.core'] = wsgi_req.async_id environ['uwsgi.node'] = uwsgi.hostname response = wsgi_application(environ, start_response) if type(response) is str: writer(response) else: try: if isinstance(response, WSGIfilewrapper): response.sendfile() else: for chunk in response: if isinstance(chunk, WSGIfilewrapper): try: chunk.sendfile() finally: chunk.close() else: writer(chunk) finally: if hasattr(response, 'close'): response.close() lib.uwsgi_pypy_hook_execute_source = uwsgi_pypy_execute_source lib.uwsgi_pypy_hook_loader = uwsgi_pypy_loader lib.uwsgi_pypy_hook_file_loader = uwsgi_pypy_file_loader lib.uwsgi_pypy_hook_paste_loader = uwsgi_pypy_paste_loader lib.uwsgi_pypy_hook_pythonpath = uwsgi_pypy_pythonpath lib.uwsgi_pypy_hook_request = uwsgi_pypy_wsgi_handler lib.uwsgi_pypy_post_fork_hook = uwsgi_pypy_post_fork_hook """ Here we define the "uwsgi" virtual module """ uwsgi = imp.new_module('uwsgi') sys.modules['uwsgi'] = uwsgi uwsgi.version = ffi.string(lib.uwsgi_pypy_version) uwsgi.hostname = ffi.string(lib.uwsgi.hostname) def uwsgi_pypy_uwsgi_register_signal(signum, kind, handler): cb = ffi.callback('void(int)', handler) uwsgi_gc.append(cb) if lib.uwsgi_register_signal(signum, ffi.new("char[]", kind), cb, lib.pypy_plugin.modifier1) < 0: raise Exception("unable to register signal %d" % signum) uwsgi.register_signal = uwsgi_pypy_uwsgi_register_signal class uwsgi_pypy_RPC(object): def __init__(self, func): self.func = func def __call__(self, argc, argv, argvs, buf): pargs = [] for i in range(0, argc): pargs.append(ffi.buffer(argv[i], argvs[i])[:]) response = self.func(*pargs) if len(response) > 0: buf[0] = lib.uwsgi_malloc(len(response)) dst = ffi.buffer(buf[0], len(response)) dst[:len(response)] = response return len(response) def uwsgi_pypy_uwsgi_register_rpc(name, func, argc=0): rpc_func = uwsgi_pypy_RPC(func) cb = ffi.callback("int(int, char*[], int[], char**)", rpc_func) uwsgi_gc.append(cb) if lib.uwsgi_register_rpc(ffi.new("char[]", name), ffi.addressof(lib.pypy_plugin), argc, cb) < 0: raise Exception("unable to register rpc func %s" % name) uwsgi.register_rpc = uwsgi_pypy_uwsgi_register_rpc def uwsgi_pypy_rpc(node, func, *args): argc = 0 argv = ffi.new('char*[256]') argvs = ffi.new('uint16_t[256]') rsize = ffi.new('uint64_t*') for arg in args: if argc >= 255: raise Exception('invalid number of rpc arguments') if len(arg) >= 65535: raise Exception('invalid rpc argument size (must be < 65535)') argv[argc] = ffi.new('char[]', arg) argvs[argc] = len(arg) argc += 1 if node: c_node = ffi.new("char[]", node) else: c_node = ffi.NULL response = lib.uwsgi_do_rpc(c_node, ffi.new("char[]", func), argc, argv, argvs, rsize) if response: ret = ffi.buffer(response, rsize[0])[:] lib.free(response) return ret return None uwsgi.rpc = uwsgi_pypy_rpc def uwsgi_pypy_call(func, *args): node = None if b'@' in func: (func, node) = func.split(b'@') return uwsgi_pypy_rpc(node, func, *args) uwsgi.call = uwsgi_pypy_call uwsgi.signal = lambda x: lib.uwsgi_signal_send(lib.uwsgi.signal_socket, x) uwsgi.metric_get = lambda x: lib.uwsgi_metric_get(x, ffi.NULL) uwsgi.metric_set = lambda x, y: lib.uwsgi_metric_set(x, ffi.NULL, y) uwsgi.metric_inc = lambda x, y=1: lib.uwsgi_metric_inc(x, ffi.NULL, y) uwsgi.metric_dec = lambda x, y=1: lib.uwsgi_metric_dec(x, ffi.NULL, y) uwsgi.metric_mul = lambda x, y=1: lib.uwsgi_metric_mul(x, ffi.NULL, y) uwsgi.metric_div = lambda x, y=1: lib.uwsgi_metric_div(x, ffi.NULL, y) def uwsgi_pypy_uwsgi_cache_get(key, cache=ffi.NULL): vallen = ffi.new('uint64_t*') value = lib.uwsgi_cache_magic_get(key, len(key), vallen, ffi.NULL, cache) if value == ffi.NULL: return None ret = ffi.buffer(value, vallen[0])[:] libc.free(value) return ret uwsgi.cache_get = uwsgi_pypy_uwsgi_cache_get def uwsgi_pypy_uwsgi_cache_set(key, value, expires=0, cache=ffi.NULL): if lib.uwsgi_cache_magic_set(key, len(key), value, len(value), expires, 0, cache) < 0: raise Exception('unable to store item in the cache') uwsgi.cache_set = uwsgi_pypy_uwsgi_cache_set def uwsgi_pypy_uwsgi_cache_update(key, value, expires=0, cache=ffi.NULL): if lib.uwsgi_cache_magic_set(key, len(key), value, len(value), expires, 1 << 1, cache) < 0: raise Exception('unable to store item in the cache') uwsgi.cache_update = uwsgi_pypy_uwsgi_cache_update def uwsgi_pypy_uwsgi_cache_del(key, cache=ffi.NULL): if lib.uwsgi_cache_magic_del(key, len(key), cache) < 0: raise Exception('unable to delete item from the cache') uwsgi.cache_del = uwsgi_pypy_uwsgi_cache_del def uwsgi_pypy_uwsgi_cache_keys(cache=ffi.NULL): uc = lib.uwsgi_cache_by_name(cache) if uc == ffi.NULL: raise Exception('no local uWSGI cache available') l = [] lib.uwsgi_cache_rlock(uc) pos = ffi.new('uint64_t *') uci = ffi.new('struct uwsgi_cache_item **') while True: uci[0] = lib.uwsgi_cache_keys(uc, pos, uci) if uci[0] == ffi.NULL: break l.append(ffi.buffer(lib.uwsgi_cache_item_key(uci[0]), uci[0].keysize)[:]) lib.uwsgi_cache_rwunlock(uc) return l uwsgi.cache_keys = uwsgi_pypy_uwsgi_cache_keys def uwsgi_pypy_uwsgi_add_timer(signum, secs): if lib.uwsgi_add_timer(signum, secs) < 0: raise Exception("unable to register timer") uwsgi.add_timer = uwsgi_pypy_uwsgi_add_timer def uwsgi_pypy_uwsgi_add_rb_timer(signum, secs): if lib.uwsgi_signal_add_rb_timer(signum, secs, 0) < 0: raise Exception("unable to register redblack timer") uwsgi.add_rb_timer = uwsgi_pypy_uwsgi_add_rb_timer def uwsgi_pypy_uwsgi_add_file_monitor(signum, filename): if lib.uwsgi_add_file_monitor(signum, ffi.new("char[]", filename)) < 0: raise Exception("unable to register file monitor") uwsgi.add_file_monitor = uwsgi_pypy_uwsgi_add_file_monitor def uwsgi_pypy_lock(num=0): if lib.uwsgi_user_lock(num) < 0: raise Exception("invalid lock") uwsgi.lock = uwsgi_pypy_lock def uwsgi_pypy_unlock(num=0): if lib.uwsgi_user_unlock(num) < 0: raise Exception("invalid lock") uwsgi.unlock = uwsgi_pypy_unlock def uwsgi_pypy_masterpid(): if lib.uwsgi.master_process: return lib.uwsgi.workers[0].pid return 0 uwsgi.masterpid = uwsgi_pypy_masterpid uwsgi.worker_id = lambda: lib.uwsgi.mywid uwsgi.mule_id = lambda: lib.uwsgi.muleid def uwsgi_pypy_signal_registered(signum): if lib.uwsgi_signal_registered(signum) > 0: return True return False uwsgi.signal_registered = uwsgi_pypy_signal_registered def uwsgi_pypy_alarm(alarm, msg): lib.uwsgi_alarm_trigger(ffi.new('char[]', alarm), ffi.new('char[]', msg), len(msg)) uwsgi.alarm = uwsgi_pypy_alarm uwsgi.setprocname = lambda name: lib.uwsgi_set_processname(ffi.new('char[]', name)) def uwsgi_pypy_add_cron(signum, minute, hour, day, month, week): if lib.uwsgi_signal_add_cron(signum, minute, hour, day, month, week) < 0: raise Exception("unable to register cron") uwsgi.add_cron = uwsgi_pypy_add_cron """ populate uwsgi.opt """ uwsgi.opt = {} for i in range(0, lib.uwsgi.exported_opts_cnt): uo = lib.uwsgi.exported_opts[i] k = ffi.string(uo.key) if uo.value == ffi.NULL: v = True else: v = ffi.string(uo.value) if k in uwsgi.opt: if type(uwsgi.opt[k]) is list: uwsgi.opt[k].append(v) else: uwsgi.opt[k] = [uwsgi.opt[k], v] else: uwsgi.opt[k] = v def uwsgi_pypy_current_wsgi_req(): wsgi_req = lib.uwsgi.current_wsgi_req() if wsgi_req == ffi.NULL: raise Exception("unable to get current wsgi_request, check your setup !!!") return wsgi_req def uwsgi_pypy_suspend(): """ uwsgi.suspend() """ wsgi_req = uwsgi_pypy_current_wsgi_req() if lib.uwsgi.schedule_to_main: lib.uwsgi.schedule_to_main(wsgi_req) uwsgi.suspend = uwsgi_pypy_suspend def uwsgi_pypy_workers(): """ uwsgi.workers() """ workers = [] for i in range(1, lib.uwsgi.numproc+1): worker = {} worker['id'] = lib.uwsgi.workers[i].id worker['pid'] = lib.uwsgi.workers[i].pid worker['requests'] = lib.uwsgi.workers[i].requests worker['delta_requests'] = lib.uwsgi.workers[i].delta_requests worker['signals'] = lib.uwsgi.workers[i].signals worker['exceptions'] = lib.uwsgi_worker_exceptions(i) worker['apps'] = [] if lib.uwsgi.workers[i].cheaped: worker['status'] == 'cheap' elif lib.uwsgi.workers[i].suspended and not lib.uwsgi_worker_is_busy(i): worker['status'] == 'pause' else: if lib.uwsgi.workers[i].sig: worker['status'] = 'sig%d' % lib.uwsgi.workers[i].signum elif lib.uwsgi_worker_is_busy(i): worker['status'] = 'busy' else: worker['status'] = 'idle' worker['running_time'] = lib.uwsgi.workers[i].running_time worker['avg_rt'] = lib.uwsgi.workers[i].avg_response_time worker['tx'] = lib.uwsgi.workers[i].tx workers.append(worker) return workers uwsgi.workers = uwsgi_pypy_workers def uwsgi_pypy_async_sleep(timeout): """ uwsgi.async_sleep(timeout) """ if timeout > 0: wsgi_req = uwsgi_pypy_current_wsgi_req() lib.async_add_timeout(wsgi_req, timeout) uwsgi.async_sleep = uwsgi_pypy_async_sleep def uwsgi_pypy_async_connect(addr): """ uwsgi.async_connect(addr) """ fd = lib.uwsgi_connect(ffi.new('char[]', addr), 0, 1) if fd < 0: raise Exception("unable to connect to %s" % addr) return fd uwsgi.async_connect = uwsgi_pypy_async_connect uwsgi.connection_fd = lambda: uwsgi_pypy_current_wsgi_req().fd def uwsgi_pypy_wait_fd_read(fd, timeout=0): """ uwsgi.wait_fd_read(fd, timeout=0) """ wsgi_req = uwsgi_pypy_current_wsgi_req() if lib.async_add_fd_read(wsgi_req, fd, timeout) < 0: raise Exception("unable to add fd %d to the event queue" % fd) uwsgi.wait_fd_read = uwsgi_pypy_wait_fd_read def uwsgi_pypy_wait_fd_write(fd, timeout=0): """ uwsgi.wait_fd_write(fd, timeout=0) """ wsgi_req = uwsgi_pypy_current_wsgi_req() if lib.async_add_fd_write(wsgi_req, fd, timeout) < 0: raise Exception("unable to add fd %d to the event queue" % fd) uwsgi.wait_fd_write = uwsgi_pypy_wait_fd_write def uwsgi_pypy_ready_fd(): """ uwsgi.ready_fd() """ wsgi_req = uwsgi_pypy_current_wsgi_req() return lib.uwsgi_ready_fd(wsgi_req) uwsgi.ready_fd = uwsgi_pypy_ready_fd def uwsgi_pypy_send(*args): """ uwsgi.send(fd=None,data) """ if len(args) == 0: raise ValueError("uwsgi.send() takes at least 1 argument") elif len(args) == 1: wsgi_req = uwsgi_pypy_current_wsgi_req() fd = wsgi_req.fd data = args[0] else: fd = args[0] data = args[1] rlen = libc.write(fd, data, len(data)) if rlen <= 0: raise IOError("unable to send data") return rlen uwsgi.send = uwsgi_pypy_send def uwsgi_pypy_recv(*args): """ uwsgi.recv(fd=None,len) """ if len(args) == 0: raise ValueError("uwsgi.recv() takes at least 1 argument") elif len(args) == 1: wsgi_req = uwsgi_pypy_current_wsgi_req() fd = wsgi_req.fd l = args[0] else: fd = args[0] l = args[1] data = ffi.new('char[%d]' % l) rlen = libc.read(fd, data, l) if rlen <= 0: raise IOError("unable to receive data") return ffi.string(data[0:rlen]) uwsgi.recv = uwsgi_pypy_recv """ uwsgi.close(fd) """ uwsgi.close = lambda fd: lib.close(fd) """ uwsgi.disconnect() """ uwsgi.disconnect = lambda: lib.uwsgi_disconnect(uwsgi_pypy_current_wsgi_req()) def uwsgi_pypy_websocket_recv(): """ uwsgi.websocket_recv() """ wsgi_req = uwsgi_pypy_current_wsgi_req() ub = lib.uwsgi_websocket_recv(wsgi_req) if ub == ffi.NULL: raise IOError("unable to receive websocket message") ret = ffi.buffer(ub.buf, ub.pos)[:] lib.uwsgi_buffer_destroy(ub) return ret uwsgi.websocket_recv = uwsgi_pypy_websocket_recv def uwsgi_pypy_websocket_recv_nb(): """ uwsgi.websocket_recv_nb() """ wsgi_req = uwsgi_pypy_current_wsgi_req() ub = lib.uwsgi_websocket_recv_nb(wsgi_req) if ub == ffi.NULL: raise IOError("unable to receive websocket message") ret = ffi.buffer(ub.buf, ub.pos)[:] lib.uwsgi_buffer_destroy(ub) return ret uwsgi.websocket_recv_nb = uwsgi_pypy_websocket_recv_nb def uwsgi_pypy_websocket_handshake(key='', origin='', proto=''): """ uwsgi.websocket_handshake(key, origin) """ wsgi_req = uwsgi_pypy_current_wsgi_req() c_key = ffi.new('char[]', key) c_origin = ffi.new('char[]', origin) c_proto = ffi.new('char[]', proto) if lib.uwsgi_websocket_handshake(wsgi_req, c_key, len(key), c_origin, len(origin), c_proto, len(proto)) < 0: raise IOError("unable to complete websocket handshake") uwsgi.websocket_handshake = uwsgi_pypy_websocket_handshake def uwsgi_pypy_websocket_send(msg): """ uwsgi.websocket_send(msg) """ wsgi_req = uwsgi_pypy_current_wsgi_req() if lib.uwsgi_websocket_send(wsgi_req, ffi.new('char[]', msg), len(msg)) < 0: raise IOError("unable to send websocket message") uwsgi.websocket_send = uwsgi_pypy_websocket_send def uwsgi_pypy_chunked_read(timeout=0): """ uwsgi.chunked_read(timeout=0) """ wsgi_req = uwsgi_pypy_current_wsgi_req() rlen = ffi.new("size_t*") chunk = lib.uwsgi_chunked_read(wsgi_req, rlen, timeout, 0) if chunk == ffi.NULL: raise IOError("unable to receive chunked part") return ffi.buffer(chunk, rlen[0])[:] uwsgi.chunked_read = uwsgi_pypy_chunked_read def uwsgi_pypy_chunked_read_nb(): """ uwsgi.chunked_read_nb() """ wsgi_req = uwsgi_pypy_current_wsgi_req() rlen = ffi.new("size_t*") chunk = lib.uwsgi_chunked_read(wsgi_req, rlen, 0, 1) if chunk == ffi.NULL: if lib.uwsgi_is_again() > 0: return None raise IOError("unable to receive chunked part") return ffi.buffer(chunk, rlen[0])[:] uwsgi.chunked_read_nb = uwsgi_pypy_chunked_read_nb """ uwsgi.set_user_harakiri(sec) """ uwsgi.set_user_harakiri = lambda x: lib.set_user_harakiri(x) def uwsgi_pypy_get_logvar(key): """ uwsgi.get_logvar(key) """ wsgi_req = uwsgi_pypy_current_wsgi_req() c_key = ffi.new('char[]', key) lv = lib.uwsgi_logvar_get(wsgi_req, c_key, len(key)) if lv: return ffi.string(lv.val[0:lv.vallen]) return None uwsgi.get_logvar = uwsgi_pypy_get_logvar def uwsgi_pypy_set_logvar(key, val): """ uwsgi.set_logvar(key, value) """ wsgi_req = uwsgi_pypy_current_wsgi_req() c_key = ffi.new('char[]', key) c_val = ffi.new('char[]', val) lib.uwsgi_logvar_add(wsgi_req, c_key, len(key), c_val, len(val)) uwsgi.set_logvar = uwsgi_pypy_set_logvar print("Initialized PyPy with Python %s" % sys.version) print("PyPy Home: %s" % sys.prefix) """ Continulets support """ # this is the dictionary of continulets (one per-core) uwsgi_pypy_continulets = {} def uwsgi_pypy_continulet_wrapper(cont): lib.async_schedule_to_req_green() @ffi.callback("void()") def uwsgi_pypy_continulet_schedule(): id = lib.uwsgi.wsgi_req.async_id modifier1 = lib.uwsgi.wsgi_req.uh.modifier1 # generate a new continulet if not lib.uwsgi.wsgi_req.suspended: from _continuation import continulet uwsgi_pypy_continulets[id] = continulet(uwsgi_pypy_continulet_wrapper) lib.uwsgi.wsgi_req.suspended = 1 # this is called in the main stack if lib.uwsgi.p[modifier1].suspend: lib.uwsgi.p[modifier1].suspend(ffi.NULL) # let's switch uwsgi_pypy_continulets[id].switch() # back to the main stack if lib.uwsgi.p[modifier1].resume: lib.uwsgi.p[modifier1].resume(ffi.NULL) @ffi.callback("void(struct wsgi_request *)") def uwsgi_pypy_continulet_switch(wsgi_req): id = wsgi_req.async_id modifier1 = wsgi_req.uh.modifier1 # this is called in the current continulet if lib.uwsgi.p[modifier1].suspend: lib.uwsgi.p[modifier1].suspend(wsgi_req) uwsgi_pypy_continulets[id].switch() # back to the continulet if lib.uwsgi.p[modifier1].resume: lib.uwsgi.p[modifier1].resume(wsgi_req) # update current running continulet lib.uwsgi.wsgi_req = wsgi_req def uwsgi_pypy_setup_continulets(): if lib.uwsgi["async"] < 1: raise Exception("pypy continulets require async mode !!!") lib.uwsgi.schedule_to_main = uwsgi_pypy_continulet_switch lib.uwsgi.schedule_to_req = uwsgi_pypy_continulet_schedule print("*** PyPy Continulets engine loaded ***") uwsgi-2.0.29/plugins/pypy/uwsgiplugin.py000066400000000000000000000003711477626554400204000ustar00rootroot00000000000000NAME='pypy' LDFLAGS = [] LIBS = [] GCC_LIST = ['pypy_plugin'] BINARY_LIST = [ ('_uwsgi_pypy_setup','pypy_setup.py')] CFLAGS = [] try: import __pypy__ import sys CFLAGS.append('-DUWSGI_PYPY_HOME="\\"%s\\""' % sys.prefix) except: pass uwsgi-2.0.29/plugins/python/000077500000000000000000000000001477626554400157705ustar00rootroot00000000000000uwsgi-2.0.29/plugins/python/gil.c000066400000000000000000000013711477626554400167110ustar00rootroot00000000000000#include "uwsgi_python.h" extern struct uwsgi_server uwsgi; extern struct uwsgi_python up; void gil_real_get() { //uwsgi_log("LOCK %d\n", uwsgi.mywid); #if !defined(PYTHREE) PyEval_AcquireLock(); PyThreadState_Swap((PyThreadState *) pthread_getspecific(up.upt_gil_key)); #else PyEval_RestoreThread((PyThreadState *) pthread_getspecific(up.upt_gil_key)); #endif //uwsgi_log("LOCKED !!! %d\n", uwsgi.mywid); } void gil_real_release() { //uwsgi_log("UNLOCK %d\n", uwsgi.mywid); #if !defined(PYTHREE) pthread_setspecific(up.upt_gil_key, (void *) PyThreadState_Swap(NULL)); PyEval_ReleaseLock(); #else pthread_setspecific(up.upt_gil_key, (void *) PyThreadState_Get()); PyEval_SaveThread(); #endif } void gil_fake_get() {} void gil_fake_release() {} uwsgi-2.0.29/plugins/python/profiler.c000066400000000000000000000046041477626554400177620ustar00rootroot00000000000000#include "uwsgi_python.h" extern struct uwsgi_server uwsgi; #ifdef HAS_NOT_PyFrame_GetLineNumber int PyFrame_GetLineNumber(PyFrameObject *frame) { if (frame->f_trace) { return frame->f_lineno; } else { return PyCode_Addr2Line(frame->f_code, frame->f_lasti); } } #endif #if PY_VERSION_HEX < 0x030900B1 PyCodeObject* PyFrame_GetCode(PyFrameObject *frame) { Py_INCREF(frame->f_code); return frame->f_code; } #endif #ifdef PYTHREE #undef PyString_AsString static char *PyString_AsString(PyObject *o) { PyObject *zero = PyUnicode_AsLatin1String(o); if (!zero) return ""; return PyBytes_AsString(zero); } #endif int uwsgi_python_profiler_call(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg) { static uint64_t last_ts = 0; uint64_t now = uwsgi_micros(); uint64_t delta = 0; PyCodeObject *code; switch(what) { case PyTrace_CALL: if (last_ts == 0) delta = 0; else delta = now - last_ts; last_ts = now; code = PyFrame_GetCode(frame); uwsgi_log("[uWSGI Python profiler %llu] CALL: %s (line %d) -> %s %d args, stacksize %d\n", (unsigned long long) delta, PyString_AsString(code->co_filename), PyFrame_GetLineNumber(frame), PyString_AsString(code->co_name), code->co_argcount, code->co_stacksize); Py_DECREF(code); break; case PyTrace_C_CALL: if (last_ts == 0) delta = 0; else delta = now - last_ts; last_ts = now; code = PyFrame_GetCode(frame); uwsgi_log("[uWSGI Python profiler %llu] C CALL: %s (line %d) -> %s %d args, stacksize %d\n", (unsigned long long) delta, PyString_AsString(code->co_filename), PyFrame_GetLineNumber(frame), PyEval_GetFuncName(arg), code->co_argcount, code->co_stacksize); Py_DECREF(code); break; } return 0; } int uwsgi_python_tracer(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg) { static uint64_t last_ts = 0; uint64_t now = uwsgi_micros(); uint64_t delta = 0; if (what == PyTrace_LINE) { if (last_ts == 0) { delta = 0; } else { delta = now - last_ts; } last_ts = now; PyCodeObject *code = PyFrame_GetCode(frame); uwsgi_log("[uWSGI Python profiler %llu] file %s line %d: %s argc:%d\n", (unsigned long long)delta, PyString_AsString(code->co_filename), PyFrame_GetLineNumber(frame), PyString_AsString(code->co_name), code->co_argcount); Py_DECREF(code); } return 0; } uwsgi-2.0.29/plugins/python/pump_subhandler.c000066400000000000000000000226741477626554400213370ustar00rootroot00000000000000#include "uwsgi_python.h" extern struct uwsgi_server uwsgi; extern struct uwsgi_python up; extern PyTypeObject uwsgi_InputType; void *uwsgi_request_subhandler_pump(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) { PyObject *zero; int i; PyObject *pydictkey, *pydictvalue; char *port = memchr(wsgi_req->host, ':', wsgi_req->host_len); if (port) { zero = PyString_FromStringAndSize(wsgi_req->host, (port-wsgi_req->host)); PyDict_SetItemString(wsgi_req->async_environ, "server_name", zero); Py_DECREF(zero); zero = PyString_FromStringAndSize(port, wsgi_req->host_len-((port+1)-wsgi_req->host)); PyDict_SetItemString(wsgi_req->async_environ, "server_port", zero); Py_DECREF(zero); } else { zero = PyString_FromStringAndSize(wsgi_req->host, wsgi_req->host_len); PyDict_SetItemString(wsgi_req->async_environ, "server_name", zero); Py_DECREF(zero); zero = PyString_FromStringAndSize("80", 2); PyDict_SetItemString(wsgi_req->async_environ, "server_port", zero); Py_DECREF(zero); } zero = PyString_FromStringAndSize(wsgi_req->remote_addr, wsgi_req->remote_addr_len); PyDict_SetItemString(wsgi_req->async_environ, "remote_addr", zero); Py_DECREF(zero); zero = PyString_FromStringAndSize(wsgi_req->path_info, wsgi_req->path_info_len); PyDict_SetItemString(wsgi_req->async_environ, "uri", zero); Py_DECREF(zero); if (wsgi_req->query_string_len > 0) { zero = PyString_FromStringAndSize(wsgi_req->query_string, wsgi_req->query_string_len); PyDict_SetItemString(wsgi_req->async_environ, "query_string", zero); Py_DECREF(zero); } zero = PyString_FromStringAndSize(uwsgi_lower(wsgi_req->method, wsgi_req->method_len), wsgi_req->method_len); PyDict_SetItemString(wsgi_req->async_environ, "method", zero); Py_DECREF(zero); if (wsgi_req->post_cl > 0) { PyDict_SetItemString(wsgi_req->async_environ, "content_length", PyInt_FromLong(wsgi_req->post_cl)); if (wsgi_req->content_type_len > 0) { zero = PyString_FromStringAndSize(wsgi_req->content_type, wsgi_req->content_type_len); PyDict_SetItemString(wsgi_req->async_environ, "content_type", zero); Py_DECREF(zero); } } PyObject *headers = PyDict_New(); for (i = 0; i < wsgi_req->var_cnt; i += 2) { #ifdef UWSGI_DEBUG uwsgi_debug("%.*s: %.*s\n", wsgi_req->hvec[i].iov_len, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i+1].iov_len, wsgi_req->hvec[i+1].iov_base); #endif if (wsgi_req->hvec[i].iov_len < 6) continue; if (!uwsgi_startswith(wsgi_req->hvec[i].iov_base, "HTTP_", 5)) { (void) uwsgi_lower(wsgi_req->hvec[i].iov_base+5, wsgi_req->hvec[i].iov_len-5); #ifdef PYTHREE pydictkey = PyUnicode_DecodeLatin1(wsgi_req->hvec[i].iov_base+5, wsgi_req->hvec[i].iov_len-5, NULL); pydictvalue = PyUnicode_DecodeLatin1(wsgi_req->hvec[i + 1].iov_base, wsgi_req->hvec[i + 1].iov_len, NULL); #else pydictkey = PyString_FromStringAndSize(wsgi_req->hvec[i].iov_base+5, wsgi_req->hvec[i].iov_len-5); pydictvalue = PyString_FromStringAndSize(wsgi_req->hvec[i + 1].iov_base, wsgi_req->hvec[i + 1].iov_len); #endif PyObject *old_value = PyDict_GetItem(headers, pydictkey); if (old_value) { if (PyString_Check(old_value)) { PyObject *new_value = PyList_New(0); PyList_Append(new_value, old_value); old_value = new_value; PyDict_SetItem(headers, pydictkey, old_value); Py_DECREF(old_value); } PyList_Append(old_value, pydictvalue); } else { PyDict_SetItem(headers, pydictkey, pydictvalue); } Py_DECREF(pydictkey); Py_DECREF(pydictvalue); } } PyDict_SetItemString(wsgi_req->async_environ, "headers", headers); Py_DECREF(headers); // create wsgi.input custom object wsgi_req->async_input = (PyObject *) PyObject_New(uwsgi_Input, &uwsgi_InputType); ((uwsgi_Input*)wsgi_req->async_input)->wsgi_req = wsgi_req; PyDict_SetItemString(wsgi_req->async_environ, "body", wsgi_req->async_input); if (wsgi_req->scheme_len > 0) { zero = PyString_FromStringAndSize(wsgi_req->scheme, wsgi_req->scheme_len); } else if (wsgi_req->https_len > 0) { if (!strncasecmp(wsgi_req->https, "on", 2) || wsgi_req->https[0] == '1') { zero = PyString_FromString("https"); } else { zero = PyString_FromString("http"); } } else { zero = PyString_FromString("http"); } PyDict_SetItemString(wsgi_req->async_environ, "scheme", zero); Py_DECREF(zero); wsgi_req->async_app = wi->callable; // export .env only in non-threaded mode if (uwsgi.threads < 2) { PyDict_SetItemString(up.embedded_dict, "env", wsgi_req->async_environ); } PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.version", wi->uwsgi_version); if (uwsgi.cores > 1) { PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.core", PyInt_FromLong(wsgi_req->async_id)); } PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.node", wi->uwsgi_node); // call if (PyTuple_GetItem(wsgi_req->async_args, 0) != wsgi_req->async_environ) { if (PyTuple_SetItem(wsgi_req->async_args, 0, wsgi_req->async_environ)) { uwsgi_log_verbose("unable to set environ to the python application callable, consider using the holy env allocator\n"); return NULL; } } return python_call(wsgi_req->async_app, wsgi_req->async_args, uwsgi.catch_exceptions, wsgi_req); } int uwsgi_response_subhandler_pump(struct wsgi_request *wsgi_req) { PyObject *pychunk; int i; char sc[4]; // ok its a yield if (!wsgi_req->async_placeholder) { if (PyDict_Check((PyObject *)wsgi_req->async_result)) { PyObject *status = PyDict_GetItemString((PyObject *)wsgi_req->async_result, "status"); if (!status) { uwsgi_log("invalid Pump response (status code).\n"); goto clear; } PyObject *headers = PyDict_GetItemString((PyObject *)wsgi_req->async_result, "headers"); if (!headers) { uwsgi_log("invalid Pump response (headers).\n"); goto clear; } wsgi_req->async_placeholder = PyDict_GetItemString((PyObject *)wsgi_req->async_result, "body"); if (!wsgi_req->async_placeholder) { uwsgi_log("invalid Pump response (body).\n"); goto clear; } // get the status code if (!PyInt_Check(status)) { uwsgi_log("invalid Pump response (status code).\n"); goto clear; } if (uwsgi_num2str2n(PyInt_AsLong(status), sc, 4) != 3) { uwsgi_log("invalid Pump response (status code).\n"); goto clear; } if (uwsgi_response_prepare_headers(wsgi_req, sc, 3)) { uwsgi_log("unable to prepare response headers\n"); } PyObject *hhkey, *hhvalue; #ifdef UWSGI_PYTHON_OLD int hhpos = 0; #else Py_ssize_t hhpos = 0; #endif while (PyDict_Next(headers, &hhpos, &hhkey, &hhvalue)) { if (!PyString_Check(hhkey)) continue; char *k = PyString_AsString(hhkey); size_t kl = PyString_Size(hhkey); k[0] = toupper((int) k[0]); if (PyList_Check(hhvalue)) { for(i=0;iasync_placeholder); if (PyString_Check((PyObject *)wsgi_req->async_placeholder)) { UWSGI_RELEASE_GIL uwsgi_response_write_body_do(wsgi_req, PyString_AsString(wsgi_req->async_placeholder), PyString_Size(wsgi_req->async_placeholder)); UWSGI_GET_GIL uwsgi_py_check_write_errors { uwsgi_py_write_exception(wsgi_req); } goto clear; } #ifdef PYTHREE else if ((wsgi_req->sendfile_fd = PyObject_AsFileDescriptor((PyObject *)wsgi_req->async_placeholder)) > -1) { #else else if (PyFile_Check((PyObject *)wsgi_req->async_placeholder)) { wsgi_req->sendfile_fd = fileno(PyFile_AsFile((PyObject *)wsgi_req->async_placeholder)); #endif UWSGI_RELEASE_GIL uwsgi_response_sendfile_do(wsgi_req, wsgi_req->sendfile_fd, 0, 0); UWSGI_GET_GIL uwsgi_py_check_write_errors { uwsgi_py_write_exception(wsgi_req); } goto clear; } PyObject *tmp = (PyObject *)wsgi_req->async_placeholder; wsgi_req->async_placeholder = PyObject_GetIter( (PyObject *)wsgi_req->async_placeholder ); Py_DECREF(tmp); if (!wsgi_req->async_placeholder) { goto clear; } if (uwsgi.async > 1) { return UWSGI_AGAIN; } } else { uwsgi_log("invalid Pump response.\n"); goto clear; } } pychunk = PyIter_Next(wsgi_req->async_placeholder); if (!pychunk) { if (PyErr_Occurred()) { uwsgi_manage_exception(wsgi_req, uwsgi.catch_exceptions); } goto clear; } if (PyString_Check(pychunk)) { UWSGI_RELEASE_GIL uwsgi_response_write_body_do(wsgi_req, PyString_AsString(pychunk), PyString_Size(pychunk)); UWSGI_GET_GIL uwsgi_py_check_write_errors { uwsgi_py_write_exception(wsgi_req); Py_DECREF(pychunk); goto clear; } } Py_DECREF(pychunk); return UWSGI_AGAIN; clear: Py_XDECREF((PyObject *)wsgi_req->async_placeholder); Py_DECREF((PyObject *)wsgi_req->async_result); PyErr_Clear(); return UWSGI_OK; } uwsgi-2.0.29/plugins/python/pyloader.c000066400000000000000000000526561477626554400177710ustar00rootroot00000000000000#include "uwsgi_python.h" /* notes exit(1) on every malloc error: apps can be dinamically loaded so on memory problem it is better to let the master process manager respawn the worker. TODO dynamic loading on prefork+thread looks flaky... NEED TO FIX IT */ extern struct uwsgi_server uwsgi; extern struct uwsgi_python up; extern struct uwsgi_plugin python_plugin; extern char **environ; PyMethodDef uwsgi_sendfile_method[] = {{"uwsgi_sendfile", py_uwsgi_sendfile, METH_VARARGS, ""}}; PyMethodDef uwsgi_eventfd_read_method[] = { {"uwsgi_eventfd_read", py_eventfd_read, METH_VARARGS, ""}}; PyMethodDef uwsgi_eventfd_write_method[] = { {"uwsgi_eventfd_write", py_eventfd_write, METH_VARARGS, ""}}; void set_dyn_pyhome(char *home, uint16_t pyhome_len) { char venv_version[30]; PyObject *site_module; PyObject *pysys_dict = get_uwsgi_pydict("sys"); PyObject *pypath = PyDict_GetItemString(pysys_dict, "path"); if (!pypath) { PyErr_Print(); exit(1); } // simulate a pythonhome directive if (uwsgi.wsgi_req->home_len > 0) { PyObject *venv_path = UWSGI_PYFROMSTRINGSIZE(uwsgi.wsgi_req->home, uwsgi.wsgi_req->home_len); #ifdef UWSGI_DEBUG uwsgi_debug("setting dynamic virtualenv to %.*s\n", uwsgi.wsgi_req->home_len, uwsgi.wsgi_req->home); #endif PyDict_SetItemString(pysys_dict, "prefix", venv_path); PyDict_SetItemString(pysys_dict, "exec_prefix", venv_path); bzero(venv_version, 30); if (snprintf(venv_version, 30, "/lib/python%d.%d", PY_MAJOR_VERSION, PY_MINOR_VERSION) == -1) { return; } // check here PyString_Concat(&venv_path, PyString_FromString(venv_version)); if (PyList_Insert(pypath, 0, venv_path)) { PyErr_Print(); } site_module = PyImport_ImportModule("site"); if (site_module) { PyImport_ReloadModule(site_module); } } } int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThreadState *interpreter, int app_type) { PyObject *app_list = NULL, *applications = NULL; if (uwsgi_apps_cnt >= uwsgi.max_apps) { uwsgi_log("ERROR: you cannot load more than %d apps in a worker\n", uwsgi.max_apps); return -1; } int id = uwsgi_apps_cnt; int multiapp = 0; int i; struct uwsgi_app *wi; time_t now = uwsgi_now(); if (uwsgi_get_app_id(NULL, wsgi_req->appid, wsgi_req->appid_len, -1) != -1) { uwsgi_log( "mountpoint %.*s already configured. skip.\n", wsgi_req->appid_len, wsgi_req->appid); return -1; } wi = &uwsgi_apps[id]; memset(wi, 0, sizeof(struct uwsgi_app)); wi->modifier1 = python_plugin.modifier1; wi->mountpoint_len = wsgi_req->appid_len < 0xff ? wsgi_req->appid_len : (0xff-1); if (wi->mountpoint_len > 0) { strncpy(wi->mountpoint, wsgi_req->appid, wi->mountpoint_len); } // dynamic chdir ? if (wsgi_req->chdir_len > 0) { strncpy(wi->chdir, wsgi_req->chdir, wsgi_req->chdir_len < 0xff ? wsgi_req->chdir_len : (0xff-1)); #ifdef UWSGI_DEBUG uwsgi_debug("chdir to %s\n", wi->chdir); #endif if (chdir(wi->chdir)) { uwsgi_error("chdir()"); } } // Initialize a new environment for the new interpreter // reload "os" environ to allow dynamic setenv() if (up.reload_os_env) { char **e, *p; PyObject *k, *env_value; PyObject *os_module = PyImport_ImportModule("os"); if (os_module) { PyObject *os_module_dict = PyModule_GetDict(os_module); PyObject *py_environ = PyDict_GetItemString(os_module_dict, "environ"); if (py_environ) { for (e = environ; *e != NULL; e++) { p = strchr(*e, '='); if (p == NULL) continue; #ifdef PYTHREE k = PyUnicode_FromStringAndSize(*e, (int)(p-*e)); #else k = PyString_FromStringAndSize(*e, (int)(p-*e)); #endif if (k == NULL) { PyErr_Print(); continue; } #ifdef PYTHREE env_value = PyUnicode_FromString(p+1); #else env_value = PyString_FromString(p+1); #endif if (env_value == NULL) { PyErr_Print(); Py_DECREF(k); continue; } #ifdef UWSGI_DEBUG #ifdef PYTHREE uwsgi_log("%s = %s\n", PyUnicode_AsUTF8(k), PyUnicode_AsUTF8(env_value)); #else uwsgi_log("%s = %s\n", PyString_AsString(k), PyString_AsString(env_value)); #endif #endif if (PyObject_SetItem(py_environ, k, env_value)) { PyErr_Print(); } Py_DECREF(k); Py_DECREF(env_value); } } } } if (interpreter == NULL && id) { wi->interpreter = Py_NewInterpreter(); if (!wi->interpreter) { uwsgi_log( "unable to initialize the new python interpreter\n"); exit(1); } PyThreadState_Swap(wi->interpreter); init_pyargv(); // we need to initialize an embedded module for every interpreter init_uwsgi_embedded_module(); init_uwsgi_vars(); } else if (interpreter) { wi->interpreter = interpreter; } else { wi->interpreter = up.main_thread; } if (wsgi_req->home_len) { set_dyn_pyhome(wsgi_req->home, wsgi_req->home_len); } if (wsgi_req->touch_reload_len > 0 && wsgi_req->touch_reload_len < 0xff) { struct stat trst; strncpy(wi->touch_reload, wsgi_req->touch_reload, wsgi_req->touch_reload_len); if (!stat(wi->touch_reload, &trst)) { wi->touch_reload_mtime = trst.st_mtime; } } wi->callable = up.loaders[loader](arg1); if (!wi->callable) { uwsgi_log("unable to load app %d (mountpoint='%s') (callable not found or import error)\n", id, wi->mountpoint); goto doh; } // the module contains multiple apps if (PyDict_Check((PyObject *)wi->callable)) { applications = wi->callable; uwsgi_log("found a multiapp module...\n"); app_list = PyDict_Keys(applications); multiapp = PyList_Size(app_list); if (multiapp < 1) { uwsgi_log("you have to define at least one app in the applications dictionary\n"); goto doh; } PyObject *app_mnt = PyList_GetItem(app_list, 0); if (!PyString_Check(app_mnt)) { uwsgi_log("the app mountpoint must be a string\n"); goto doh; } char *tmp_mountpoint = PyString_AsString(app_mnt); wi->mountpoint_len = strlen(wi->mountpoint) < 0xff ? strlen(wi->mountpoint) : (0xff-1); strncpy(wi->mountpoint, tmp_mountpoint, wi->mountpoint_len); wsgi_req->appid = wi->mountpoint; wsgi_req->appid_len = wi->mountpoint_len; #ifdef UWSGI_DEBUG uwsgi_log("main mountpoint = %s\n", wi->mountpoint); #endif wi->callable = PyDict_GetItem(applications, app_mnt); if (PyString_Check((PyObject *) wi->callable)) { PyObject *callables_dict = get_uwsgi_pydict((char *)arg1); if (callables_dict) { wi->callable = PyDict_GetItem(callables_dict, (PyObject *)wi->callable); if (!wi->callable) { uwsgi_log("skipping broken app %s\n", wsgi_req->appid); goto multiapp; } } } } Py_INCREF((PyObject *)wi->callable); wi->environ = malloc(sizeof(PyObject*)*uwsgi.cores); if (!wi->environ) { uwsgi_error("malloc()"); exit(1); } for(i=0;ienviron[i] = PyDict_New(); if (!wi->environ[i]) { uwsgi_log("unable to allocate new env dictionary for app\n"); exit(1); } } wi->argc = 1; if (app_type == PYTHON_APP_TYPE_WSGI) { #ifdef UWSGI_DEBUG uwsgi_log("-- WSGI callable selected --\n"); #endif wi->request_subhandler = uwsgi_request_subhandler_wsgi; wi->response_subhandler = uwsgi_response_subhandler_wsgi; wi->argc = 2; } else if (app_type == PYTHON_APP_TYPE_WEB3) { #ifdef UWSGI_DEBUG uwsgi_log("-- Web3 callable selected --\n"); #endif wi->request_subhandler = uwsgi_request_subhandler_web3; wi->response_subhandler = uwsgi_response_subhandler_web3; } else if (app_type == PYTHON_APP_TYPE_PUMP) { #ifdef UWSGI_DEBUG uwsgi_log("-- Pump callable selected --\n"); #endif wi->request_subhandler = uwsgi_request_subhandler_pump; wi->response_subhandler = uwsgi_response_subhandler_pump; } wi->args = malloc(sizeof(PyObject*)*uwsgi.cores); if (!wi->args) { uwsgi_error("malloc()"); exit(1); } for(i=0;iargs[i] = PyTuple_New(wi->argc); if (!wi->args[i]) { uwsgi_log("unable to allocate new tuple for app args\n"); exit(1); } Py_INCREF(Py_None); PyTuple_SetItem(wi->args[i], 0, Py_None); // add start_response on WSGI app if (app_type == PYTHON_APP_TYPE_WSGI) { Py_INCREF((PyObject *)up.wsgi_spitout); if (PyTuple_SetItem(wi->args[i], 1, up.wsgi_spitout)) { uwsgi_log("unable to set start_response in args tuple\n"); exit(1); } } } if (app_type == PYTHON_APP_TYPE_WSGI) { // prepare sendfile() for WSGI app wi->sendfile = PyCFunction_New(uwsgi_sendfile_method, NULL); wi->eventfd_read = PyCFunction_New(uwsgi_eventfd_read_method, NULL); wi->eventfd_write = PyCFunction_New(uwsgi_eventfd_write_method, NULL); } // cache most used values wi->error = PyFile_FromFile(stderr, "wsgi_errors", "w", NULL); Py_INCREF((PyObject *)wi->error); wi->gateway_version = PyTuple_New(2); PyTuple_SetItem(wi->gateway_version, 0, PyInt_FromLong(1)); PyTuple_SetItem(wi->gateway_version, 1, PyInt_FromLong(0)); Py_INCREF((PyObject *)wi->gateway_version); wi->uwsgi_version = PyString_FromString(UWSGI_VERSION); Py_INCREF((PyObject *)wi->uwsgi_version); wi->uwsgi_node = PyString_FromString(uwsgi.hostname); Py_INCREF((PyObject *)wi->uwsgi_node); if (uwsgi.threads > 1 && id) { // if we have multiple threads we need to initialize a PyThreadState for each one for(i=0;iinterpreter)->interp); //uwsgi_log("%p\n", uwsgi.workers[uwsgi.mywid].cores[i].ts[id]); if (!uwsgi.workers[uwsgi.mywid].cores[i].ts[id]) { uwsgi_log("unable to allocate new PyThreadState structure for app %s", wi->mountpoint); goto doh; } // cow ? if (uwsgi.mywid == 0) { int j; for(j=1;j<=uwsgi.numproc;j++) { uwsgi.workers[j].cores[i].ts[id] = uwsgi.workers[0].cores[i].ts[id]; } } } PyThreadState_Swap((PyThreadState *) pthread_getspecific(up.upt_save_key) ); } else if (interpreter == NULL && id) { PyThreadState_Swap(up.main_thread); } const char *default_app = ""; if (!uwsgi.no_default_app) { if ((wsgi_req->appid_len == 0 || (wsgi_req->appid_len = 1 && wsgi_req->appid[0] == '/')) && uwsgi.default_app == -1) { default_app = " (default app)" ; uwsgi.default_app = id; } } wi->started_at = now; wi->startup_time = uwsgi_now() - now; if (app_type == PYTHON_APP_TYPE_WSGI) { uwsgi_log( "WSGI app %d (mountpoint='%.*s') ready in %d seconds on interpreter %p pid: %d%s\n", id, wi->mountpoint_len, wi->mountpoint, (int) wi->startup_time, wi->interpreter, (int) getpid(), default_app); } else if (app_type == PYTHON_APP_TYPE_WEB3) { uwsgi_log( "Web3 app %d (mountpoint='%.*s') ready in %d seconds on interpreter %p pid: %d%s\n", id, wi->mountpoint_len, wi->mountpoint, (int) wi->startup_time, wi->interpreter, (int) getpid(), default_app); } else if (app_type == PYTHON_APP_TYPE_PUMP) { uwsgi_log( "Pump app %d (mountpoint='%.*s') ready in %d seconds on interpreter %p pid: %d%s\n", id, wi->mountpoint_len, wi->mountpoint, (int) wi->startup_time, wi->interpreter, (int) getpid(), default_app); } uwsgi_apps_cnt++; multiapp: if (multiapp > 1) { for(i=1;iappid = PyString_AsString(app_mnt); wsgi_req->appid_len = strlen(wsgi_req->appid); PyObject *a_callable = PyDict_GetItem(applications, app_mnt); if (PyString_Check(a_callable)) { PyObject *callables_dict = get_uwsgi_pydict((char *)arg1); if (callables_dict) { a_callable = PyDict_GetItem(callables_dict, a_callable); } } if (!a_callable) { uwsgi_log("skipping broken app %s\n", wsgi_req->appid); continue; } init_uwsgi_app(LOADER_CALLABLE, a_callable, wsgi_req, wi->interpreter, app_type); } } // emulate COW uwsgi_emulate_cow_for_apps(id); return id; doh: if (PyErr_Occurred()) PyErr_Print(); if (interpreter == NULL && id) { Py_EndInterpreter(wi->interpreter); if (uwsgi.threads > 1) { PyThreadState_Swap((PyThreadState *) pthread_getspecific(up.upt_save_key)); } else { PyThreadState_Swap(up.main_thread); } } return -1; } char *get_uwsgi_pymodule(char *module) { char *quick_callable; if ( (quick_callable = strchr(module, ':')) ) { quick_callable[0] = 0; quick_callable++; return quick_callable; } return NULL; } PyObject *get_uwsgi_pydict(char *module) { PyObject *wsgi_module, *wsgi_dict; wsgi_module = PyImport_ImportModule(module); if (!wsgi_module) { PyErr_Print(); return NULL; } wsgi_dict = PyModule_GetDict(wsgi_module); if (!wsgi_dict) { PyErr_Print(); return NULL; } return wsgi_dict; } PyObject *uwsgi_uwsgi_loader(void *arg1) { PyObject *wsgi_dict; char *quick_callable; PyObject *tmp_callable; PyObject *applications; PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi"); char *module = (char *) arg1; quick_callable = get_uwsgi_pymodule(module); if (quick_callable == NULL) { if (up.callable) { quick_callable = up.callable; } else { quick_callable = "application"; } wsgi_dict = get_uwsgi_pydict(module); } else { wsgi_dict = get_uwsgi_pydict(module); module[strlen(module)] = ':'; } if (!wsgi_dict) { return NULL; } applications = PyDict_GetItemString(uwsgi_dict, "applications"); if (applications && PyDict_Check(applications)) return applications; applications = PyDict_GetItemString(wsgi_dict, "applications"); if (applications && PyDict_Check(applications)) return applications; // quick callable -> thanks gunicorn for the idea // we have extended the concept a bit... if (quick_callable[strlen(quick_callable) -2 ] == '(' && quick_callable[strlen(quick_callable) -1] ==')') { quick_callable[strlen(quick_callable) -2 ] = 0; tmp_callable = PyDict_GetItemString(wsgi_dict, quick_callable); quick_callable[strlen(quick_callable)] = '('; if (tmp_callable) { return python_call(tmp_callable, PyTuple_New(0), 0, NULL); } } return PyDict_GetItemString(wsgi_dict, quick_callable); } /* this is the mount loader, it loads app on mountpoint automagically */ PyObject *uwsgi_mount_loader(void *arg1) { PyObject *callable = NULL; char *what = (char *) arg1; if ( !strcmp(what+strlen(what)-3, ".py") || !strcmp(what+strlen(what)-5, ".wsgi")) { callable = uwsgi_file_loader((void *)what); if (!callable) exit(UWSGI_FAILED_APP_CODE); } else if (!strcmp(what+strlen(what)-4, ".ini")) { callable = uwsgi_paste_loader((void *)what); } else if (strchr(what, ':')) { callable = uwsgi_uwsgi_loader((void *)what); } return callable; } /* this is the dynamic loader, it loads app reading information from a wsgi_request */ PyObject *uwsgi_dyn_loader(void *arg1) { PyObject *callable = NULL; char *tmpstr; struct wsgi_request *wsgi_req = (struct wsgi_request *) arg1; // MANAGE UWSGI_SCRIPT if (wsgi_req->script_len > 0) { tmpstr = uwsgi_strncopy(wsgi_req->script, wsgi_req->script_len); callable = uwsgi_uwsgi_loader((void *)tmpstr); free(tmpstr); } // MANAGE UWSGI_MODULE else if (wsgi_req->module_len > 0) { if (wsgi_req->callable_len > 0) { tmpstr = uwsgi_concat3n(wsgi_req->module, wsgi_req->module_len, ":", 1, wsgi_req->callable, wsgi_req->callable_len); } else { tmpstr = uwsgi_strncopy(wsgi_req->module, wsgi_req->module_len); } callable = uwsgi_uwsgi_loader((void *)tmpstr); free(tmpstr); } // MANAGE UWSGI_FILE else if (wsgi_req->file_len > 0) { tmpstr = uwsgi_strncopy(wsgi_req->file, wsgi_req->file_len); callable = uwsgi_file_loader((void *)tmpstr); free(tmpstr); } // TODO MANAGE UWSGI_PASTE /* else if (wsgi_req->wsgi_paste_len > 0) { tmpstr = uwsgi_strncopy(wsgi_req->paste, wsgi_req->paste_len); callable = uwsgi_paste_loader((void *)tmpstr); free(tmpstr); } */ return callable; } /* trying to emulate Graham's mod_wsgi, this will allows easy and fast migrations */ PyObject *uwsgi_file_loader(void *arg1) { char *filename = (char *) arg1; PyObject *wsgi_file_module, *wsgi_file_dict; PyObject *wsgi_file_callable; char *callable = up.callable; if (!callable) callable = "application"; char *pythonized_filename = uwsgi_pythonize(filename); char *py_filename = uwsgi_concat2("uwsgi_file_", pythonized_filename); free(pythonized_filename); wsgi_file_module = uwsgi_pyimport_by_filename(py_filename, filename); if (!wsgi_file_module) { PyErr_Print(); free(py_filename); return NULL; } wsgi_file_dict = PyModule_GetDict(wsgi_file_module); if (!wsgi_file_dict) { PyErr_Print(); Py_DECREF(wsgi_file_module); free(py_filename); return NULL; } wsgi_file_callable = PyDict_GetItemString(wsgi_file_dict, callable); if (!wsgi_file_callable) { PyErr_Print(); Py_DECREF(wsgi_file_dict); Py_DECREF(wsgi_file_module); free(py_filename); uwsgi_log( "unable to find \"application\" callable in file %s\n", filename); return NULL; } if (!PyFunction_Check(wsgi_file_callable) && !PyCallable_Check(wsgi_file_callable)) { uwsgi_log( "\"application\" must be a callable object in file %s\n", filename); Py_DECREF(wsgi_file_callable); Py_DECREF(wsgi_file_dict); Py_DECREF(wsgi_file_module); free(py_filename); return NULL; } free(py_filename); return wsgi_file_callable; } PyObject *uwsgi_pecan_loader(void *arg1) { char *pecan = (char *) arg1; PyObject *pecan_module, *pecan_dict, *pecan_deploy; PyObject *pecan_arg, *pecan_app; uwsgi_log( "Loading pecan environment: %s\n", pecan); pecan_module = PyImport_ImportModule("pecan.deploy"); if (!pecan_module) { PyErr_Print(); exit(UWSGI_FAILED_APP_CODE); } pecan_dict = PyModule_GetDict(pecan_module); if (!pecan_dict) { PyErr_Print(); exit(UWSGI_FAILED_APP_CODE); } pecan_deploy = PyDict_GetItemString(pecan_dict, "deploy"); if (!pecan_deploy) { PyErr_Print(); exit(UWSGI_FAILED_APP_CODE); } pecan_arg = PyTuple_New(1); if (!pecan_arg) { PyErr_Print(); exit(UWSGI_FAILED_APP_CODE); } if (PyTuple_SetItem(pecan_arg, 0, UWSGI_PYFROMSTRING(pecan))) { PyErr_Print(); exit(UWSGI_FAILED_APP_CODE); } pecan_app = PyObject_CallObject(pecan_deploy, pecan_arg); if (!pecan_app) { PyErr_Print(); exit(UWSGI_FAILED_APP_CODE); } return pecan_app; } PyObject *uwsgi_paste_loader(void *arg1) { char *paste = (char *) arg1; PyObject *paste_module, *paste_dict, *paste_loadapp; PyObject *paste_arg, *paste_app; uwsgi_log( "Loading paste environment: %s\n", paste); if (up.paste_logger) { PyObject *paste_logger_dict = get_uwsgi_pydict("logging.config"); if (paste_logger_dict) { PyObject *paste_logger_fileConfig = PyDict_GetItemString(paste_logger_dict, "fileConfig"); if (paste_logger_fileConfig) { PyObject *paste_logger_arg = PyTuple_New(1); if (!paste_logger_arg) { PyErr_Print(); exit(UWSGI_FAILED_APP_CODE); } PyTuple_SetItem(paste_logger_arg, 0, UWSGI_PYFROMSTRING(paste+7)); if (python_call(paste_logger_fileConfig, paste_logger_arg, 0, NULL)) { PyErr_Print(); } } } } paste_module = PyImport_ImportModule("paste.deploy"); if (!paste_module) { PyErr_Print(); exit(UWSGI_FAILED_APP_CODE); } paste_dict = PyModule_GetDict(paste_module); if (!paste_dict) { PyErr_Print(); exit(UWSGI_FAILED_APP_CODE); } paste_loadapp = PyDict_GetItemString(paste_dict, "loadapp"); if (!paste_loadapp) { PyErr_Print(); exit(UWSGI_FAILED_APP_CODE); } paste_arg = PyTuple_New(1); if (!paste_arg) { PyErr_Print(); exit(UWSGI_FAILED_APP_CODE); } if (PyTuple_SetItem(paste_arg, 0, UWSGI_PYFROMSTRING(paste))) { PyErr_Print(); exit(UWSGI_FAILED_APP_CODE); } paste_app = PyObject_CallObject(paste_loadapp, paste_arg); if (!paste_app) { PyErr_Print(); exit(UWSGI_FAILED_APP_CODE); } return paste_app; } PyObject *uwsgi_eval_loader(void *arg1) { char *code = (char *) arg1; PyObject *wsgi_eval_module, *wsgi_eval_callable = NULL; PyObject *wsgi_compiled_node; wsgi_compiled_node = Py_CompileString(code, "uwsgi_eval_config", Py_file_input); if (!wsgi_compiled_node) { PyErr_Print(); uwsgi_log( "failed to compile eval code\n"); exit(UWSGI_FAILED_APP_CODE); } wsgi_eval_module = PyImport_ExecCodeModule("uwsgi_eval_config", wsgi_compiled_node); if (!wsgi_eval_module) { PyErr_Print(); exit(UWSGI_FAILED_APP_CODE); } Py_DECREF(wsgi_compiled_node); up.loader_dict = PyModule_GetDict(wsgi_eval_module); if (!up.loader_dict) { PyErr_Print(); exit(UWSGI_FAILED_APP_CODE); } if (up.callable) { wsgi_eval_callable = PyDict_GetItemString(up.loader_dict, up.callable); } else { wsgi_eval_callable = PyDict_GetItemString(up.loader_dict, "application"); } if (wsgi_eval_callable) { if (!PyFunction_Check(wsgi_eval_callable) && !PyCallable_Check(wsgi_eval_callable)) { uwsgi_log( "you must define a callable object in your code\n"); exit(UWSGI_FAILED_APP_CODE); } } return wsgi_eval_callable; } PyObject *uwsgi_callable_loader(void *arg1) { return (PyObject *) arg1; } PyObject *uwsgi_string_callable_loader(void *arg1) { char *callable = (char *) arg1; return PyDict_GetItem(up.loader_dict, UWSGI_PYFROMSTRING(callable)); } uwsgi-2.0.29/plugins/python/python_plugin.c000066400000000000000000001731631477626554400210460ustar00rootroot00000000000000#include "uwsgi_python.h" /* This is the official python plugin, the one with the modifier1 mapped to 0 Since uWSGI 1.0 it is heavily based on Graham Dumpleton mod_wsgi (for Apache) */ extern struct uwsgi_server uwsgi; struct uwsgi_python up; #include extern PyTypeObject uwsgi_InputType; void uwsgi_opt_pythonpath(char *opt, char *value, void *foobar) { int i; glob_t g; if (glob(value, GLOB_MARK, NULL, &g)) { uwsgi_string_new_list(&up.python_path, value); } else { for (i = 0; i < (int) g.gl_pathc; i++) { uwsgi_string_new_list(&up.python_path, g.gl_pathv[i]); } } } void uwsgi_opt_pyshell(char *opt, char *value, void *foobar) { uwsgi.honour_stdin = 1; if (value) { up.pyshell = value; } else { up.pyshell = ""; } if (!strcmp("pyshell-oneshot", opt)) { up.pyshell_oneshot = 1; } } void uwsgi_opt_pyrun(char *opt, char *value, void *foobar) { uwsgi.honour_stdin = 1; uwsgi.command_mode = 1; up.pyrun = value; } void uwsgi_opt_pyver(char *opt, char *foo, void *bar) { const char *version = Py_GetVersion(); const char *space = strchr(version, ' '); if (space) { fprintf(stdout, "%.*s\n", (int) (space-version), version); } else { fprintf(stdout, "%s\n", version); } exit(0); } void uwsgi_opt_ini_paste(char *opt, char *value, void *foobar) { uwsgi_opt_load_ini(opt, value, NULL); if (value[0] != '/') { up.paste = uwsgi_concat4("config:", uwsgi.cwd, "/", value); } else { up.paste = uwsgi_concat2("config:", value); } if (!strcmp("ini-paste-logged", opt)) { up.paste_logger = 1; } } struct uwsgi_option uwsgi_python_options[] = { {"wsgi-file", required_argument, 0, "load .wsgi file", uwsgi_opt_set_str, &up.file_config, 0}, {"file", required_argument, 0, "load .wsgi file", uwsgi_opt_set_str, &up.file_config, 0}, {"eval", required_argument, 0, "eval python code", uwsgi_opt_set_str, &up.eval, 0}, {"module", required_argument,'w', "load a WSGI module", uwsgi_opt_set_str, &up.wsgi_config, 0}, {"wsgi", required_argument, 'w', "load a WSGI module", uwsgi_opt_set_str, &up.wsgi_config, 0}, {"callable", required_argument, 0, "set default WSGI callable name", uwsgi_opt_set_str, &up.callable, 0}, {"test", required_argument, 'J', "test a module import", uwsgi_opt_set_str, &up.test_module, 0}, {"home", required_argument, 'H', "set PYTHONHOME/virtualenv", uwsgi_opt_set_str, &up.home, 0}, {"virtualenv", required_argument, 'H', "set PYTHONHOME/virtualenv", uwsgi_opt_set_str, &up.home, 0}, {"venv", required_argument, 'H', "set PYTHONHOME/virtualenv", uwsgi_opt_set_str, &up.home, 0}, {"pyhome", required_argument, 'H', "set PYTHONHOME/virtualenv", uwsgi_opt_set_str, &up.home, 0}, {"py-programname", required_argument, 0, "set python program name", uwsgi_opt_set_str, &up.programname, 0}, {"py-program-name", required_argument, 0, "set python program name", uwsgi_opt_set_str, &up.programname, 0}, {"pythonpath", required_argument, 0, "add directory (or glob) to pythonpath", uwsgi_opt_pythonpath, NULL, 0}, {"python-path", required_argument, 0, "add directory (or glob) to pythonpath", uwsgi_opt_pythonpath, NULL, 0}, {"pp", required_argument, 0, "add directory (or glob) to pythonpath", uwsgi_opt_pythonpath, NULL, 0}, {"pymodule-alias", required_argument, 0, "add a python alias module", uwsgi_opt_add_string_list, &up.pymodule_alias, 0}, {"post-pymodule-alias", required_argument, 0, "add a python module alias after uwsgi module initialization", uwsgi_opt_add_string_list, &up.post_pymodule_alias, 0}, {"import", required_argument, 0, "import a python module", uwsgi_opt_add_string_list, &up.import_list, 0}, {"pyimport", required_argument, 0, "import a python module", uwsgi_opt_add_string_list, &up.import_list, 0}, {"py-import", required_argument, 0, "import a python module", uwsgi_opt_add_string_list, &up.import_list, 0}, {"python-import", required_argument, 0, "import a python module", uwsgi_opt_add_string_list, &up.import_list, 0}, {"shared-import", required_argument, 0, "import a python module in all of the processes", uwsgi_opt_add_string_list, &up.shared_import_list, 0}, {"shared-pyimport", required_argument, 0, "import a python module in all of the processes", uwsgi_opt_add_string_list, &up.shared_import_list, 0}, {"shared-py-import", required_argument, 0, "import a python module in all of the processes", uwsgi_opt_add_string_list, &up.shared_import_list, 0}, {"shared-python-import", required_argument, 0, "import a python module in all of the processes", uwsgi_opt_add_string_list, &up.shared_import_list, 0}, {"spooler-import", required_argument, 0, "import a python module in the spooler", uwsgi_opt_add_string_list, &up.spooler_import_list}, {"spooler-pyimport", required_argument, 0, "import a python module in the spooler", uwsgi_opt_add_string_list, &up.spooler_import_list}, {"spooler-py-import", required_argument, 0, "import a python module in the spooler", uwsgi_opt_add_string_list, &up.spooler_import_list}, {"spooler-python-import", required_argument, 0, "import a python module in the spooler", uwsgi_opt_add_string_list, &up.spooler_import_list}, {"pyargv", required_argument, 0, "manually set sys.argv", uwsgi_opt_set_str, &up.argv, 0}, {"optimize", required_argument, 'O', "set python optimization level", uwsgi_opt_set_int, &up.optimize, 0}, {"pecan", required_argument, 0, "load a pecan config file", uwsgi_opt_set_str, &up.pecan, 0}, {"paste", required_argument, 0, "load a paste.deploy config file", uwsgi_opt_set_str, &up.paste, 0}, {"paste-logger", no_argument, 0, "enable paste fileConfig logger", uwsgi_opt_true, &up.paste_logger, 0}, {"web3", required_argument, 0, "load a web3 app", uwsgi_opt_set_str, &up.web3, 0}, {"pump", required_argument, 0, "load a pump app", uwsgi_opt_set_str, &up.pump, 0}, {"wsgi-lite", required_argument, 0, "load a wsgi-lite app", uwsgi_opt_set_str, &up.wsgi_lite, 0}, {"ini-paste", required_argument, 0, "load a paste.deploy config file containing uwsgi section", uwsgi_opt_ini_paste, NULL, UWSGI_OPT_IMMEDIATE}, {"ini-paste-logged", required_argument, 0, "load a paste.deploy config file containing uwsgi section (load loggers too)", uwsgi_opt_ini_paste, NULL, UWSGI_OPT_IMMEDIATE}, {"reload-os-env", no_argument, 0, "force reload of os.environ at each request", uwsgi_opt_true, &up.reload_os_env, 0}, #ifndef __CYGWIN__ {"no-site", no_argument, 0, "do not import site module", uwsgi_opt_true, &Py_NoSiteFlag, 0}, #endif {"pyshell", optional_argument, 0, "run an interactive python shell in the uWSGI environment", uwsgi_opt_pyshell, NULL, 0}, {"pyshell-oneshot", optional_argument, 0, "run an interactive python shell in the uWSGI environment (one-shot variant)", uwsgi_opt_pyshell, NULL, 0}, {"python", required_argument, 0, "run a python script in the uWSGI environment", uwsgi_opt_pyrun, NULL, 0}, {"py", required_argument, 0, "run a python script in the uWSGI environment", uwsgi_opt_pyrun, NULL, 0}, {"pyrun", required_argument, 0, "run a python script in the uWSGI environment", uwsgi_opt_pyrun, NULL, 0}, {"py-tracebacker", required_argument, 0, "enable the uWSGI python tracebacker", uwsgi_opt_set_str, &up.tracebacker, UWSGI_OPT_THREADS|UWSGI_OPT_MASTER}, {"py-auto-reload", required_argument, 0, "monitor python modules mtime to trigger reload (use only in development)", uwsgi_opt_set_int, &up.auto_reload, UWSGI_OPT_THREADS|UWSGI_OPT_MASTER}, {"py-autoreload", required_argument, 0, "monitor python modules mtime to trigger reload (use only in development)", uwsgi_opt_set_int, &up.auto_reload, UWSGI_OPT_THREADS|UWSGI_OPT_MASTER}, {"python-auto-reload", required_argument, 0, "monitor python modules mtime to trigger reload (use only in development)", uwsgi_opt_set_int, &up.auto_reload, UWSGI_OPT_THREADS|UWSGI_OPT_MASTER}, {"python-autoreload", required_argument, 0, "monitor python modules mtime to trigger reload (use only in development)", uwsgi_opt_set_int, &up.auto_reload, UWSGI_OPT_THREADS|UWSGI_OPT_MASTER}, {"py-auto-reload-ignore", required_argument, 0, "ignore the specified module during auto-reload scan (can be specified multiple times)", uwsgi_opt_add_string_list, &up.auto_reload_ignore, UWSGI_OPT_THREADS|UWSGI_OPT_MASTER}, {"wsgi-env-behaviour", required_argument, 0, "set the strategy for allocating/deallocating the WSGI env", uwsgi_opt_set_str, &up.wsgi_env_behaviour, 0}, {"wsgi-env-behavior", required_argument, 0, "set the strategy for allocating/deallocating the WSGI env", uwsgi_opt_set_str, &up.wsgi_env_behaviour, 0}, {"start_response-nodelay", no_argument, 0, "send WSGI http headers as soon as possible (PEP violation)", uwsgi_opt_true, &up.start_response_nodelay, 0}, {"wsgi-strict", no_argument, 0, "try to be fully PEP compliant disabling optimizations", uwsgi_opt_true, &up.wsgi_strict, 0}, {"wsgi-accept-buffer", no_argument, 0, "accept CPython buffer-compliant objects as WSGI response in addition to string/bytes", uwsgi_opt_true, &up.wsgi_accept_buffer, 0}, {"wsgi-accept-buffers", no_argument, 0, "accept CPython buffer-compliant objects as WSGI response in addition to string/bytes", uwsgi_opt_true, &up.wsgi_accept_buffer, 0}, {"wsgi-disable-file-wrapper", no_argument, 0, "disable wsgi.file_wrapper feature", uwsgi_opt_true, &up.wsgi_disable_file_wrapper, 0}, {"python-version", no_argument, 0, "report python version", uwsgi_opt_pyver, NULL, UWSGI_OPT_IMMEDIATE}, {"python-raw", required_argument, 0, "load a python file for managing raw requests", uwsgi_opt_set_str, &up.raw, 0}, #if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER) {"py-sharedarea", required_argument, 0, "create a sharedarea from a python bytearray object of the specified size", uwsgi_opt_add_string_list, &up.sharedarea, 0}, #endif {"py-call-osafterfork", no_argument, 0, "enable child processes running cpython to trap OS signals", uwsgi_opt_true, &up.call_osafterfork, 0}, {"py-call-uwsgi-fork-hooks", no_argument, 0, "call pre and post hooks when uswgi forks to update the internal interpreter state of CPython", uwsgi_opt_true, &up.call_uwsgi_fork_hooks, 0}, {"python-worker-override", required_argument, 0, "override worker with the specified python script", uwsgi_opt_set_str, &up.worker_override, 0}, {"py-executable", required_argument, 0, "override sys.executable value", uwsgi_opt_set_str, &up.executable, 0}, {"py-sys-executable", required_argument, 0, "override sys.executable value", uwsgi_opt_set_str, &up.executable, 0}, {0, 0, 0, 0, 0, 0, 0}, }; /* this routine will be called after each fork to reinitialize the various locks */ void uwsgi_python_pthread_prepare(void) { pthread_mutex_lock(&up.lock_pyloaders); } void uwsgi_python_pthread_parent(void) { pthread_mutex_unlock(&up.lock_pyloaders); } void uwsgi_python_pthread_child(void) { pthread_mutex_init(&up.lock_pyloaders, NULL); } PyMethodDef uwsgi_spit_method[] = { {"uwsgi_spit", py_uwsgi_spit, METH_VARARGS, ""} }; PyMethodDef uwsgi_write_method[] = { {"uwsgi_write", py_uwsgi_write, METH_VARARGS, ""} }; PyDoc_STRVAR(uwsgi_py_doc, "uWSGI api module."); #ifdef PYTHREE static PyModuleDef uwsgi_module3 = { PyModuleDef_HEAD_INIT, "uwsgi", uwsgi_py_doc, -1, NULL, }; PyObject *init_uwsgi3(void) { return PyModule_Create(&uwsgi_module3); } #endif int uwsgi_python_init() { char *pyversion = strchr(Py_GetVersion(), '\n'); if (!pyversion) { uwsgi_log_initial("Python version: %s\n", Py_GetVersion()); } else { uwsgi_log_initial("Python version: %.*s %s\n", pyversion-Py_GetVersion(), Py_GetVersion(), Py_GetCompiler()+1); } if (Py_IsInitialized()) { uwsgi_log("--- Python VM already initialized ---\n"); PyGILState_Ensure(); goto ready; } if (up.home != NULL) { if (!uwsgi_is_dir(up.home)) { uwsgi_log("!!! Python Home is not a directory: %s !!!\n", up.home); } #ifdef PYTHREE // check for PEP 405 virtualenv (starting from python 3.3) char *pep405_env = uwsgi_concat2(up.home, "/pyvenv.cfg"); if (uwsgi_file_exists(pep405_env)) { uwsgi_log("PEP 405 virtualenv detected: %s\n", up.home); free(pep405_env); goto pep405; } free(pep405_env); // build the PYTHONHOME wchar path wchar_t *wpyhome; size_t len = strlen(up.home) + 1; wpyhome = uwsgi_calloc(sizeof(wchar_t) * len ); if (!wpyhome) { uwsgi_error("malloc()"); exit(1); } mbstowcs(wpyhome, up.home, len); Py_SetPythonHome(wpyhome); // do not free this memory !!! //free(wpyhome); pep405: #else Py_SetPythonHome(up.home); #endif uwsgi_log("Set PythonHome to %s\n", up.home); } char *program_name = up.programname; if (!program_name) { program_name = uwsgi.binary_path; } #ifdef PYTHREE if (!up.programname) { if (up.home) { program_name = uwsgi_concat2(up.home, "/bin/python"); } } wchar_t *pname = uwsgi_calloc(sizeof(wchar_t) * (strlen(program_name)+1)); mbstowcs(pname, program_name, strlen(program_name)+1); Py_SetProgramName(pname); #ifdef UWSGI_PY312 PyImport_AppendInittab("uwsgi", init_uwsgi3); #endif #else Py_SetProgramName(program_name); #endif Py_OptimizeFlag = up.optimize; Py_Initialize(); ready: if (!uwsgi.has_threads) { uwsgi_log_initial("*** Python threads support is disabled. You can enable it with --enable-threads ***\n"); } up.wsgi_spitout = PyCFunction_New(uwsgi_spit_method, NULL); up.wsgi_writeout = PyCFunction_New(uwsgi_write_method, NULL); up.main_thread = PyThreadState_Get(); // by default set a fake GIL (little impact on performance) up.gil_get = gil_fake_get; up.gil_release = gil_fake_release; up.swap_ts = simple_swap_ts; up.reset_ts = simple_reset_ts; #if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER) struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, up.sharedarea) { uint64_t len = uwsgi_n64(usl->value); PyObject *obj = PyByteArray_FromStringAndSize(NULL, len); char *storage = PyByteArray_AsString(obj); Py_INCREF(obj); struct uwsgi_sharedarea *sa = uwsgi_sharedarea_init_ptr(storage, len); sa->obj = obj; } #endif uwsgi_log_initial("Python main interpreter initialized at %p\n", up.main_thread); return 1; } void uwsgi_python_reset_random_seed() { PyObject *random_module, *random_dict, *random_seed; // reinitialize the random seed (thanks Jonas Borgström) random_module = PyImport_ImportModule("random"); if (random_module) { random_dict = PyModule_GetDict(random_module); if (random_dict) { random_seed = PyDict_GetItemString(random_dict, "seed"); if (random_seed) { PyObject *random_args = PyTuple_New(1); // pass no args PyTuple_SetItem(random_args, 0, Py_None); PyObject_CallObject(random_seed, random_args); if (PyErr_Occurred()) { PyErr_Print(); } } } } } void uwsgi_python_atexit() { if (uwsgi.mywid == 0) goto realstuff; // if hijacked do not run atexit hooks if (uwsgi.workers[uwsgi.mywid].hijacked) return; // if busy do not run atexit hooks if (uwsgi_worker_is_busy(uwsgi.mywid)) return; // managing atexit in async mode is a real pain...skip it for now if (uwsgi.async > 1) return; realstuff: // this time we use this higher level function // as this code can be executed in a signal handler #ifdef __GNU_kFreeBSD__ return; #endif if (!Py_IsInitialized()) { return; } // always call it PyGILState_Ensure(); // no need to worry about freeing memory PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi"); if (uwsgi_dict) { PyObject *ae = PyDict_GetItemString(uwsgi_dict, "atexit"); if (ae) { python_call(ae, PyTuple_New(0), 0, NULL); } } // this part is a 1:1 copy of mod_wsgi 3.x // it is required to fix some atexit bug with python 3 // and to shutdown useless threads complaints PyObject *module = PyImport_ImportModule("atexit"); Py_XDECREF(module); if (uwsgi.has_threads) { if (!PyImport_AddModule("dummy_threading")) PyErr_Clear(); } // For the reasons explained in // https://github.com/unbit/uwsgi/issues/1384, tearing down // the interpreter can be very expensive. if (uwsgi.skip_atexit_teardown) return; Py_Finalize(); } void uwsgi_python_post_fork() { // Need to acquire the gil when no master process is used as first worker // will not have been forked like others // Necessary if uwsgi fork hooks called to update interpreter state if (up.call_uwsgi_fork_hooks && !uwsgi.master_process && uwsgi.mywid == 1) { UWSGI_GET_GIL } if (uwsgi.i_am_a_spooler) { UWSGI_GET_GIL } // reset python signal flags so child processes can trap signals // Necessary if uwsgi fork hooks not called to update interpreter state if (!up.call_uwsgi_fork_hooks && up.call_osafterfork) { #ifdef HAS_NOT_PYOS_FORK_STABLE_API PyOS_AfterFork(); #else PyOS_AfterFork_Child(); #endif } uwsgi_python_reset_random_seed(); // call the post_fork_hook PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi"); if (uwsgi_dict) { PyObject *pfh = PyDict_GetItemString(uwsgi_dict, "post_fork_hook"); if (pfh) { python_call(pfh, PyTuple_New(0), 0, NULL); } } PyErr_Clear(); if (uwsgi.mywid > 0) { uwsgi_python_set_thread_name(0); if (up.auto_reload) { // spawn the reloader thread pthread_t par_tid; pthread_create(&par_tid, NULL, uwsgi_python_autoreloader_thread, NULL); } if (up.tracebacker) { // spawn the tracebacker thread pthread_t ptb_tid; pthread_create(&ptb_tid, NULL, uwsgi_python_tracebacker_thread, NULL); } } UWSGI_RELEASE_GIL } PyObject *uwsgi_pyimport_by_filename(char *name, char *filename) { char *pycontent; PyObject *py_compiled_node, *py_file_module; int is_a_package = 0; struct stat pystat; char *real_filename = filename; if (!uwsgi_check_scheme(filename)) { FILE *pyfile = fopen(filename, "r"); if (!pyfile) { uwsgi_log("failed to open python file %s\n", filename); return NULL; } if (fstat(fileno(pyfile), &pystat)) { fclose(pyfile); uwsgi_error("fstat()"); return NULL; } if (S_ISDIR(pystat.st_mode)) { is_a_package = 1; fclose(pyfile); real_filename = uwsgi_concat2(filename, "/__init__.py"); pyfile = fopen(real_filename, "r"); if (!pyfile) { uwsgi_error_open(real_filename); free(real_filename); return NULL; } } fclose(pyfile); pycontent = uwsgi_simple_file_read(real_filename); if (!pycontent) { if (is_a_package) { free(real_filename); } uwsgi_log("no data read from file %s\n", real_filename); return NULL; } } else { size_t pycontent_size = 0; pycontent = uwsgi_open_and_read(filename, &pycontent_size, 1, NULL); if (!pycontent) { uwsgi_log("no data read from url %s\n", real_filename); return NULL; } } py_compiled_node = Py_CompileString(pycontent, real_filename, Py_file_input); if (!py_compiled_node) { PyErr_Print(); uwsgi_log("failed to compile %s\n", real_filename); return NULL; } if (is_a_package) { py_file_module = PyImport_AddModule(name); if (py_file_module) { PyModule_AddObject(py_file_module, "__path__", Py_BuildValue("[O]", PyString_FromString(filename))); } free(real_filename); } py_file_module = PyImport_ExecCodeModule(name, py_compiled_node); if (!py_file_module) { PyErr_Print(); return NULL; } Py_DECREF(py_compiled_node); return py_file_module; } void init_uwsgi_vars() { PyObject *pysys, *pysys_dict, *pypath; PyObject *modules = PyImport_GetModuleDict(); PyObject *tmp_module; /* add cwd to pythonpath */ pysys = PyImport_ImportModule("sys"); if (!pysys) { PyErr_Print(); exit(1); } pysys_dict = PyModule_GetDict(pysys); #ifdef PYTHREE // In python3, stdout / stderr was changed to be buffered (a bug according // to many): // - https://bugs.python.org/issue13597 // - https://bugs.python.org/issue13601 // We'll fix this by manually restore the unbuffered behaviour. // In the case of a tty, this fix breaks readline support in interactive // debuggers so we'll only do this in the non-tty case. if (!Py_FdIsInteractive(stdin, NULL)) { #ifdef HAS_NO_ERRORS_IN_PyFile_FromFd PyObject *new_stdprint = PyFile_FromFd(2, NULL, "w", _IOLBF, NULL, NULL, 0); #else PyObject *new_stdprint = PyFile_FromFd(2, NULL, "w", _IOLBF, NULL, "backslashreplace", NULL, 0); #endif PyDict_SetItemString(pysys_dict, "stdout", new_stdprint); PyDict_SetItemString(pysys_dict, "__stdout__", new_stdprint); PyDict_SetItemString(pysys_dict, "stderr", new_stdprint); PyDict_SetItemString(pysys_dict, "__stderr__", new_stdprint); } #endif pypath = PyDict_GetItemString(pysys_dict, "path"); if (!pypath) { PyErr_Print(); exit(1); } if (PyList_Insert(pypath, 0, UWSGI_PYFROMSTRING(".")) != 0) { PyErr_Print(); } struct uwsgi_string_list *uppp = up.python_path; while(uppp) { if (PyList_Insert(pypath, 0, UWSGI_PYFROMSTRING(uppp->value)) != 0) { PyErr_Print(); } else { uwsgi_log("added %s to pythonpath.\n", uppp->value); } uppp = uppp->next; } struct uwsgi_string_list *uppma = up.pymodule_alias; while(uppma) { // split key=value char *value = strchr(uppma->value, '='); if (!value) { uwsgi_log("invalid pymodule-alias syntax\n"); goto next; } value[0] = 0; if (!strchr(value + 1, '/')) { // this is a standard pymodule tmp_module = PyImport_ImportModule(value + 1); if (!tmp_module) { PyErr_Print(); exit(1); } PyDict_SetItemString(modules, uppma->value, tmp_module); } else { // this is a filepath that need to be mapped tmp_module = uwsgi_pyimport_by_filename(uppma->value, value + 1); if (!tmp_module) { PyErr_Print(); exit(1); } } uwsgi_log("mapped virtual pymodule \"%s\" to real pymodule \"%s\"\n", uppma->value, value + 1); // reset original value value[0] = '='; next: uppma = uppma->next; } } void init_uwsgi_embedded_module() { PyObject *new_uwsgi_module, *zero; int i; if (PyType_Ready(&uwsgi_InputType) < 0) { PyErr_Print(); uwsgi_log("could not initialize the uwsgi python module\n"); exit(1); } /* initialize for stats */ up.workers_tuple = PyTuple_New(uwsgi.numproc); for (i = 0; i < uwsgi.numproc; i++) { zero = PyDict_New(); Py_INCREF(zero); PyTuple_SetItem(up.workers_tuple, i, zero); } #ifdef PYTHREE #ifndef UWSGI_PY312 PyImport_AppendInittab("uwsgi", init_uwsgi3); #endif new_uwsgi_module = PyImport_AddModule("uwsgi"); #else new_uwsgi_module = Py_InitModule3("uwsgi", NULL, uwsgi_py_doc); #endif if (new_uwsgi_module == NULL) { uwsgi_log("could not initialize the uwsgi python module\n"); exit(1); } Py_INCREF((PyObject *) &uwsgi_InputType); up.embedded_dict = PyModule_GetDict(new_uwsgi_module); if (!up.embedded_dict) { uwsgi_log("could not get uwsgi module __dict__\n"); exit(1); } // just for safety Py_INCREF(up.embedded_dict); if (PyDict_SetItemString(up.embedded_dict, "version", PyString_FromString(UWSGI_VERSION))) { PyErr_Print(); exit(1); } PyObject *uwsgi_py_version_info = PyTuple_New(5); PyTuple_SetItem(uwsgi_py_version_info, 0, PyInt_FromLong(UWSGI_VERSION_BASE)); PyTuple_SetItem(uwsgi_py_version_info, 1, PyInt_FromLong(UWSGI_VERSION_MAJOR)); PyTuple_SetItem(uwsgi_py_version_info, 2, PyInt_FromLong(UWSGI_VERSION_MINOR)); PyTuple_SetItem(uwsgi_py_version_info, 3, PyInt_FromLong(UWSGI_VERSION_REVISION)); PyTuple_SetItem(uwsgi_py_version_info, 4, PyString_FromString(UWSGI_VERSION_CUSTOM)); if (PyDict_SetItemString(up.embedded_dict, "version_info", uwsgi_py_version_info)) { PyErr_Print(); exit(1); } if (PyDict_SetItemString(up.embedded_dict, "hostname", PyString_FromStringAndSize(uwsgi.hostname, uwsgi.hostname_len))) { PyErr_Print(); exit(1); } if (uwsgi.mode) { if (PyDict_SetItemString(up.embedded_dict, "mode", PyString_FromString(uwsgi.mode))) { PyErr_Print(); exit(1); } } if (uwsgi.pidfile) { if (PyDict_SetItemString(up.embedded_dict, "pidfile", PyString_FromString(uwsgi.pidfile))) { PyErr_Print(); exit(1); } } if (uwsgi.spoolers) { int sc = 0; struct uwsgi_spooler *uspool = uwsgi.spoolers; while(uspool) { sc++; uspool = uspool->next;} PyObject *py_spooler_tuple = PyTuple_New(sc); uspool = uwsgi.spoolers; sc = 0; while(uspool) { PyTuple_SetItem(py_spooler_tuple, sc, PyString_FromString(uspool->dir)); sc++; uspool = uspool->next; } if (PyDict_SetItemString(up.embedded_dict, "spoolers", py_spooler_tuple)) { PyErr_Print(); exit(1); } } if (PyDict_SetItemString(up.embedded_dict, "SPOOL_RETRY", PyInt_FromLong(-1))) { PyErr_Print(); exit(1); } if (PyDict_SetItemString(up.embedded_dict, "SPOOL_OK", PyInt_FromLong(-2))) { PyErr_Print(); exit(1); } if (PyDict_SetItemString(up.embedded_dict, "SPOOL_IGNORE", PyInt_FromLong(0))) { PyErr_Print(); exit(1); } if (PyDict_SetItemString(up.embedded_dict, "numproc", PyInt_FromLong(uwsgi.numproc))) { PyErr_Print(); exit(1); } if (PyDict_SetItemString(up.embedded_dict, "has_threads", PyInt_FromLong(uwsgi.has_threads))) { PyErr_Print(); exit(1); } if (PyDict_SetItemString(up.embedded_dict, "cores", PyInt_FromLong(uwsgi.cores))) { PyErr_Print(); exit(1); } if (uwsgi.loop) { if (PyDict_SetItemString(up.embedded_dict, "loop", PyString_FromString(uwsgi.loop))) { PyErr_Print(); exit(1); } } else { PyDict_SetItemString(up.embedded_dict, "loop", Py_None); } PyObject *py_opt_dict = PyDict_New(); for (i = 0; i < uwsgi.exported_opts_cnt; i++) { if (PyDict_Contains(py_opt_dict, PyString_FromString(uwsgi.exported_opts[i]->key))) { PyObject *py_opt_item = PyDict_GetItemString(py_opt_dict, uwsgi.exported_opts[i]->key); if (PyList_Check(py_opt_item)) { if (uwsgi.exported_opts[i]->value == NULL) { PyList_Append(py_opt_item, Py_True); } else { PyList_Append(py_opt_item, PyString_FromString(uwsgi.exported_opts[i]->value)); } } else { PyObject *py_opt_list = PyList_New(0); PyList_Append(py_opt_list, py_opt_item); if (uwsgi.exported_opts[i]->value == NULL) { PyList_Append(py_opt_list, Py_True); } else { PyList_Append(py_opt_list, PyString_FromString(uwsgi.exported_opts[i]->value)); } PyDict_SetItemString(py_opt_dict, uwsgi.exported_opts[i]->key, py_opt_list); } } else { if (uwsgi.exported_opts[i]->value == NULL) { PyDict_SetItemString(py_opt_dict, uwsgi.exported_opts[i]->key, Py_True); } else { PyDict_SetItemString(py_opt_dict, uwsgi.exported_opts[i]->key, PyString_FromString(uwsgi.exported_opts[i]->value)); } } } if (PyDict_SetItemString(up.embedded_dict, "opt", py_opt_dict)) { PyErr_Print(); exit(1); } PyObject *py_sockets_list = PyList_New(0); struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while(uwsgi_sock) { if (uwsgi_sock->bound) { PyList_Append(py_sockets_list, PyInt_FromLong(uwsgi_sock->fd)); } uwsgi_sock = uwsgi_sock->next; } if (PyDict_SetItemString(up.embedded_dict, "sockets", py_sockets_list)) { PyErr_Print(); exit(1); } PyObject *py_magic_table = PyDict_New(); uint8_t mtk; for (i = 0; i <= 0xff; i++) { // a bit of magic :P mtk = i; if (uwsgi.magic_table[i]) { if (uwsgi.magic_table[i][0] != 0) { PyDict_SetItem(py_magic_table, PyString_FromStringAndSize((char *) &mtk, 1), PyString_FromString(uwsgi.magic_table[i])); } } } if (PyDict_SetItemString(up.embedded_dict, "magic_table", py_magic_table)) { PyErr_Print(); exit(1); } #ifdef UNBIT if (PyDict_SetItemString(up.embedded_dict, "unbit", Py_True)) { #else if (PyDict_SetItemString(up.embedded_dict, "unbit", Py_None)) { #endif PyErr_Print(); exit(1); } if (PyDict_SetItemString(up.embedded_dict, "buffer_size", PyInt_FromLong(uwsgi.buffer_size))) { PyErr_Print(); exit(1); } if (PyDict_SetItemString(up.embedded_dict, "started_on", PyInt_FromLong(uwsgi.start_tv.tv_sec))) { PyErr_Print(); exit(1); } if (PyDict_SetItemString(up.embedded_dict, "start_response", up.wsgi_spitout)) { PyErr_Print(); exit(1); } if (PyDict_SetItemString(up.embedded_dict, "applications", Py_None)) { PyErr_Print(); exit(1); } if (uwsgi.is_a_reload) { if (PyDict_SetItemString(up.embedded_dict, "is_a_reload", Py_True)) { PyErr_Print(); exit(1); } } else { if (PyDict_SetItemString(up.embedded_dict, "is_a_reload", Py_False)) { PyErr_Print(); exit(1); } } init_uwsgi_module_advanced(new_uwsgi_module); if (uwsgi.spoolers) { init_uwsgi_module_spooler(new_uwsgi_module); } if (uwsgi.sharedareas) { init_uwsgi_module_sharedarea(new_uwsgi_module); } init_uwsgi_module_cache(new_uwsgi_module); if (uwsgi.queue_size > 0) { init_uwsgi_module_queue(new_uwsgi_module); } if (uwsgi.snmp) { init_uwsgi_module_snmp(new_uwsgi_module); } if (up.extension) { up.extension(); } } int uwsgi_python_magic(char *mountpoint, char *lazy) { char *qc = strchr(lazy, ':'); if (qc) { qc[0] = 0; up.callable = qc + 1; } if (!strcmp(lazy + strlen(lazy) - 3, ".py")) { up.file_config = lazy; return 1; } else if (!strcmp(lazy + strlen(lazy) - 5, ".wsgi")) { up.file_config = lazy; return 1; } else if (qc && strchr(lazy, '.')) { up.wsgi_config = lazy; return 1; } // reset lazy if (qc) { qc[0] = ':'; } return 0; } int uwsgi_python_mount_app(char *mountpoint, char *app) { int id; if (strchr(app, ':') || uwsgi_endswith(app, ".py") || uwsgi_endswith(app, ".wsgi")) { uwsgi.wsgi_req->appid = mountpoint; uwsgi.wsgi_req->appid_len = strlen(mountpoint); // lazy ? if (uwsgi.mywid > 0) UWSGI_GET_GIL if (uwsgi.single_interpreter) { id = init_uwsgi_app(LOADER_MOUNT, app, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI); } else { id = init_uwsgi_app(LOADER_MOUNT, app, uwsgi.wsgi_req, NULL, PYTHON_APP_TYPE_WSGI); } // lazy ? if (uwsgi.mywid > 0) UWSGI_RELEASE_GIL return id; } return -1; } char *uwsgi_pythonize(char *orig) { char *name; size_t i, len, offset = 0; if (!strncmp(orig, "sym://", 6)) { offset = 6; } else if (!strncmp(orig, "http://", 7)) { offset = 7; } else if (!strncmp(orig, "data://", 7)) { offset = 7; } name = uwsgi_concat2(orig+offset, ""); len = strlen(name); for(i=0;ivalue, '/') || uwsgi_endswith(upli->value, ".py")) { uwsgi_pyimport_by_filename(uwsgi_pythonize(upli->value), upli->value); } else { if (PyImport_ImportModule(upli->value) == NULL) { PyErr_Print(); } } upli = upli->next; } UWSGI_RELEASE_GIL } // this is the default (fake) allocator for WSGI's env // the dictionary is created on app loading (one for each async core/thread) and reused (clearing it after each request, constantly) // // from a python-programmer point of view it is a hack/cheat but it does not violate the WSGI standard // and it is a bit faster than the "holy" allocator void *uwsgi_python_create_env_cheat(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) { wsgi_req->async_args = wi->args[wsgi_req->async_id]; Py_INCREF((PyObject *)wi->environ[wsgi_req->async_id]); return wi->environ[wsgi_req->async_id]; } void uwsgi_python_destroy_env_cheat(struct wsgi_request *wsgi_req) { PyDict_Clear((PyObject *)wsgi_req->async_environ); } // this is the "holy" allocator for WSGI's env // Armin Ronacher told me this is what most of python programmers expect // I cannot speak for that as i am a perl guy, and i expect only black-magic things :P // // this should be the default one, but changing default behaviours (even if they are wrong) // always make my customers going berserk... // // it is only slightly (better: irrelevant) slower, so no fear in enabling it... void *uwsgi_python_create_env_holy(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) { wsgi_req->async_args = PyTuple_New(2); // set start_response() Py_INCREF(Py_None); Py_INCREF(up.wsgi_spitout); PyTuple_SetItem((PyObject *)wsgi_req->async_args, 0, Py_None); PyTuple_SetItem((PyObject *)wsgi_req->async_args, 1, up.wsgi_spitout); PyObject *env = PyDict_New(); return env; } void uwsgi_python_destroy_env_holy(struct wsgi_request *wsgi_req) { if (uwsgi.threads < 2) { // in non-multithread modes, we set uwsgi.env, so let's remove it now // to equalise the refcount of the environ PyDict_DelItemString(up.embedded_dict, "env"); } // avoid to decref environ if it is mapped to the python callable if (PyTuple_GetItem(wsgi_req->async_args, 0) != wsgi_req->async_environ) { Py_DECREF((PyObject *)wsgi_req->async_environ); } Py_DECREF((PyObject *) wsgi_req->async_args); } // this hook will be executed by master (or worker1 when master is not requested, so COW is in place) void uwsgi_python_preinit_apps() { // GIL was released in previous initialization steps but init_pyargv expects // the GIL to be acquired // Necessary if uwsgi fork hooks called to update interpreter state if (up.call_uwsgi_fork_hooks) { UWSGI_GET_GIL } init_pyargv(); init_uwsgi_embedded_module(); #ifdef __linux__ uwsgi_init_symbol_import(); #endif if (up.test_module != NULL) { if (PyImport_ImportModule(up.test_module)) { exit(0); } exit(1); } if (up.wsgi_env_behaviour) { if (!strcmp(up.wsgi_env_behaviour, "holy")) { up.wsgi_env_create = uwsgi_python_create_env_holy; up.wsgi_env_destroy = uwsgi_python_destroy_env_holy; } else if (!strcmp(up.wsgi_env_behaviour, "cheat")) { up.wsgi_env_create = uwsgi_python_create_env_cheat; up.wsgi_env_destroy = uwsgi_python_destroy_env_cheat; } else { uwsgi_log("invalid wsgi-env-behaviour value: %s\n", up.wsgi_env_behaviour); exit(1); } } else { up.wsgi_env_create = uwsgi_python_create_env_cheat; up.wsgi_env_destroy = uwsgi_python_destroy_env_cheat; } init_uwsgi_vars(); // load shared imports struct uwsgi_string_list *upli = up.shared_import_list; while(upli) { if (strchr(upli->value, '/') || uwsgi_endswith(upli->value, ".py")) { uwsgi_pyimport_by_filename(uwsgi_pythonize(upli->value), upli->value); } else { if (PyImport_ImportModule(upli->value) == NULL) { PyErr_Print(); } } upli = upli->next; } // Release the GIL before moving on forward with initialization // Necessary if uwsgi fork hooks called to update interpreter state if (up.call_uwsgi_fork_hooks) { UWSGI_RELEASE_GIL } } void uwsgi_python_init_apps() { // lazy ? // Also necessary if uwsgi fork hooks called to update interpreter state if (uwsgi.mywid > 0 || up.call_uwsgi_fork_hooks) { UWSGI_GET_GIL; } // prepare for stack suspend/resume if (uwsgi.async > 1) { #ifdef UWSGI_PY312 up.current_c_recursion_remaining = uwsgi_malloc(sizeof(int)*uwsgi.async); up.current_py_recursion_remaining = uwsgi_malloc(sizeof(int)*uwsgi.async); #elif defined UWSGI_PY311 up.current_recursion_remaining = uwsgi_malloc(sizeof(int)*uwsgi.async); #else up.current_recursion_depth = uwsgi_malloc(sizeof(int)*uwsgi.async); #endif up.current_frame = uwsgi_malloc(sizeof(up.current_frame[0])*uwsgi.async); } // setup app loaders up.loaders[LOADER_DYN] = uwsgi_dyn_loader; up.loaders[LOADER_UWSGI] = uwsgi_uwsgi_loader; up.loaders[LOADER_FILE] = uwsgi_file_loader; up.loaders[LOADER_PECAN] = uwsgi_pecan_loader; up.loaders[LOADER_PASTE] = uwsgi_paste_loader; up.loaders[LOADER_EVAL] = uwsgi_eval_loader; up.loaders[LOADER_MOUNT] = uwsgi_mount_loader; up.loaders[LOADER_CALLABLE] = uwsgi_callable_loader; up.loaders[LOADER_STRING_CALLABLE] = uwsgi_string_callable_loader; struct uwsgi_string_list *upli = up.import_list; while(upli) { if (strchr(upli->value, '/') || uwsgi_endswith(upli->value, ".py")) { uwsgi_pyimport_by_filename(uwsgi_pythonize(upli->value), upli->value); } else { if (PyImport_ImportModule(upli->value) == NULL) { PyErr_Print(); } } upli = upli->next; } struct uwsgi_string_list *uppa = up.post_pymodule_alias; PyObject *modules = PyImport_GetModuleDict(); PyObject *tmp_module; while(uppa) { // split key=value char *value = strchr(uppa->value, '='); if (!value) { uwsgi_log("invalid pymodule-alias syntax\n"); goto next; } value[0] = 0; if (!strchr(value + 1, '/')) { // this is a standard pymodule tmp_module = PyImport_ImportModule(value + 1); if (!tmp_module) { PyErr_Print(); exit(1); } PyDict_SetItemString(modules, uppa->value, tmp_module); } else { // this is a filepath that need to be mapped tmp_module = uwsgi_pyimport_by_filename(uppa->value, value + 1); if (!tmp_module) { PyErr_Print(); exit(1); } } uwsgi_log("mapped virtual pymodule \"%s\" to real pymodule \"%s\"\n", uppa->value, value + 1); // reset original value value[0] = '='; next: uppa = uppa->next; } if (up.raw) { up.raw_callable = uwsgi_file_loader(up.raw); if (up.raw_callable) { Py_INCREF(up.raw_callable); } } if (up.wsgi_config != NULL) { init_uwsgi_app(LOADER_UWSGI, up.wsgi_config, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI); } if (up.file_config != NULL) { init_uwsgi_app(LOADER_FILE, up.file_config, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI); } if (up.pecan != NULL) { init_uwsgi_app(LOADER_PECAN, up.pecan, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI); } if (up.paste != NULL) { init_uwsgi_app(LOADER_PASTE, up.paste, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI); } if (up.eval != NULL) { init_uwsgi_app(LOADER_EVAL, up.eval, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI); } if (up.web3 != NULL) { init_uwsgi_app(LOADER_UWSGI, up.web3, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WEB3); } if (up.pump != NULL) { init_uwsgi_app(LOADER_UWSGI, up.pump, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_PUMP); } if (up.wsgi_lite != NULL) { init_uwsgi_app(LOADER_UWSGI, up.wsgi_lite, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI_LITE); } if (uwsgi.profiler) { if (!strcmp(uwsgi.profiler, "pycall")) { PyEval_SetProfile(uwsgi_python_profiler_call, NULL); } else if (!strcmp(uwsgi.profiler, "pyline")) { PyEval_SetTrace(uwsgi_python_tracer, NULL); } } PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi"); if (uwsgi_dict) { up.after_req_hook = PyDict_GetItemString(uwsgi_dict, "after_req_hook"); if (up.after_req_hook) { Py_INCREF(up.after_req_hook); up.after_req_hook_args = PyTuple_New(0); Py_INCREF(up.after_req_hook_args); } } // lazy ? // Also necessary if uwsgi fork hooks called to update interpreter state if (uwsgi.mywid > 0 || up.call_uwsgi_fork_hooks) { UWSGI_RELEASE_GIL; } } void uwsgi_python_master_fixup(int step) { static int master_fixed = 0; static int worker_fixed = 0; if (!uwsgi.master_process) return; // Skip master fixup if uwsgi fork hooks called to update interpreter state if (up.call_uwsgi_fork_hooks) return; if (uwsgi.has_threads) { if (step == 0) { if (!master_fixed) { UWSGI_RELEASE_GIL; master_fixed = 1; } } else { if (!worker_fixed) { UWSGI_GET_GIL; worker_fixed = 1; } } } } void uwsgi_python_pre_uwsgi_fork() { if (!up.call_uwsgi_fork_hooks) return; if (uwsgi.has_threads) { // Acquire the gil and import lock before forking in order to avoid // deadlocks in workers UWSGI_GET_GIL #ifdef HAS_NOT_PYOS_FORK_STABLE_API _PyImport_AcquireLock(); #else PyOS_BeforeFork(); #endif } } void uwsgi_python_post_uwsgi_fork(int step) { if (!up.call_uwsgi_fork_hooks) return; if (uwsgi.has_threads) { if (step == 0) { // Release locks within master process #ifdef HAS_NOT_PYOS_FORK_STABLE_API _PyImport_ReleaseLock(); #else PyOS_AfterFork_Parent(); #endif UWSGI_RELEASE_GIL } else { // Ensure thread state and locks are cleaned up in child process #ifdef HAS_NOT_PYOS_FORK_STABLE_API PyOS_AfterFork(); #else PyOS_AfterFork_Child(); #endif } } } void uwsgi_python_enable_threads() { #ifdef UWSGI_SHOULD_CALL_PYEVAL_INITTHREADS PyEval_InitThreads(); #endif if (pthread_key_create(&up.upt_save_key, NULL)) { uwsgi_error("pthread_key_create()"); exit(1); } if (pthread_key_create(&up.upt_gil_key, NULL)) { uwsgi_error("pthread_key_create()"); exit(1); } pthread_setspecific(up.upt_save_key, (void *) PyThreadState_Get()); pthread_setspecific(up.upt_gil_key, (void *) PyThreadState_Get()); pthread_mutex_init(&up.lock_pyloaders, NULL); pthread_atfork(uwsgi_python_pthread_prepare, uwsgi_python_pthread_parent, uwsgi_python_pthread_child); up.gil_get = gil_real_get; up.gil_release = gil_real_release; up.swap_ts = simple_threaded_swap_ts; up.reset_ts = simple_threaded_reset_ts; if (uwsgi.threads > 1) { up.swap_ts = threaded_swap_ts; up.reset_ts = threaded_reset_ts; } // Release the newly created gil from call to PyEval_InitThreads above // Necessary if uwsgi fork hooks called to update interpreter state if (up.call_uwsgi_fork_hooks) { UWSGI_RELEASE_GIL } uwsgi_log("python threads support enabled\n"); } void uwsgi_python_set_thread_name(int core_id) { // call threading.current_thread (taken from mod_wsgi, but removes DECREFs as thread in uWSGI are fixed) PyObject *threading_module = PyImport_ImportModule("threading"); if (threading_module) { PyObject *threading_module_dict = PyModule_GetDict(threading_module); if (threading_module_dict) { PyObject *threading_current = PyDict_GetItemString(threading_module_dict, "current_thread"); if (threading_current) { PyObject *current_thread = PyObject_CallObject(threading_current, (PyObject *)NULL); if (!current_thread) { // ignore the error PyErr_Clear(); } else { #ifdef PYTHREE PyObject_SetAttrString(current_thread, "name", PyUnicode_FromFormat("uWSGIWorker%dCore%d", uwsgi.mywid, core_id)); #else PyObject_SetAttrString(current_thread, "name", PyString_FromFormat("uWSGIWorker%dCore%d", uwsgi.mywid, core_id)); #endif Py_INCREF(current_thread); } } } } } void uwsgi_python_init_thread(int core_id) { // set a new ThreadState for each thread PyThreadState *pts; pts = PyThreadState_New(up.main_thread->interp); pthread_setspecific(up.upt_save_key, (void *) pts); pthread_setspecific(up.upt_gil_key, (void *) pts); #ifdef UWSGI_DEBUG uwsgi_log("python ThreadState %d = %p\n", core_id, pts); #endif UWSGI_GET_GIL; uwsgi_python_set_thread_name(core_id); UWSGI_RELEASE_GIL; } int uwsgi_check_python_mtime(PyObject *times_dict, char *filename) { struct stat st; PyObject *py_mtime = PyDict_GetItemString(times_dict, filename); if (!py_mtime) { if (stat(filename, &st)) { return 0; } PyDict_SetItemString(times_dict, filename, PyLong_FromLong(st.st_mtime)); } // the record is already tracked; else { long mtime = PyLong_AsLong(py_mtime); if (stat(filename, &st)) { return 0; } if ((long) st.st_mtime != mtime) { uwsgi_log("[uwsgi-python-reloader] module/file %s has been modified\n", filename); kill(uwsgi.workers[0].pid, SIGHUP); return 1; } } return 0; } PyObject *uwsgi_python_setup_thread(char *name) { // block signals on this thread sigset_t smask; sigfillset(&smask); #ifndef UWSGI_DEBUG sigdelset(&smask, SIGSEGV); #endif pthread_sigmask(SIG_BLOCK, &smask, NULL); PyThreadState *pts = PyThreadState_New(up.main_thread->interp); pthread_setspecific(up.upt_save_key, (void *) pts); pthread_setspecific(up.upt_gil_key, (void *) pts); UWSGI_GET_GIL; PyObject *threading_module = PyImport_ImportModule("threading"); if (threading_module) { PyObject *threading_module_dict = PyModule_GetDict(threading_module); if (threading_module_dict) { PyObject *threading_current = PyDict_GetItemString(threading_module_dict, "current_thread"); if (threading_current) { PyObject *current_thread = PyObject_CallObject(threading_current, (PyObject *)NULL); if (!current_thread) { // ignore the error PyErr_Clear(); } else { PyObject_SetAttrString(current_thread, "name", PyString_FromString(name)); Py_INCREF(current_thread); return current_thread; } } } } return NULL; } void *uwsgi_python_autoreloader_thread(void *foobar) { PyObject *new_thread = uwsgi_python_setup_thread("uWSGIAutoReloader"); if (!new_thread) return NULL; PyObject *modules = PyImport_GetModuleDict(); if (uwsgi.mywid == 1) { uwsgi_log("Python auto-reloader enabled\n"); } PyObject *times_dict = PyDict_New(); char *filename; for(;;) { UWSGI_RELEASE_GIL; sleep(up.auto_reload); UWSGI_GET_GIL; if (uwsgi.lazy || uwsgi.lazy_apps) { // do not start monitoring til the first app is loaded (required for lazy mode) if (uwsgi_apps_cnt == 0) continue; } #ifdef UWSGI_PYTHON_OLD int pos = 0; #else Py_ssize_t pos = 0; #endif PyObject *mod_name, *mod; while (PyDict_Next(modules, &pos, &mod_name, &mod)) { if (mod == NULL) continue; int found = 0; struct uwsgi_string_list *usl = up.auto_reload_ignore; while(usl) { #ifdef PYTHREE PyObject *zero = PyUnicode_AsUTF8String(mod_name); char *str_mod_name = PyString_AsString(zero); int ret_cmp = strcmp(usl->value, str_mod_name); Py_DECREF(zero); if (!ret_cmp) { #else if (!strcmp(usl->value, PyString_AsString(mod_name))) { #endif found = 1; break; } usl = usl->next; } if (found) continue; if (!PyObject_HasAttrString(mod, "__file__")) continue; PyObject *mod_file = PyObject_GetAttrString(mod, "__file__"); if (!mod_file) continue; if (mod_file == Py_None) continue; #ifdef PYTHREE PyObject *zero = PyUnicode_AsUTF8String(mod_file); char *mod_filename = PyString_AsString(zero); #else char *mod_filename = PyString_AsString(mod_file); #endif if (!mod_filename) { #ifdef PYTHREE Py_DECREF(zero); #endif continue; } char *ext = strrchr(mod_filename, '.'); if (ext && (!strcmp(ext+1, "pyc") || !strcmp(ext+1, "pyd") || !strcmp(ext+1, "pyo"))) { filename = uwsgi_concat2n(mod_filename, strlen(mod_filename)-1, "", 0); } else { filename = uwsgi_concat2(mod_filename, ""); } if (uwsgi_check_python_mtime(times_dict, filename)) { UWSGI_RELEASE_GIL; return NULL; } free(filename); #ifdef PYTHREE Py_DECREF(zero); #endif } } return NULL; } void uwsgi_python_suspend(struct wsgi_request *wsgi_req) { PyGILState_STATE pgst = PyGILState_Ensure(); PyThreadState *tstate = PyThreadState_GET(); PyGILState_Release(pgst); if (wsgi_req) { #ifdef UWSGI_PY313 up.current_c_recursion_remaining[wsgi_req->async_id] = tstate->c_recursion_remaining; up.current_py_recursion_remaining[wsgi_req->async_id] = tstate->py_recursion_remaining; up.current_frame[wsgi_req->async_id] = tstate->current_frame; #elif defined UWSGI_PY312 up.current_c_recursion_remaining[wsgi_req->async_id] = tstate->c_recursion_remaining; up.current_py_recursion_remaining[wsgi_req->async_id] = tstate->py_recursion_remaining; up.current_frame[wsgi_req->async_id] = tstate->cframe; #elif defined UWSGI_PY311 up.current_recursion_remaining[wsgi_req->async_id] = tstate->recursion_remaining; up.current_frame[wsgi_req->async_id] = tstate->cframe; #else up.current_recursion_depth[wsgi_req->async_id] = tstate->recursion_depth; up.current_frame[wsgi_req->async_id] = tstate->frame; #endif } else { #ifdef UWSGI_PY313 up.current_main_c_recursion_remaining = tstate->c_recursion_remaining; up.current_main_py_recursion_remaining = tstate->py_recursion_remaining; up.current_main_frame = tstate->current_frame; #elif defined UWSGI_PY312 up.current_main_c_recursion_remaining = tstate->c_recursion_remaining; up.current_main_py_recursion_remaining = tstate->py_recursion_remaining; up.current_main_frame = tstate->cframe; #elif defined UWSGI_PY311 up.current_main_recursion_remaining = tstate->recursion_remaining; up.current_main_frame = tstate->cframe; #else up.current_main_recursion_depth = tstate->recursion_depth; up.current_main_frame = tstate->frame; #endif } } char *uwsgi_python_code_string(char *id, char *code, char *function, char *key, uint16_t keylen) { PyObject *cs_module = NULL; PyObject *cs_dict = NULL; UWSGI_GET_GIL; cs_module = PyImport_ImportModule(id); if (!cs_module) { PyErr_Clear(); cs_module = uwsgi_pyimport_by_filename(id, code); } if (!cs_module) { UWSGI_RELEASE_GIL; return NULL; } cs_dict = PyModule_GetDict(cs_module); if (!cs_dict) { PyErr_Print(); UWSGI_RELEASE_GIL; return NULL; } PyObject *func = PyDict_GetItemString(cs_dict, function); if (!func) { uwsgi_log("function %s not available in %s\n", function, code); PyErr_Print(); UWSGI_RELEASE_GIL; return NULL; } PyObject *args = PyTuple_New(1); PyTuple_SetItem(args, 0, PyString_FromStringAndSize(key, keylen)); PyObject *ret = python_call(func, args, 0, NULL); Py_DECREF(args); if (ret && PyString_Check(ret)) { char *val = PyString_AsString(ret); UWSGI_RELEASE_GIL; return val; } UWSGI_RELEASE_GIL; return NULL; } int uwsgi_python_signal_handler(uint8_t sig, void *handler) { UWSGI_GET_GIL; PyObject *args = PyTuple_New(1); PyObject *ret; if (!args) goto clear; if (!handler) goto clear; PyTuple_SetItem(args, 0, PyInt_FromLong(sig)); ret = python_call(handler, args, 0, NULL); Py_DECREF(args); if (ret) { Py_DECREF(ret); UWSGI_RELEASE_GIL; return 0; } clear: UWSGI_RELEASE_GIL; return -1; } uint64_t uwsgi_python_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char **buffer) { UWSGI_GET_GIL; uint8_t i; char *rv; size_t rl; PyObject *pyargs = PyTuple_New(argc); PyObject *ret; if (!pyargs) { UWSGI_RELEASE_GIL; return 0; } for (i = 0; i < argc; i++) { PyTuple_SetItem(pyargs, i, PyString_FromStringAndSize(argv[i], argvs[i])); } ret = python_call((PyObject *) func, pyargs, 0, NULL); Py_DECREF(pyargs); if (ret) { if (PyString_Check(ret)) { rv = PyString_AsString(ret); rl = PyString_Size(ret); if (rl > 0) { *buffer = uwsgi_malloc(rl); memcpy(*buffer, rv, rl); Py_DECREF(ret); UWSGI_RELEASE_GIL; return rl; } } Py_DECREF(ret); } if (PyErr_Occurred()) PyErr_Print(); UWSGI_RELEASE_GIL; return 0; } void uwsgi_python_add_item(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) { PyObject *pydict = (PyObject *) data; PyObject *o_key = PyString_FromStringAndSize(key, keylen); PyObject *zero = PyString_FromStringAndSize(val, vallen); PyDict_SetItem(pydict, o_key, zero); Py_DECREF(o_key); Py_DECREF(zero); } PyObject *uwsgi_python_dict_from_spooler_content(char *filename, char *buf, uint16_t len, char *body, size_t body_len) { PyObject *spool_dict = PyDict_New(); PyObject *value = PyString_FromString(filename); PyDict_SetItemString(spool_dict, "spooler_task_name", value); Py_DECREF(value); if (uwsgi_hooked_parse(buf, len, uwsgi_python_add_item, spool_dict)) return NULL; if (body && body_len > 0) { PyObject *value = PyString_FromStringAndSize(body, body_len); PyDict_SetItemString(spool_dict, "body", value); Py_DECREF(value); } return spool_dict; } int uwsgi_python_spooler(char *filename, char *buf, uint16_t len, char *body, size_t body_len) { static int random_seed_reset = 0; UWSGI_GET_GIL; if (!random_seed_reset) { uwsgi_python_reset_random_seed(); random_seed_reset = 1; } if (!up.embedded_dict) { // ignore UWSGI_RELEASE_GIL; return 0; } PyObject *spool_func = PyDict_GetItemString(up.embedded_dict, "spooler"); if (!spool_func) { // ignore UWSGI_RELEASE_GIL; return 0; } int retval = -1; PyObject *pyargs = PyTuple_New(1); PyObject *ret = NULL; PyObject *spool_dict = uwsgi_python_dict_from_spooler_content(filename, buf, len, body, body_len); if (!spool_dict) { retval = -2; goto clear; } // PyTuple_SetItem steals a reference !!! Py_INCREF(spool_dict); PyTuple_SetItem(pyargs, 0, spool_dict); ret = python_call(spool_func, pyargs, 0, NULL); if (ret) { if (!PyInt_Check(ret)) { retval = -1; // error, retry } else { retval = (int) PyInt_AsLong(ret); } goto clear; } if (PyErr_Occurred()) PyErr_Print(); // error, retry retval = -1; clear: Py_XDECREF(ret); Py_XDECREF(pyargs); Py_XDECREF(spool_dict); UWSGI_RELEASE_GIL; return retval; } void uwsgi_python_resume(struct wsgi_request *wsgi_req) { PyGILState_STATE pgst = PyGILState_Ensure(); PyThreadState *tstate = PyThreadState_GET(); PyGILState_Release(pgst); if (wsgi_req) { #ifdef UWSGI_PY313 tstate->c_recursion_remaining = up.current_c_recursion_remaining[wsgi_req->async_id]; tstate->py_recursion_remaining = up.current_py_recursion_remaining[wsgi_req->async_id]; tstate->current_frame = up.current_frame[wsgi_req->async_id]; #elif defined UWSGI_PY312 tstate->c_recursion_remaining = up.current_c_recursion_remaining[wsgi_req->async_id]; tstate->py_recursion_remaining = up.current_py_recursion_remaining[wsgi_req->async_id]; tstate->cframe = up.current_frame[wsgi_req->async_id]; #elif defined UWSGI_PY311 tstate->recursion_remaining = up.current_recursion_remaining[wsgi_req->async_id]; tstate->cframe = up.current_frame[wsgi_req->async_id]; #else tstate->recursion_depth = up.current_recursion_depth[wsgi_req->async_id]; tstate->frame = up.current_frame[wsgi_req->async_id]; #endif } else { #ifdef UWSGI_PY313 tstate->c_recursion_remaining = up.current_main_c_recursion_remaining; tstate->py_recursion_remaining = up.current_main_py_recursion_remaining; tstate->current_frame = up.current_main_frame; #elif defined UWSGI_PY312 tstate->c_recursion_remaining = up.current_main_c_recursion_remaining; tstate->py_recursion_remaining = up.current_main_py_recursion_remaining; tstate->cframe = up.current_main_frame; #elif defined UWSGI_PY311 tstate->recursion_remaining = up.current_main_recursion_remaining; tstate->cframe = up.current_main_frame; #else tstate->recursion_depth = up.current_main_recursion_depth; tstate->frame = up.current_main_frame; #endif } } void uwsgi_python_fixup() { // set hacky modifier 30 uwsgi.p[30] = uwsgi_malloc( sizeof(struct uwsgi_plugin) ); memcpy(uwsgi.p[30], uwsgi.p[0], sizeof(struct uwsgi_plugin) ); uwsgi.p[30]->init_thread = NULL; uwsgi.p[30]->atexit = NULL; } void uwsgi_python_hijack(void) { // the pyshell will be execute only in the first worker FILE *pyfile; if (up.pyrun) { uwsgi.workers[uwsgi.mywid].hijacked = 1; UWSGI_GET_GIL; pyfile = fopen(up.pyrun, "r"); if (!pyfile) { uwsgi_error_open(up.pyrun); exit(1); } PyRun_SimpleFile(pyfile, up.pyrun); // could be never executed exit(0); } if (up.pyshell_oneshot && uwsgi.workers[uwsgi.mywid].hijacked_count > 0) { uwsgi.workers[uwsgi.mywid].hijacked = 0; return; } if (up.pyshell && uwsgi.mywid == 1) { uwsgi.workers[uwsgi.mywid].hijacked = 1; uwsgi.workers[uwsgi.mywid].hijacked_count++; // re-map stdin to stdout and stderr if we are logging to a file if (uwsgi.logfile) { if (dup2(0, 1) < 0) { uwsgi_error("dup2()"); } if (dup2(0, 2) < 0) { uwsgi_error("dup2()"); } } UWSGI_GET_GIL; int ret = -1; if (up.pyshell[0] != 0) { ret = PyRun_SimpleString(up.pyshell); } else { PyImport_ImportModule("readline"); ret = PyRun_InteractiveLoop(stdin, "uwsgi"); } if (up.pyshell_oneshot) { exit(UWSGI_DE_HIJACKED_CODE); } if (ret == 0) { exit(UWSGI_QUIET_CODE); } exit(0); } } int uwsgi_python_mule(char *opt) { if (uwsgi_endswith(opt, ".py")) { UWSGI_GET_GIL; uwsgi_pyimport_by_filename("__main__", opt); UWSGI_RELEASE_GIL; return 1; } else if (strchr(opt, ':')) { UWSGI_GET_GIL; PyObject *result = NULL; PyObject *arglist = Py_BuildValue("()"); PyObject *callable = up.loaders[LOADER_MOUNT](opt); if (callable) { result = PyObject_CallObject(callable, arglist); } Py_XDECREF(result); Py_XDECREF(arglist); Py_XDECREF(callable); UWSGI_RELEASE_GIL; return 1; } return 0; } int uwsgi_python_mule_msg(char *message, size_t len) { UWSGI_GET_GIL; PyObject *mule_msg_hook = PyDict_GetItemString(up.embedded_dict, "mule_msg_hook"); if (!mule_msg_hook) { // ignore UWSGI_RELEASE_GIL; return 0; } PyObject *pyargs = PyTuple_New(1); PyTuple_SetItem(pyargs, 0, PyString_FromStringAndSize(message, len)); PyObject *ret = python_call(mule_msg_hook, pyargs, 0, NULL); Py_DECREF(pyargs); if (ret) { Py_DECREF(ret); } if (PyErr_Occurred()) PyErr_Print(); UWSGI_RELEASE_GIL; return 1; } static void uwsgi_python_harakiri(int wid) { if (up.tracebacker) { char buf[8192]; char *wid_str = uwsgi_num2str(wid); char *address = uwsgi_concat2(up.tracebacker, wid_str); int fd = uwsgi_connect(address, -1, 0); if (fd < 1) goto exit; for(;;) { int ret = uwsgi_waitfd(fd, uwsgi.socket_timeout); if (ret <= 0) goto cleanup; ssize_t len = read(fd, buf, 8192); if (len <= 0) goto cleanup; uwsgi_log("%.*s", (int) len, buf); } cleanup: close(fd); exit: free(wid_str); free(address); } } /* # you can use this logger to offload logging to python # be sure to configure it to not log to stderr otherwise you will generate a loop import logging logging.basicConfig(filename='/tmp/pippo.log') */ static ssize_t uwsgi_python_logger(struct uwsgi_logger *ul, char *message, size_t len) { if (!Py_IsInitialized()) return -1; UWSGI_GET_GIL if (!ul->configured) { PyObject *py_logging = PyImport_ImportModule("logging"); if (!py_logging) goto clear; PyObject *py_logging_dict = PyModule_GetDict(py_logging); if (!py_logging_dict) goto clear; PyObject *py_getLogger = PyDict_GetItemString(py_logging_dict, "getLogger"); if (!py_getLogger) goto clear; PyObject *py_getLogger_args = NULL; if (ul->arg) { py_getLogger_args = PyTuple_New(1); PyTuple_SetItem(py_getLogger_args, 0, UWSGI_PYFROMSTRING(ul->arg)); } ul->data = (void *) PyObject_CallObject(py_getLogger, py_getLogger_args); if (PyErr_Occurred()) { PyErr_Clear(); } Py_XDECREF(py_getLogger_args); if (!ul->data) goto clear; ul->configured = 1; } PyObject_CallMethod((PyObject *) ul->data, "error", "(s#)", message, len); if (PyErr_Occurred()) { PyErr_Clear(); } UWSGI_RELEASE_GIL return len; clear: UWSGI_RELEASE_GIL return -1; } static void uwsgi_python_on_load() { uwsgi_register_logger("python", uwsgi_python_logger); } static int uwsgi_python_worker() { if (!up.worker_override) return 0; UWSGI_GET_GIL; // ensure signals can be used again from python // Necessary if fork hooks have been not used to update interpreter state if (!up.call_osafterfork && !up.call_uwsgi_fork_hooks) #ifdef HAS_NOT_PYOS_FORK_STABLE_API PyOS_AfterFork(); #else PyOS_AfterFork_Child(); #endif FILE *pyfile = fopen(up.worker_override, "r"); if (!pyfile) { uwsgi_error_open(up.worker_override); exit(1); } PyRun_SimpleFile(pyfile, up.worker_override); return 1; } struct uwsgi_plugin python_plugin = { .name = "python", .alias = "python", .modifier1 = 0, .init = uwsgi_python_init, .post_fork = uwsgi_python_post_fork, .options = uwsgi_python_options, .request = uwsgi_request_wsgi, .after_request = uwsgi_after_request_wsgi, .preinit_apps = uwsgi_python_preinit_apps, .init_apps = uwsgi_python_init_apps, .fixup = uwsgi_python_fixup, .master_fixup = uwsgi_python_master_fixup, .mount_app = uwsgi_python_mount_app, .enable_threads = uwsgi_python_enable_threads, .init_thread = uwsgi_python_init_thread, .magic = uwsgi_python_magic, .suspend = uwsgi_python_suspend, .resume = uwsgi_python_resume, .harakiri = uwsgi_python_harakiri, .hijack_worker = uwsgi_python_hijack, .spooler_init = uwsgi_python_spooler_init, .signal_handler = uwsgi_python_signal_handler, .rpc = uwsgi_python_rpc, .mule = uwsgi_python_mule, .mule_msg = uwsgi_python_mule_msg, .on_load = uwsgi_python_on_load, .spooler = uwsgi_python_spooler, .atexit = uwsgi_python_atexit, .code_string = uwsgi_python_code_string, .exception_class = uwsgi_python_exception_class, .exception_msg = uwsgi_python_exception_msg, .exception_repr = uwsgi_python_exception_repr, .exception_log = uwsgi_python_exception_log, .backtrace = uwsgi_python_backtrace, .worker = uwsgi_python_worker, .pre_uwsgi_fork = uwsgi_python_pre_uwsgi_fork, .post_uwsgi_fork = uwsgi_python_post_uwsgi_fork, }; uwsgi-2.0.29/plugins/python/pyutils.c000066400000000000000000000240761477626554400176560ustar00rootroot00000000000000#include "uwsgi_python.h" extern struct uwsgi_server uwsgi; extern struct uwsgi_python up; int manage_python_response(struct wsgi_request *wsgi_req) { // use standard WSGI response parse return uwsgi_response_subhandler_wsgi(wsgi_req); } char *uwsgi_python_get_exception_type(PyObject *exc) { char *class_name = NULL; #if !defined(PYTHREE) if (PyClass_Check(exc)) { class_name = PyString_AsString( ((PyClassObject*)(exc))->cl_name ); } else { #endif class_name = (char *) ((PyTypeObject*)exc)->tp_name; #if !defined(PYTHREE) } #endif if (class_name) { char *dot = strrchr(class_name, '.'); if (dot) class_name = dot+1; PyObject *module_name = PyObject_GetAttrString(exc, "__module__"); if (module_name) { #ifdef PYTHREE char *mod_name = NULL; PyObject *zero = PyUnicode_AsUTF8String(module_name); if (zero) { mod_name = PyString_AsString(zero); } #else char *mod_name = PyString_AsString(module_name); #endif if (mod_name && strcmp(mod_name, "exceptions") ) { char *ret = uwsgi_concat3(mod_name, ".", class_name); #ifdef PYTHREE Py_DECREF(zero); #endif Py_DECREF(module_name); return ret; } Py_DECREF(module_name); return uwsgi_str(class_name); } } return NULL; } struct uwsgi_buffer *uwsgi_python_backtrace(struct wsgi_request *wsgi_req) { PyObject *type = NULL; PyObject *value = NULL; PyObject *traceback = NULL; struct uwsgi_buffer *ub = NULL; PyErr_Fetch(&type, &value, &traceback); PyErr_NormalizeException(&type, &value, &traceback); // traceback could not be available if (!traceback) goto end; PyObject *traceback_module = PyImport_ImportModule("traceback"); if (!traceback_module) { goto end; } PyObject *traceback_dict = PyModule_GetDict(traceback_module); PyObject *extract_tb = PyDict_GetItemString(traceback_dict, "extract_tb"); if (!extract_tb) goto end; PyObject *args = PyTuple_New(1); Py_INCREF(traceback); PyTuple_SetItem(args, 0, traceback); PyObject *result = PyObject_CallObject(extract_tb, args); Py_DECREF(args); if (!result) goto end; ub = uwsgi_buffer_new(4096); Py_ssize_t i; // we have to build a uwsgi array with 5 items (4 are taken from the python tb) for(i=0;i< PySequence_Size(result);i++) { PyObject *t = PySequence_GetItem(result, i); PyObject *tb_filename = PySequence_GetItem(t, 0); PyObject *tb_lineno = PySequence_GetItem(t, 1); PyObject *tb_function = PySequence_GetItem(t, 2); PyObject *tb_text = PySequence_GetItem(t, 3); int64_t line_no = PyInt_AsLong(tb_lineno); #ifdef PYTHREE PyObject *zero = NULL; if (tb_filename) { zero = PyUnicode_AsUTF8String(tb_filename); if (!zero) goto end0; // filename if (uwsgi_buffer_u16le(ub, PyString_Size(zero))) { Py_DECREF(zero); goto end0; } if (uwsgi_buffer_append(ub, PyString_AsString(zero), PyString_Size(zero))) { Py_DECREF(zero); goto end0; } Py_DECREF(zero); } else { if (uwsgi_buffer_u16le(ub, 0)) { goto end0; } } // lineno if (uwsgi_buffer_append_valnum(ub, line_no)) goto end0; if (tb_function) { zero = PyUnicode_AsUTF8String(tb_function); if (!zero) goto end0; // function if (uwsgi_buffer_u16le(ub, PyString_Size(zero))) { Py_DECREF(zero); goto end0; } if (uwsgi_buffer_append(ub, PyString_AsString(zero), PyString_Size(zero))) { Py_DECREF(zero); goto end0; } Py_DECREF(zero); } else { if (uwsgi_buffer_u16le(ub, 0)) { goto end0; } } if (tb_text) { zero = PyUnicode_AsUTF8String(tb_text); if (!zero) goto end0; // text if (uwsgi_buffer_u16le(ub, PyString_Size(zero))) { Py_DECREF(zero); goto end0; } if (uwsgi_buffer_append(ub, PyString_AsString(zero), PyString_Size(zero))) { Py_DECREF(zero); goto end0; } Py_DECREF(zero); } else { if (uwsgi_buffer_u16le(ub, 0)) { goto end0; } } #else // filename if (uwsgi_buffer_u16le(ub, PyString_Size(tb_filename))) goto end0; if (uwsgi_buffer_append(ub, PyString_AsString(tb_filename), PyString_Size(tb_filename))) goto end0; // lineno if (uwsgi_buffer_append_valnum(ub, line_no)) goto end0; // function if (uwsgi_buffer_u16le(ub, PyString_Size(tb_function))) goto end0; if (uwsgi_buffer_append(ub, PyString_AsString(tb_function), PyString_Size(tb_function))) goto end0; // text if (uwsgi_buffer_u16le(ub, PyString_Size(tb_text))) goto end0; if (uwsgi_buffer_append(ub, PyString_AsString(tb_text), PyString_Size(tb_text))) goto end0; #endif // custom (unused) if (uwsgi_buffer_u16le(ub, 0)) goto end0; if (uwsgi_buffer_append(ub, "", 0)) goto end0; } Py_DECREF(result); goto end; end0: Py_DECREF(result); uwsgi_buffer_destroy(ub); ub = NULL; end: PyErr_Restore(type, value, traceback); return ub; } struct uwsgi_buffer *uwsgi_python_exception_class(struct wsgi_request *wsgi_req) { PyObject *type = NULL; PyObject *value = NULL; PyObject *traceback = NULL; struct uwsgi_buffer *ub = NULL; PyErr_Fetch(&type, &value, &traceback); PyErr_NormalizeException(&type, &value, &traceback); char *class = uwsgi_python_get_exception_type(type); if (class) { size_t class_len = strlen(class); ub = uwsgi_buffer_new(class_len); if (uwsgi_buffer_append(ub, class, class_len)) { uwsgi_buffer_destroy(ub); ub = NULL; goto end; } } end: free(class); PyErr_Restore(type, value, traceback); return ub; } struct uwsgi_buffer *uwsgi_python_exception_msg(struct wsgi_request *wsgi_req) { PyObject *type = NULL; PyObject *value = NULL; PyObject *traceback = NULL; struct uwsgi_buffer *ub = NULL; PyErr_Fetch(&type, &value, &traceback); PyErr_NormalizeException(&type, &value, &traceback); // value could be NULL ? if (!value) goto end; #ifdef PYTHREE char *msg = NULL; PyObject *zero = PyUnicode_AsUTF8String( PyObject_Str(value) ); if (zero) { msg = PyString_AsString( zero ); } #else char *msg = PyString_AsString( PyObject_Str(value) ); #endif if (msg) { size_t msg_len = strlen(msg); ub = uwsgi_buffer_new(msg_len); if (uwsgi_buffer_append(ub, msg, msg_len)) { #ifdef PYTHREE Py_DECREF(zero); #endif uwsgi_buffer_destroy(ub); ub = NULL; goto end; } #ifdef PYTHREE Py_DECREF(zero); #endif } end: PyErr_Restore(type, value, traceback); return ub; } struct uwsgi_buffer *uwsgi_python_exception_repr(struct wsgi_request *wsgi_req) { struct uwsgi_buffer *ub_class = uwsgi_python_exception_class(wsgi_req); if (!ub_class) return NULL; struct uwsgi_buffer *ub_msg = uwsgi_python_exception_msg(wsgi_req); if (!ub_msg) { uwsgi_buffer_destroy(ub_class); return NULL; } struct uwsgi_buffer *ub = uwsgi_buffer_new(ub_class->pos + 2 + ub_msg->pos); if (uwsgi_buffer_append(ub, ub_class->buf, ub_class->pos)) goto error; if (uwsgi_buffer_append(ub, ": ", 2)) goto error; if (uwsgi_buffer_append(ub, ub_msg->buf, ub_msg->pos)) goto error; uwsgi_buffer_destroy(ub_class); uwsgi_buffer_destroy(ub_msg); return ub; error: uwsgi_buffer_destroy(ub_class); uwsgi_buffer_destroy(ub_msg); uwsgi_buffer_destroy(ub); return NULL; } void uwsgi_python_exception_log(struct wsgi_request *wsgi_req) { PyErr_Print(); } PyObject *python_call(PyObject *callable, PyObject *args, int catch, struct wsgi_request *wsgi_req) { //uwsgi_log("ready to call %p %p\n", callable, args); PyObject *pyret = PyObject_CallObject(callable, args); //uwsgi_log("called\n"); if (PyErr_Occurred()) { if (wsgi_req) { uwsgi_manage_exception(wsgi_req, catch); } else { PyErr_Print(); } } #ifdef UWSGI_DEBUG if (pyret) { uwsgi_debug("called %p %p %d\n", callable, args, pyret->ob_refcnt); } #endif return pyret; } int uwsgi_python_call(struct wsgi_request *wsgi_req, PyObject *callable, PyObject *args) { wsgi_req->async_result = python_call(callable, args, 0, wsgi_req); if (wsgi_req->async_result) { while ( manage_python_response(wsgi_req) != UWSGI_OK) { if (uwsgi.async > 1) { return UWSGI_AGAIN; } } } return UWSGI_OK; } void init_pyargv() { char *ap; char *argv0 = "uwsgi"; if (up.pyrun) { argv0 = up.pyrun; } #ifdef PYTHREE wchar_t *pname = uwsgi_calloc(sizeof(wchar_t) * (strlen(argv0)+1)); mbstowcs(pname, argv0, strlen(argv0)+1); #else char *pname = argv0; #endif up.argc = 1; if (up.argv) { char *tmp_ptr = uwsgi_str(up.argv); #ifdef __sun__ // FIX THIS !!! char *ctx = NULL; ap = strtok_r(tmp_ptr, " ", &ctx); while ((ap = strtok_r(NULL, " ", &ctx)) != NULL) { #else while ((ap = strsep(&tmp_ptr, " \t")) != NULL) { #endif if (*ap != '\0') { up.argc++; } } free(tmp_ptr); } #ifdef PYTHREE up.py_argv = uwsgi_calloc(sizeof(wchar_t *) * up.argc+1); #else up.py_argv = uwsgi_calloc(sizeof(char *) * up.argc+1); #endif up.py_argv[0] = pname; if (up.argv) { char *py_argv_copy = uwsgi_str(up.argv); up.argc = 1; #ifdef PYTHREE wchar_t *wcargv = uwsgi_calloc( sizeof( wchar_t ) * (strlen(py_argv_copy)+1)); #endif #ifdef __sun__ // FIX THIS !!! char *ctx = NULL; ap = strtok_r(py_argv_copy, " ", &ctx); while ((ap = strtok_r(NULL, " ", &ctx)) != NULL) { #else while ((ap = strsep(&py_argv_copy, " \t")) != NULL) { #endif if (*ap != '\0') { #ifdef PYTHREE mbstowcs( wcargv, ap, strlen(ap)); up.py_argv[up.argc] = wcargv; wcargv += strlen(ap) + 1; #else up.py_argv[up.argc] = ap; #endif up.argc++; } } } PySys_SetArgv(up.argc, up.py_argv); PyObject *sys_dict = get_uwsgi_pydict("sys"); if (!sys_dict) { uwsgi_log("unable to load python sys module !!!\n"); exit(1); } if (!up.executable) up.executable = uwsgi.binary_path; #ifdef PYTHREE PyDict_SetItemString(sys_dict, "executable", PyUnicode_FromString(up.executable)); #else PyDict_SetItemString(sys_dict, "executable", PyString_FromString(up.executable)); #endif } uwsgi-2.0.29/plugins/python/raw.c000066400000000000000000000046121477626554400167300ustar00rootroot00000000000000#include "uwsgi_python.h" extern struct uwsgi_server uwsgi; extern struct uwsgi_python up; static int manage_raw_response(struct wsgi_request *wsgi_req) { int ret = 0; if (!wsgi_req->async_force_again) { ret = uwsgi_python_send_body(wsgi_req, (PyObject *) wsgi_req->async_result); if (ret == 0) { if (PyInt_Check((PyObject *) wsgi_req->async_result) || PyObject_HasAttrString((PyObject *) wsgi_req->async_result, "fileno")) { // is it a file ? int fd = PyObject_AsFileDescriptor((PyObject *) wsgi_req->async_result); if (fd >= 0) { wsgi_req->sendfile_fd = fd; uwsgi_response_sendfile_do(wsgi_req, fd, 0, 0); wsgi_req->sendfile_fd = -1; return UWSGI_OK; } } } } if (ret == 0) { if (!wsgi_req->async_placeholder) { wsgi_req->async_placeholder = PyObject_GetIter((PyObject *) wsgi_req->async_result); if (!wsgi_req->async_placeholder) return UWSGI_OK; } PyObject *pychunk = PyIter_Next((PyObject *) wsgi_req->async_placeholder); if (!pychunk) return UWSGI_OK; ret = uwsgi_python_send_body(wsgi_req, pychunk); if (ret == 0) { if (PyInt_Check(pychunk) || PyObject_HasAttrString(pychunk, "fileno")) { // is it a file ? int fd = PyObject_AsFileDescriptor(pychunk); if (fd >= 0) { wsgi_req->sendfile_fd = fd; uwsgi_response_sendfile_do(wsgi_req, fd, 0, 0); wsgi_req->sendfile_fd = -1; } } } Py_DECREF(pychunk); return UWSGI_AGAIN; } return UWSGI_OK; } int uwsgi_request_python_raw(struct wsgi_request *wsgi_req) { if (!up.raw_callable) return UWSGI_OK; // back from async if (wsgi_req->async_force_again) { UWSGI_GET_GIL int ret = manage_raw_response(wsgi_req); if (ret == UWSGI_AGAIN) { wsgi_req->async_force_again = 1; UWSGI_RELEASE_GIL return UWSGI_AGAIN; } goto end; } UWSGI_GET_GIL PyObject * args = PyTuple_New(1); PyTuple_SetItem(args, 0, PyInt_FromLong(wsgi_req->fd)); wsgi_req->async_result = PyObject_CallObject(up.raw_callable, args); Py_DECREF(args); if (wsgi_req->async_result) { for (;;) { int ret = manage_raw_response(wsgi_req); if (ret == UWSGI_AGAIN) { wsgi_req->async_force_again = 1; if (uwsgi.async > 1) { UWSGI_RELEASE_GIL return UWSGI_AGAIN; } continue; } break; } } end: if (PyErr_Occurred()) PyErr_Print(); if (wsgi_req->async_result) { Py_DECREF((PyObject *) wsgi_req->async_result); } UWSGI_RELEASE_GIL; return UWSGI_OK; } uwsgi-2.0.29/plugins/python/symimporter.c000066400000000000000000000545141477626554400205370ustar00rootroot00000000000000#include "uwsgi_python.h" extern struct uwsgi_server uwsgi; extern struct uwsgi_python up; struct _symimporter { PyObject_HEAD; } uwsgi_symbol_importer_object; struct _symzipimporter { PyObject_HEAD; char *prefix; PyObject *zip; PyObject *items; } uwsgi_symbol_zip_importer_object; static char *symbolize(char *name) { char *base = uwsgi_concat2(name, ""); char *ptr = base; while(*ptr != 0) { if (*ptr == '.') { *ptr = '_'; } ptr++; } return base; } static char *name_to_py(char *prefix, char *name) { char *base; char *ptr; if (prefix) { if (prefix[strlen(prefix)-1] == '/') { base = uwsgi_concat3(prefix, name, ".py"); ptr = base + strlen(prefix); } else { base = uwsgi_concat4(prefix, "/", name, ".py"); ptr = base + strlen(prefix) + 1; } } else { base = uwsgi_concat2(name, ".py"); ptr = base; } while(*ptr != 0) { if (*ptr == '.') { *ptr = '/'; } ptr++; } // fix .py ptr-=3; *ptr = '.'; return base; } static char *name_to_init_py(char *prefix, char *name) { char *base; char *ptr; if (prefix) { if (prefix[strlen(prefix)-1] == '/') { base = uwsgi_concat3(prefix, name, "/__init__.py"); ptr = base + strlen(prefix); } else { base = uwsgi_concat4(prefix, "/", name, "/__init__.py"); ptr = base + strlen(prefix) + 1; } } else { base = uwsgi_concat2(name, "/__init__.py"); ptr = base; } while(*ptr != 0) { if (*ptr == '.') { *ptr = '/'; } ptr++; } // fix .py ptr-=3; *ptr = '.'; return base; } static char *name_to_symbol(char *name, char *what) { char *symbol = uwsgi_concat4("_binary_", name, "_", what); char *sym_ptr_start = dlsym(RTLD_DEFAULT, symbol); free(symbol); return sym_ptr_start; } static char *name_to_symbol_module(char *name, char *what) { char *symbol = uwsgi_concat4("_binary_", name, "_py_", what); char *sym_ptr_start = dlsym(RTLD_DEFAULT, symbol); free(symbol); return sym_ptr_start; } static char *name_to_symbol_pkg(char *name, char *what) { char *symbol = uwsgi_concat4("_binary_", name, "___init___py_", what); char *sym_ptr_start = dlsym(RTLD_DEFAULT, symbol); free(symbol); return sym_ptr_start; } int py_list_has_string(PyObject *obj, char *name) { Py_ssize_t i, len = PyList_Size(obj); int found = 0; for(i=0;iprefix, fullname); if (py_list_has_string(this->items, filename)) { free(filename); return self; } PyErr_Clear(); free(filename); filename = name_to_init_py(this->prefix, fullname); if (py_list_has_string(this->items, filename)) { free(filename); return self; } PyErr_Clear(); free(filename); Py_INCREF(Py_None); return Py_None; } static PyObject* symzipimporter_load_module(PyObject *self, PyObject *args) { char *fullname; char *modname; struct _symzipimporter *this = (struct _symzipimporter *) self; if (!PyArg_ParseTuple(args, "s:load_module", &fullname)) { return NULL; } char *filename = name_to_py(this->prefix, fullname); if (py_list_has_string(this->items, filename)) { PyObject *mod = PyImport_AddModule(fullname); if (!mod) goto clear; PyObject *dict = PyModule_GetDict(mod); if (!dict) goto clear; PyDict_SetItemString(dict, "__loader__", self); modname = uwsgi_concat2("symzip://", fullname); PyObject *source = PyObject_CallMethod(this->zip, "read", "(s)", filename); free(filename); PyObject *code = Py_CompileString(PyString_AsString(source), modname, Py_file_input); if (!code) { PyErr_Print(); goto shit; } mod = PyImport_ExecCodeModuleEx(fullname, code, modname); Py_DECREF(code); shit: Py_DECREF(source); free(modname); return mod; } PyErr_Clear(); free(filename); filename = name_to_init_py(this->prefix, fullname); if (py_list_has_string(this->items, filename)) { PyObject *mod = PyImport_AddModule(fullname); if (!mod) goto clear; PyObject *dict = PyModule_GetDict(mod); if (!dict) goto clear; modname = uwsgi_concat2("symzip://", fullname); PyObject *pkgpath = Py_BuildValue("[O]", PyString_FromString(modname)); PyDict_SetItemString(dict, "__path__", pkgpath); PyDict_SetItemString(dict, "__loader__", self); PyObject *source = PyObject_CallMethod(this->zip, "read", "(s)", filename); free(filename); PyObject *code = Py_CompileString(PyString_AsString(source), modname, Py_file_input); if (!code) { PyErr_Print(); goto shit2; } mod = PyImport_ExecCodeModuleEx(fullname, code, modname); Py_DECREF(code); shit2: Py_DECREF(source); free(modname); return mod; } clear: PyErr_Clear(); free(filename); Py_INCREF(Py_None); return Py_None; } static PyObject* symimporter_find_module(PyObject *self, PyObject *args) { char *fullname; PyObject *path = NULL; if (!PyArg_ParseTuple(args, "s|O:find_module", &fullname, &path)) { return NULL; } char *fullname2 = symbolize(fullname); char *code_start = name_to_symbol_module(fullname2, "start"); if (code_start) { free(fullname2); Py_INCREF(self); return self; } code_start = name_to_symbol_pkg(fullname2, "start"); if (code_start) { free(fullname2); Py_INCREF(self); return self; } free(fullname2); Py_INCREF(Py_None); return Py_None; } static PyObject* symimporter_load_module(PyObject *self, PyObject *args) { char *code_start; char *code_end; char *fullname; char *source; char *modname; PyObject *code; if (!PyArg_ParseTuple(args, "s:load_module", &fullname)) { return NULL; } char *fullname2 = symbolize(fullname); code_start = name_to_symbol_module(fullname2, "start"); if (code_start) { code_end = name_to_symbol_module(fullname2, "end"); if (code_end) { PyObject *mod = PyImport_AddModule(fullname); if (!mod) goto clear; PyObject *dict = PyModule_GetDict(mod); if (!dict) goto clear; PyDict_SetItemString(dict, "__loader__", self); source = uwsgi_concat2n(code_start, code_end-code_start, "", 0); modname = uwsgi_concat3("sym://", fullname2, "_py"); code = Py_CompileString(source, modname, Py_file_input); if (!code) { PyErr_Print(); goto shit; } mod = PyImport_ExecCodeModuleEx(fullname, code, modname); Py_DECREF(code); shit: free(source); free(modname); free(fullname2); return mod; } } code_start = name_to_symbol_pkg(fullname2, "start"); if (code_start) { code_end = name_to_symbol_pkg(fullname2, "end"); if (code_end) { char *symbolized; PyObject *mod = PyImport_AddModule(fullname); if (!mod) goto clear; PyObject *dict = PyModule_GetDict(mod); if (!dict) goto clear; source = uwsgi_concat2n(code_start, code_end-code_start, "", 0); symbolized = symbolize(fullname); modname = uwsgi_concat3("sym://", symbolized, "___init___py"); PyObject *pkgpath = Py_BuildValue("[O]", PyString_FromString(modname)); PyDict_SetItemString(dict, "__path__", pkgpath); PyDict_SetItemString(dict, "__loader__", self); code = Py_CompileString(source, modname, Py_file_input); if (!code) { PyErr_Print(); goto shit2; } mod = PyImport_ExecCodeModuleEx(fullname, code, modname); Py_DECREF(code); shit2: free(symbolized); free(source); free(modname); free(fullname2); return mod; } } clear: free(fullname2); Py_INCREF(Py_None); return Py_None; } static PyMethodDef symimporter_methods[] = { {"find_module", symimporter_find_module, METH_VARARGS}, {"load_module", symimporter_load_module, METH_VARARGS}, { NULL, NULL }, }; static PyMethodDef symzipimporter_methods[] = { {"find_module", symzipimporter_find_module, METH_VARARGS}, {"load_module", symzipimporter_load_module, METH_VARARGS}, { NULL, NULL }, }; static void uwsgi_symimporter_free(struct _symimporter *self) { PyObject_Del(self); } static PyTypeObject SymImporter_Type = { PyVarObject_HEAD_INIT(NULL, 0) "uwsgi.SymbolsImporter", sizeof(struct _symimporter), 0, /* tp_itemsize */ (destructor) uwsgi_symimporter_free, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, "uwsgi symbols importer", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ symimporter_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ PyType_GenericNew, /* tp_new */ 0, /* tp_free */ }; static int zipimporter_init(struct _symzipimporter *self, PyObject *args, PyObject *kwds) { char *name; char *prefix = NULL; size_t len = 0; if (!PyArg_ParseTuple(args, "s", &name)) return -1; // avoid GC !!! name = uwsgi_concat2(name, ""); if (uwsgi_check_scheme(name)) { prefix = uwsgi_get_last_char(name, '/'); prefix = uwsgi_get_last_char(prefix, ':'); } else { prefix = uwsgi_get_last_char(name, ':'); } if (prefix) { prefix[0] = 0; } char *body = uwsgi_open_and_read(name, &len, 0, NULL); if (!body) { return -1; } PyObject *stringio = PyImport_ImportModule("StringIO"); if (!stringio) { free(body); return -1; } #ifdef PYTHREE PyObject *source_code = PyObject_CallMethodObjArgs(stringio, PyString_FromString("StringIO"), PyString_FromStringAndSize(body, len)); #else PyObject *stringio_dict = PyModule_GetDict(stringio); if (!stringio_dict) { return -1; } PyObject *stringio_stringio = PyDict_GetItemString(stringio_dict, "StringIO"); if (!stringio_stringio) { return -1; } PyObject *stringio_args = PyTuple_New(1); PyTuple_SetItem(stringio_args, 0, PyString_FromStringAndSize(body, len)); PyObject *source_code = PyInstance_New(stringio_stringio, stringio_args, NULL); #endif if (!source_code) { return -1; } PyObject *zipfile = PyImport_ImportModule("zipfile"); if (!zipfile) { PyErr_Print(); return -1; } #ifdef PYTHREE self->zip = PyObject_CallMethodObjArgs(zipfile, PyString_FromString("ZipFile"), source_code); #else PyObject *zipfile_dict = PyModule_GetDict(zipfile); if (!zipfile_dict) { return -1; } PyObject *zipfile_zipfile = PyDict_GetItemString(zipfile_dict, "ZipFile"); if (!zipfile_zipfile) { return -1; } PyObject *zipfile_args = PyTuple_New(1); PyTuple_SetItem(zipfile_args, 0, source_code); self->zip = PyInstance_New(zipfile_zipfile, zipfile_args, NULL); #endif if (!self->zip) { return -1; } Py_INCREF(self->zip); self->items = PyObject_CallMethod(self->zip, "namelist", NULL); if (!self->items) { return -1; } Py_INCREF(self->items); self->prefix = NULL; if (prefix) { self->prefix = prefix+1; prefix[0] = ':'; } return 0; } static int symzipimporter_init(struct _symzipimporter *self, PyObject *args, PyObject *kwds) { char *name; char *prefix = NULL; if (!PyArg_ParseTuple(args, "s", &name)) return -1; // avoid GC !!! name = uwsgi_concat2(name, ""); prefix = strchr(name, ':'); if (prefix) { prefix[0] = 0; } char *code_start = name_to_symbol(name, "start"); if (!code_start) { PyErr_Format(PyExc_ValueError, "unable to find symbol"); goto error; } char *code_end = name_to_symbol(name, "end"); if (!code_end) { PyErr_Format(PyExc_ValueError, "unable to find symbol"); goto error; } PyObject *stringio = PyImport_ImportModule("StringIO"); if (!stringio) { goto error; } #ifdef PYTHREE PyObject *source_code = PyObject_CallMethodObjArgs(stringio, PyString_FromString("StringIO"), PyString_FromStringAndSize(code_start, code_end-code_start)); #else PyObject *stringio_dict = PyModule_GetDict(stringio); if (!stringio_dict) { goto error; } PyObject *stringio_stringio = PyDict_GetItemString(stringio_dict, "StringIO"); if (!stringio_stringio) { goto error; } PyObject *stringio_args = PyTuple_New(1); PyTuple_SetItem(stringio_args, 0, PyString_FromStringAndSize(code_start, code_end-code_start)); PyObject *source_code = PyInstance_New(stringio_stringio, stringio_args, NULL); #endif if (!source_code) { goto error; } PyObject *zipfile = PyImport_ImportModule("zipfile"); if (!zipfile) { goto error; } #ifdef PYTHREE self->zip = PyObject_CallMethodObjArgs(zipfile, PyString_FromString("ZipFile"), source_code); #else PyObject *zipfile_dict = PyModule_GetDict(zipfile); if (!zipfile_dict) { goto error; } PyObject *zipfile_zipfile = PyDict_GetItemString(zipfile_dict, "ZipFile"); if (!zipfile_zipfile) { goto error; } PyObject *zipfile_args = PyTuple_New(1); PyTuple_SetItem(zipfile_args, 0, source_code); self->zip = PyInstance_New(zipfile_zipfile, zipfile_args, NULL); #endif if (!self->zip) { goto error; } Py_INCREF(self->zip); self->items = PyObject_CallMethod(self->zip, "namelist", NULL); if (!self->items) { goto error; } Py_INCREF(self->items); self->prefix = NULL; if (prefix) { self->prefix = prefix+1; prefix[0] = ':'; } return 0; error: free(name); return -1; } static PyTypeObject SymZipImporter_Type = { PyVarObject_HEAD_INIT(NULL, 0) "uwsgi.SymbolsZipImporter", sizeof(struct _symzipimporter), 0, /* tp_itemsize */ (destructor) uwsgi_symimporter_free, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, "uwsgi symbols zip importer", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ symzipimporter_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc) symzipimporter_init, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ PyType_GenericNew, /* tp_new */ 0, /* tp_free */ }; static PyTypeObject ZipImporter_Type = { PyVarObject_HEAD_INIT(NULL, 0) "uwsgi.ZipImporter", sizeof(struct _symzipimporter), 0, /* tp_itemsize */ (destructor) uwsgi_symimporter_free, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, "uwsgi zip importer", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ symzipimporter_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc) zipimporter_init, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ PyType_GenericNew, /* tp_new */ 0, /* tp_free */ }; int uwsgi_init_symbol_import() { if (PyType_Ready(&SymImporter_Type) < 0) { PyErr_Print(); uwsgi_log("unable to initialize symbols importer module\n"); exit(1); } if (PyType_Ready(&ZipImporter_Type) < 0) { PyErr_Print(); uwsgi_log("unable to initialize zip importer module\n"); exit(1); } if (PyType_Ready(&SymZipImporter_Type) < 0) { PyErr_Print(); uwsgi_log("unable to initialize symbols zip importer module\n"); exit(1); } PyObject *uwsgi_em = PyImport_ImportModule("uwsgi"); if (!uwsgi_em) { PyErr_Print(); uwsgi_log("unable to get uwsgi module\n"); exit(1); } Py_INCREF((PyObject *)&SymImporter_Type); if (PyModule_AddObject(uwsgi_em, "SymbolsImporter", (PyObject *)&SymImporter_Type) < 0) { PyErr_Print(); uwsgi_log("unable to initialize symbols importer object\n"); exit(1); } Py_INCREF((PyObject *)&ZipImporter_Type); if (PyModule_AddObject(uwsgi_em, "ZipImporter", (PyObject *)&ZipImporter_Type) < 0) { PyErr_Print(); uwsgi_log("unable to initialize zip importer object\n"); exit(1); } Py_INCREF((PyObject *)&SymZipImporter_Type); if (PyModule_AddObject(uwsgi_em, "SymbolsZipImporter", (PyObject *)&SymZipImporter_Type) < 0) { PyErr_Print(); uwsgi_log("unable to initialize symbols zip importer object\n"); exit(1); } return 0; } uwsgi-2.0.29/plugins/python/tracebacker.c000066400000000000000000000210251477626554400204020ustar00rootroot00000000000000#include "uwsgi_python.h" extern struct uwsgi_server uwsgi; extern struct uwsgi_python up; char *uwsgi_python_get_thread_name(PyObject *thread_id) { PyObject *threading_module = PyImport_ImportModule("threading"); if (!threading_module) return NULL; PyObject *threading_dict = PyModule_GetDict(threading_module); if (!threading_dict) return NULL; PyObject *threading_enumerate = PyDict_GetItemString(threading_dict, "enumerate"); if (!threading_enumerate) return NULL; PyObject *threads_list = PyObject_CallObject(threading_enumerate, (PyObject *)NULL); if (!threads_list) return NULL; PyObject *threads_list_iter = PyObject_GetIter(threads_list); if (!threads_list_iter) goto clear; PyObject *threads_list_next = PyIter_Next(threads_list_iter); while(threads_list_next) { PyObject *thread_ident = PyObject_GetAttrString(threads_list_next, "ident"); if (!thread_ident) goto clear2; if (PyInt_AsLong(thread_ident) == PyInt_AsLong(thread_id)) { PyObject *thread_name = PyObject_GetAttrString(threads_list_next, "name"); if (!thread_name) goto clear2; #ifdef PYTHREE PyObject *thread_name_utf8 = PyUnicode_AsEncodedString(thread_name, "ASCII", "strict"); if (!thread_name_utf8) goto clear2; char *name = NULL; char *tmp_name = PyBytes_AS_STRING(thread_name_utf8); if (tmp_name) { name = uwsgi_str(tmp_name); Py_DECREF(thread_name_utf8); } #else char *name = PyString_AsString(thread_name); #endif Py_DECREF(threads_list_next); Py_DECREF(threads_list_iter); Py_DECREF(threads_list); return name; } Py_DECREF(threads_list_next); threads_list_next = PyIter_Next(threads_list_iter); } clear2: Py_DECREF(threads_list_iter); clear: Py_DECREF(threads_list); return NULL; } void *uwsgi_python_tracebacker_thread(void *foobar) { struct iovec iov[11]; PyObject *new_thread = uwsgi_python_setup_thread("uWSGITraceBacker"); if (!new_thread) return NULL; struct sockaddr_un so_sun; socklen_t so_sun_len = 0; char *str_wid = uwsgi_num2str(uwsgi.mywid); char *sock_path = uwsgi_concat2(up.tracebacker, str_wid); int current_defer_accept = uwsgi.no_defer_accept; uwsgi.no_defer_accept = 1; int fd = bind_to_unix(sock_path, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); if (fd < 0) { uwsgi.no_defer_accept = current_defer_accept; free(str_wid); free(sock_path); return NULL; } uwsgi.no_defer_accept = current_defer_accept; PyObject *traceback_module = PyImport_ImportModule("traceback"); if (!traceback_module) { free(str_wid); free(sock_path); close(fd); return NULL; } PyObject *traceback_dict = PyModule_GetDict(traceback_module); PyObject *extract_stack = PyDict_GetItemString(traceback_dict, "extract_stack"); PyObject *sys_module = PyImport_ImportModule("sys"); PyObject *sys_dict = PyModule_GetDict(sys_module); PyObject *_current_frames = PyDict_GetItemString(sys_dict, "_current_frames"); uwsgi_log("python tracebacker for worker %d available on %s\n", uwsgi.mywid, sock_path); for(;;) { UWSGI_RELEASE_GIL; int client_fd = accept(fd, (struct sockaddr *) &so_sun, &so_sun_len); if (client_fd < 0) { uwsgi_error("accept()"); UWSGI_GET_GIL; continue; } UWSGI_GET_GIL; // here is the core of the tracebacker PyObject *current_frames = PyObject_CallObject(_current_frames, (PyObject *)NULL); if (!current_frames) goto end2; PyObject *current_frames_items = PyObject_GetAttrString(current_frames, "items"); if (!current_frames_items) goto end; PyObject *frames_ret = PyObject_CallObject(current_frames_items, (PyObject *)NULL); if (!frames_ret) goto end3; PyObject *frames_iter = PyObject_GetIter(frames_ret); if (!frames_iter) goto end4; // we have the first frame, lets parse it if (write(client_fd, "*** uWSGI Python tracebacker output ***\n\n", 41) < 0) { uwsgi_error("write()"); } PyObject *frame = PyIter_Next(frames_iter); while(frame) { PyObject *thread_id = PyTuple_GetItem(frame, 0); if (!thread_id) goto next2; PyObject *stack = PyTuple_GetItem(frame, 1); if (!stack) goto next2; PyObject *arg_tuple = PyTuple_New(1); PyTuple_SetItem(arg_tuple, 0, stack); Py_INCREF(stack); PyObject *stacktrace = PyObject_CallObject( extract_stack, arg_tuple); Py_DECREF(arg_tuple); if (!stacktrace) goto next2; PyObject *stacktrace_iter = PyObject_GetIter(stacktrace); if (!stacktrace_iter) { Py_DECREF(stacktrace); goto next2;} PyObject *st_items = PyIter_Next(stacktrace_iter); // we have the first traceback item while(st_items) { #ifdef PYTHREE int thread_name_need_free = 0; PyObject *st_filename = PyObject_GetAttrString(st_items, "filename"); if (!st_filename) { Py_DECREF(st_items); goto next; } PyObject *st_lineno = PyObject_GetAttrString(st_items, "lineno"); if (!st_lineno) {Py_DECREF(st_items); goto next;} PyObject *st_name = PyObject_GetAttrString(st_items, "name"); if (!st_name) {Py_DECREF(st_items); goto next;} PyObject *st_line = PyObject_GetAttrString(st_items, "line"); #else PyObject *st_filename = PyTuple_GetItem(st_items, 0); if (!st_filename) { Py_DECREF(st_items); goto next; } PyObject *st_lineno = PyTuple_GetItem(st_items, 1); if (!st_lineno) {Py_DECREF(st_items); goto next;} PyObject *st_name = PyTuple_GetItem(st_items, 2); if (!st_name) {Py_DECREF(st_items); goto next;} PyObject *st_line = PyTuple_GetItem(st_items, 3); #endif iov[0].iov_base = "thread_id = "; iov[0].iov_len = 12; iov[1].iov_base = uwsgi_python_get_thread_name(thread_id); if (!iov[1].iov_base) { iov[1].iov_base = ""; } #ifdef PYTHREE else { thread_name_need_free = 1; } #endif iov[1].iov_len = strlen(iov[1].iov_base); iov[2].iov_base = " filename = "; iov[2].iov_len = 12; #ifdef PYTHREE PyObject *st_filename_utf8 = PyUnicode_AsEncodedString(st_filename, "ASCII", "strict"); if (!st_filename_utf8) { if (thread_name_need_free) free(iov[1].iov_base); goto next; } iov[3].iov_base = PyBytes_AS_STRING(st_filename_utf8); #else iov[3].iov_base = PyString_AsString(st_filename); #endif iov[3].iov_len = strlen(iov[3].iov_base); iov[4].iov_base = " lineno = "; iov[4].iov_len = 10 ; iov[5].iov_base = uwsgi_num2str(PyInt_AsLong(st_lineno)); iov[5].iov_len = strlen(iov[5].iov_base); iov[6].iov_base = " function = "; iov[6].iov_len = 12 ; #ifdef PYTHREE PyObject *st_name_utf8 = PyUnicode_AsEncodedString(st_name, "ASCII", "strict"); if (!st_name_utf8) { if (thread_name_need_free) free(iov[1].iov_base); Py_DECREF(st_filename_utf8); goto next; } iov[7].iov_base = PyBytes_AS_STRING(st_name_utf8); #else iov[7].iov_base = PyString_AsString(st_name); #endif iov[7].iov_len = strlen(iov[7].iov_base); iov[8].iov_base = ""; iov[8].iov_len = 0 ; iov[9].iov_base = ""; iov[9].iov_len = 0; iov[10].iov_base = "\n"; iov[10].iov_len = 1; #ifdef PYTHREE PyObject *st_line_utf8 = NULL; #endif if (st_line) { iov[8].iov_base = " line = "; iov[8].iov_len = 8; #ifdef PYTHREE PyObject *st_line_utf8 = PyUnicode_AsEncodedString(st_line, "ASCII", "strict"); if (!st_line_utf8) { if (thread_name_need_free) free(iov[1].iov_base); Py_DECREF(st_filename_utf8); Py_DECREF(st_name_utf8); goto next; } iov[9].iov_base = PyBytes_AS_STRING(st_line_utf8); #else iov[9].iov_base = PyString_AsString(st_line); #endif iov[9].iov_len = strlen(iov[9].iov_base); } if (writev(client_fd, iov, 11) < 0) { uwsgi_error("writev()"); } // free the line_no free(iov[5].iov_base); Py_DECREF(st_items); #ifdef PYTHREE Py_DECREF(st_filename_utf8); Py_DECREF(st_name_utf8); if (st_line_utf8) { Py_DECREF(st_line_utf8); } if (thread_name_need_free) free(iov[1].iov_base); #endif st_items = PyIter_Next(stacktrace_iter); } if (write(client_fd, "\n", 1) < 0) { uwsgi_error("write()"); } next: Py_DECREF(stacktrace_iter); Py_DECREF(stacktrace); next2: Py_DECREF(frame); frame = PyIter_Next(frames_iter); } Py_DECREF(frames_iter); end4: Py_DECREF(frames_ret); end3: Py_DECREF(current_frames_items); end: Py_DECREF(current_frames); end2: close(client_fd); } return NULL; } uwsgi-2.0.29/plugins/python/uwsgi_pymodule.c000066400000000000000000002760521477626554400212240ustar00rootroot00000000000000#include "uwsgi_python.h" extern struct uwsgi_server uwsgi; extern struct uwsgi_python up; extern struct uwsgi_plugin python_plugin; static PyObject *py_uwsgi_add_var(PyObject * self, PyObject * args) { char *key = NULL; Py_ssize_t keylen = 0; char *val = NULL; Py_ssize_t vallen = 0; struct wsgi_request *wsgi_req = py_current_wsgi_req(); if (!PyArg_ParseTuple(args, "s#s#", &key, &keylen, &val, &vallen)) { return NULL; } if (!uwsgi_req_append(wsgi_req, key, keylen, val, vallen)) { return PyErr_Format(PyExc_ValueError, "unable to add request var, check your buffer size"); } Py_INCREF(Py_True); return Py_True; } static PyObject *py_uwsgi_micros(PyObject * self, PyObject * args) { return PyLong_FromUnsignedLongLong(uwsgi_micros()); } static PyObject *py_uwsgi_signal_wait(PyObject * self, PyObject * args) { struct wsgi_request *wsgi_req = py_current_wsgi_req(); int wait_for_specific_signal = 0; uint8_t uwsgi_signal = 0; int received_signal; wsgi_req->signal_received = -1; if (PyTuple_Size(args) > 0) { if (!PyArg_ParseTuple(args, "|B:", &uwsgi_signal)) { return NULL; } wait_for_specific_signal = 1; } UWSGI_RELEASE_GIL; if (wait_for_specific_signal) { received_signal = uwsgi_signal_wait(uwsgi_signal); } else { received_signal = uwsgi_signal_wait(-1); } if (received_signal < 0) { UWSGI_GET_GIL; return PyErr_Format(PyExc_SystemError, "error waiting for signal"); } wsgi_req->signal_received = received_signal; UWSGI_GET_GIL; return PyString_FromString(""); } static PyObject *py_uwsgi_signal_received(PyObject * self, PyObject * args) { struct wsgi_request *wsgi_req = py_current_wsgi_req(); return PyInt_FromLong(wsgi_req->signal_received); } char *uwsgi_encode_pydict(PyObject * pydict, uint16_t * size) { int i; PyObject *zero, *key, *val; uint16_t keysize, valsize; char *buf, *bufptr; PyObject *vars = PyDict_Items(pydict); if (!vars) { PyErr_Print(); return NULL; } *size = 0; // calc the packet size // try to fallback whenever possible for (i = 0; i < PyList_Size(vars); i++) { zero = PyList_GetItem(vars, i); if (!zero) { PyErr_Print(); continue; } if (!PyTuple_Check(zero)) { uwsgi_log("invalid python dictionary item\n"); continue; } if (PyTuple_Size(zero) < 2) { uwsgi_log("invalid python dictionary item\n"); continue; } key = PyTuple_GetItem(zero, 0); val = PyTuple_GetItem(zero, 1); if (!PyString_Check(key) || !PyString_Check(val)) { continue; } keysize = PyString_Size(key); valsize = PyString_Size(val); *size += (keysize + 2 + valsize + 2); // do not DECREF here !!! //Py_DECREF(zero); } if (*size <= 4) { uwsgi_log("empty python dictionary\n"); return NULL; } // remember to free this memory !!! buf = malloc(*size); if (!buf) { uwsgi_error("malloc()"); return NULL; } bufptr = buf; for (i = 0; i < PyList_Size(vars); i++) { zero = PyList_GetItem(vars, i); if (!zero) { PyErr_Print(); continue; } if (!PyTuple_Check(zero)) { uwsgi_log("invalid python dictionary item\n"); continue; } if (PyTuple_Size(zero) < 2) { uwsgi_log("invalid python dictionary item\n"); continue; } key = PyTuple_GetItem(zero, 0); val = PyTuple_GetItem(zero, 1); if (!key || !val) { PyErr_Print(); continue; } if (!PyString_Check(key) || !PyString_Check(val)) { continue; } keysize = PyString_Size(key); valsize = PyString_Size(val); if (bufptr + keysize + 2 + valsize + 2 <= buf + *size) { *bufptr++ = (uint8_t) (keysize & 0xff); *bufptr++ = (uint8_t) ((keysize >> 8) & 0xff); memcpy(bufptr, PyString_AsString(key), keysize); bufptr += keysize; *bufptr++ = (uint8_t) (valsize & 0xff); *bufptr++ = (uint8_t) ((valsize >> 8) & 0xff); memcpy(bufptr, PyString_AsString(val), valsize); bufptr += valsize; } } return buf; } static PyObject *py_uwsgi_listen_queue(PyObject * self, PyObject * args) { int id = 0; if (!PyArg_ParseTuple(args, "|i:listen_queue", &id)) { return NULL; } struct uwsgi_socket *uwsgi_sock = uwsgi_get_socket_by_num(id); if (!uwsgi_sock) { return PyErr_Format(PyExc_ValueError, "unable to find socket %d", id); } return PyInt_FromLong(uwsgi_sock->queue); } static PyObject *py_uwsgi_close(PyObject * self, PyObject * args) { int fd; if (!PyArg_ParseTuple(args, "i:close", &fd)) { return NULL; } close(fd); Py_INCREF(Py_None); return Py_None; } static PyObject *py_uwsgi_add_cron(PyObject * self, PyObject * args) { uint8_t uwsgi_signal; int minute, hour, day, month, week; if (!PyArg_ParseTuple(args, "Biiiii:add_cron", &uwsgi_signal, &minute, &hour, &day, &month, &week)) { return NULL; } if (uwsgi_signal_add_cron(uwsgi_signal, minute, hour, day, month, week)) { return PyErr_Format(PyExc_ValueError, "unable to add cron"); } Py_INCREF(Py_True); return Py_True; } static PyObject *py_uwsgi_add_timer(PyObject * self, PyObject * args) { uint8_t uwsgi_signal; int secs; if (!PyArg_ParseTuple(args, "Bi:add_timer", &uwsgi_signal, &secs)) { return NULL; } if (uwsgi_add_timer(uwsgi_signal, secs)) return PyErr_Format(PyExc_ValueError, "unable to add timer"); Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_add_rb_timer(PyObject * self, PyObject * args) { uint8_t uwsgi_signal; int secs; int iterations = 0; if (!PyArg_ParseTuple(args, "Bi|i:add_rb_timer", &uwsgi_signal, &secs, &iterations)) { return NULL; } if (uwsgi_signal_add_rb_timer(uwsgi_signal, secs, iterations)) return PyErr_Format(PyExc_ValueError, "unable to add rb_timer"); Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_add_file_monitor(PyObject * self, PyObject * args) { uint8_t uwsgi_signal; char *filename; if (!PyArg_ParseTuple(args, "Bs:add_file_monitor", &uwsgi_signal, &filename)) { return NULL; } if (uwsgi_add_file_monitor(uwsgi_signal, filename)) return PyErr_Format(PyExc_ValueError, "unable to add file monitor"); Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_call(PyObject * self, PyObject * args) { char *func; uint64_t size = 0; PyObject *py_func; int argc = PyTuple_Size(args); int i; char *argv[256]; uint16_t argvs[256]; // TODO better error reporting if (argc < 1) goto clear; py_func = PyTuple_GetItem(args, 0); if (!PyString_Check(py_func)) goto clear; func = PyString_AsString(py_func); for (i = 0; i < (argc - 1); i++) { PyObject *py_str = PyTuple_GetItem(args, i + 1); if (!PyString_Check(py_str)) { goto clear; } argv[i] = PyString_AsString(py_str); argvs[i] = PyString_Size(py_str); } UWSGI_RELEASE_GIL; // response must always be freed char *response = uwsgi_do_rpc(NULL, func, argc - 1, argv, argvs, &size); UWSGI_GET_GIL; if (response) { PyObject *ret = PyString_FromStringAndSize(response, size); free(response); return ret; } Py_INCREF(Py_None); return Py_None; clear: return PyErr_Format(PyExc_ValueError, "unable to call rpc function"); } PyObject *py_uwsgi_rpc_list(PyObject * self, PyObject * args) { uint64_t i; PyObject *rpc_list = PyTuple_New(uwsgi.shared->rpc_count[uwsgi.mywid]); int pos = (uwsgi.mywid * uwsgi.rpc_max); for (i = 0; i < uwsgi.shared->rpc_count[uwsgi.mywid]; i++) { if (uwsgi.rpc_table[pos + i].name[0] != 0) { PyTuple_SetItem(rpc_list, i, PyString_FromString(uwsgi.rpc_table[pos + i].name)); } } return rpc_list; } PyObject *py_uwsgi_rpc(PyObject * self, PyObject * args) { char *node = NULL, *func; uint64_t size = 0; PyObject *py_node, *py_func; int argc = PyTuple_Size(args); char *argv[256]; uint16_t argvs[256]; int i; // TODO better error reporting if (argc < 2) goto clear; py_node = PyTuple_GetItem(args, 0); if (PyString_Check(py_node)) { node = PyString_AsString(py_node); } #ifdef PYTHREE else if (PyUnicode_Check(py_node)) { node = PyBytes_AsString(PyUnicode_AsLatin1String(py_node)); } #endif py_func = PyTuple_GetItem(args, 1); if (!PyString_Check(py_func)) goto clear; func = PyString_AsString(py_func); for (i = 0; i < (argc - 2); i++) { PyObject *py_str = PyTuple_GetItem(args, i + 2); if (!PyString_Check(py_str)) goto clear; argv[i] = PyString_AsString(py_str); argvs[i] = PyString_Size(py_str); } UWSGI_RELEASE_GIL; char *response = uwsgi_do_rpc(node, func, argc - 2, argv, argvs, &size); UWSGI_GET_GIL; if (response) { PyObject *ret = PyString_FromStringAndSize(response, size); free(response); return ret; } Py_INCREF(Py_None); return Py_None; clear: return PyErr_Format(PyExc_ValueError, "unable to call rpc function"); } PyObject *py_uwsgi_register_rpc(PyObject * self, PyObject * args) { uint8_t argc = 0; char *name; PyObject *func; if (!PyArg_ParseTuple(args, "sO|B:register_rpc", &name, &func, &argc)) { return NULL; } Py_INCREF(func); if (uwsgi_register_rpc(name, &python_plugin, argc, func)) { return PyErr_Format(PyExc_ValueError, "unable to register rpc function"); } Py_INCREF(Py_True); return Py_True; } PyObject *py_uwsgi_signal_registered(PyObject * self, PyObject * args) { uint8_t uwsgi_signal; if (!PyArg_ParseTuple(args, "B:signal_registered", &uwsgi_signal)) { return NULL; } if (uwsgi_signal_registered(uwsgi_signal)) { Py_INCREF(Py_True); return Py_True; } Py_INCREF(Py_None); return Py_None; } #ifdef UWSGI_SSL PyObject *py_uwsgi_i_am_the_lord(PyObject * self, PyObject * args) { char *legion_name = NULL; if (!PyArg_ParseTuple(args, "s:i_am_the_lord", &legion_name)) { return NULL; } if (uwsgi_legion_i_am_the_lord(legion_name)) { Py_INCREF(Py_True); return Py_True; } Py_INCREF(Py_False); return Py_False; } PyObject *py_uwsgi_lord_scroll(PyObject * self, PyObject * args) { char *legion_name = NULL; if (!PyArg_ParseTuple(args, "s:lord_scroll", &legion_name)) { return NULL; } uint16_t rlen = 0; char *buf = uwsgi_legion_lord_scroll(legion_name, &rlen); if (!buf) { Py_INCREF(Py_None); return Py_None; } PyObject *ret = PyString_FromStringAndSize(buf, rlen); free(buf); return ret; } static void scrolls_items(uint16_t pos, char *key, uint16_t keylen, void *data) { PyObject *list = (PyObject *) data; PyObject *zero = PyString_FromStringAndSize(key, keylen); PyList_Append(list, zero); Py_DECREF(zero); } PyObject *py_uwsgi_scrolls(PyObject * self, PyObject * args) { char *legion_name = NULL; if (!PyArg_ParseTuple(args, "s:scrolls", &legion_name)) { return NULL; } uint64_t rlen = 0; char *buf = uwsgi_legion_scrolls(legion_name, &rlen); if (!buf) goto end; PyObject *list = PyList_New(0); if (uwsgi_hooked_parse_array(buf, rlen, scrolls_items, list)) { goto error; } free(buf); return list; error: free(buf); end: Py_INCREF(Py_None); return Py_None; } #endif PyObject *py_uwsgi_register_signal(PyObject * self, PyObject * args) { uint8_t uwsgi_signal; char *signal_kind; PyObject *handler; if (!PyArg_ParseTuple(args, "BsO:register_signal", &uwsgi_signal, &signal_kind, &handler)) { return NULL; } Py_INCREF(handler); if (uwsgi_register_signal(uwsgi_signal, signal_kind, handler, 0)) { return PyErr_Format(PyExc_ValueError, "unable to register signal"); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_signal(PyObject * self, PyObject * args) { uint8_t uwsgi_signal; char *remote = NULL; if (!PyArg_ParseTuple(args, "B|s:signal", &uwsgi_signal, &remote)) { return NULL; } if (remote) { #ifdef UWSGI_DEBUG uwsgi_log("sending signal %d to node %s\n", uwsgi_signal, remote); #endif int ret = uwsgi_remote_signal_send(remote, uwsgi_signal); if (ret == 1) goto clear; if (ret == -1) return PyErr_Format(PyExc_IOError, "unable to deliver signal %d to node %s", uwsgi_signal, remote); if (ret == 0) return PyErr_Format(PyExc_ValueError, "node %s rejected signal %d", remote, uwsgi_signal); } else { #ifdef UWSGI_DEBUG uwsgi_log("sending signal %d to master\n", uwsgi_signal); #endif uwsgi_signal_send(uwsgi.signal_socket, uwsgi_signal); } clear: Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_log_this(PyObject * self, PyObject * args) { struct wsgi_request *wsgi_req = py_current_wsgi_req(); wsgi_req->log_this = 1; Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_alarm(PyObject * self, PyObject * args) { char *alarm = NULL; char *msg = NULL; Py_ssize_t msg_len = 0; if (!PyArg_ParseTuple(args, "ss#:alarm", &alarm, &msg, &msg_len)) { return NULL; } uwsgi_alarm_trigger(alarm, msg, msg_len); Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_get_logvar(PyObject * self, PyObject * args) { char *key = NULL; Py_ssize_t keylen = 0; struct wsgi_request *wsgi_req = py_current_wsgi_req(); if (!PyArg_ParseTuple(args, "s#:get_logvar", &key, &keylen)) { return NULL; } struct uwsgi_logvar *lv = uwsgi_logvar_get(wsgi_req, key, keylen); if (lv) { return PyString_FromStringAndSize(lv->val, lv->vallen); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_set_logvar(PyObject * self, PyObject * args) { char *key = NULL; Py_ssize_t keylen = 0; char *val = NULL; Py_ssize_t vallen = 0; struct wsgi_request *wsgi_req = py_current_wsgi_req(); if (!PyArg_ParseTuple(args, "s#s#:set_logvar", &key, &keylen, &val, &vallen)) { return NULL; } uwsgi_logvar_add(wsgi_req, key, keylen, val, vallen); Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_recv(PyObject * self, PyObject * args) { int fd, max_size = 4096; char buf[4096]; ssize_t rlen; if (!PyArg_ParseTuple(args, "i|i:recv", &fd, &max_size)) { return NULL; } UWSGI_RELEASE_GIL // security check if (max_size > 4096) max_size = 4096; rlen = read(fd, buf, max_size); UWSGI_GET_GIL if (rlen > 0) { return PyString_FromStringAndSize(buf, rlen); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_is_connected(PyObject * self, PyObject * args) { int fd = -1; if (!PyArg_ParseTuple(args, "i:is_connected", &fd)) { return NULL; } if (uwsgi_is_connected(fd)) { Py_INCREF(Py_True); return Py_True; } Py_INCREF(Py_False); return Py_False; } PyObject *py_uwsgi_send(PyObject * self, PyObject * args) { PyObject *data; PyObject *arg1, *arg2; struct wsgi_request *wsgi_req = py_current_wsgi_req(); int uwsgi_fd = wsgi_req->fd; if (!PyArg_ParseTuple(args, "O|O:send", &arg1, &arg2)) { return NULL; } if (PyTuple_Size(args) > 1) { uwsgi_fd = PyInt_AsLong(arg1); data = arg2; } else { data = arg1; } UWSGI_RELEASE_GIL if (write(uwsgi_fd, PyString_AsString(data), PyString_Size(data)) < 0) { uwsgi_error("write()"); UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; } #ifdef UWSGI_ROUTING static PyObject *py_uwsgi_route(PyObject * self, PyObject * args) { struct wsgi_request *wsgi_req = py_current_wsgi_req(); char *router_name = NULL; char *router_args = NULL; if (!PyArg_ParseTuple(args, "ss:route", &router_name, &router_args)) { return NULL; } int ret = uwsgi_route_api_func(wsgi_req, router_name, uwsgi_str(router_args)); return PyInt_FromLong(ret); } #endif PyObject *py_uwsgi_offload(PyObject * self, PyObject * args) { /* size_t len = 0; char *filename = NULL; struct wsgi_request *wsgi_req = py_current_wsgi_req(); if (!PyArg_ParseTuple(args, "s|i:offload_transfer", &filename, &len)) { return NULL; } if (!wsgi_req->socket->can_offload) { return PyErr_Format(PyExc_ValueError, "The current socket does not support offloading"); } if (!wsgi_req->headers_sent) { UWSGI_RELEASE_GIL if (uwsgi_response_write_headers_do(wsgi_req)) { UWSGI_GET_GIL return PyErr_Format(PyExc_ValueError, "unable to send headers before offload transfer"); } UWSGI_GET_GIL } UWSGI_RELEASE_GIL if (uwsgi_offload_request_sendfile_do(wsgi_req, filename, -1, len)) { UWSGI_GET_GIL return PyErr_Format(PyExc_ValueError, "unable to offload the request"); } UWSGI_GET_GIL */ return PyString_FromString(""); } PyObject *py_uwsgi_advanced_sendfile(PyObject * self, PyObject * args) { PyObject *what; char *filename; size_t chunk = 0; off_t pos = 0; size_t filesize = 0; struct wsgi_request *wsgi_req = py_current_wsgi_req(); int fd = -1; if (!PyArg_ParseTuple(args, "O|iii:sendfile", &what, &chunk, &pos, &filesize)) { return NULL; } if (PyString_Check(what)) { filename = PyString_AsString(what); fd = open(filename, O_RDONLY); if (fd < 0) { uwsgi_error_open(filename); goto clear; } } #ifdef PYTHREE else if (PyUnicode_Check(what)) { filename = PyBytes_AsString(PyUnicode_AsLatin1String(what)); fd = open(filename, O_RDONLY); if (fd < 0) { uwsgi_error_open(filename); goto clear; } } #endif else { fd = PyObject_AsFileDescriptor(what); if (fd < 0) goto clear; // check for mixing file_wrapper and sendfile if (fd == wsgi_req->sendfile_fd) { Py_INCREF(what); } } UWSGI_RELEASE_GIL // fd is closed by the following function uwsgi_response_sendfile_do(wsgi_req, fd, pos, filesize); UWSGI_GET_GIL // revert to old values uwsgi_py_check_write_errors { uwsgi_py_write_exception(wsgi_req); return NULL; } Py_INCREF(Py_True); return Py_True; clear: Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_async_sleep(PyObject * self, PyObject * args) { float timeout; int sec_timeout; if (!PyArg_ParseTuple(args, "f:async_sleep", &timeout)) { return NULL; } sec_timeout = (int) timeout; if (sec_timeout > 0) { async_add_timeout(uwsgi.wsgi_req, sec_timeout); } return PyString_FromString(""); } PyObject *py_uwsgi_warning(PyObject * self, PyObject * args) { char *message; int len; if (!PyArg_ParseTuple(args, "s:set_warning_message", &message)) { return NULL; } len = strlen(message); if (len > 80) { uwsgi_log("- warning message must be max 80 chars, it will be truncated -"); memcpy(uwsgi.shared->warning_message, message, 80); uwsgi.shared->warning_message[80] = 0; } else { memcpy(uwsgi.shared->warning_message, message, len); uwsgi.shared->warning_message[len] = 0; } Py_INCREF(Py_True); return Py_True; } PyObject *py_uwsgi_log(PyObject * self, PyObject * args) { char *logline; if (!PyArg_ParseTuple(args, "s:log", &logline)) { return NULL; } uwsgi_log("%s\n", logline); Py_INCREF(Py_True); return Py_True; } PyObject *py_uwsgi_set_user_harakiri(PyObject * self, PyObject * args) { int sec = 0; if (!PyArg_ParseTuple(args, "i:set_user_harakiri", &sec)) { return NULL; } set_user_harakiri(sec); Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_i_am_the_spooler(PyObject * self, PyObject * args) { if (uwsgi.i_am_a_spooler) { Py_INCREF(Py_True); return Py_True; } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_is_locked(PyObject * self, PyObject * args) { int lock_num = 0; // the spooler cannot lock resources if (uwsgi.i_am_a_spooler) { return PyErr_Format(PyExc_ValueError, "The spooler cannot lock/unlock resources"); } if (!PyArg_ParseTuple(args, "|i:is_locked", &lock_num)) { return NULL; } if (lock_num < 0 || lock_num > uwsgi.locks) { return PyErr_Format(PyExc_ValueError, "Invalid lock number"); } UWSGI_RELEASE_GIL if (uwsgi_lock_check(uwsgi.user_lock[lock_num]) == 0) { UWSGI_GET_GIL Py_INCREF(Py_False); return Py_False; } UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; } PyObject *py_uwsgi_lock(PyObject * self, PyObject * args) { int lock_num = 0; // the spooler cannot lock resources if (uwsgi.i_am_a_spooler) { return PyErr_Format(PyExc_ValueError, "The spooler cannot lock/unlock resources"); } if (!PyArg_ParseTuple(args, "|i:lock", &lock_num)) { return NULL; } if (lock_num < 0 || lock_num > uwsgi.locks) { return PyErr_Format(PyExc_ValueError, "Invalid lock number"); } UWSGI_RELEASE_GIL uwsgi_lock(uwsgi.user_lock[lock_num]); UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_unlock(PyObject * self, PyObject * args) { int lock_num = 0; if (uwsgi.i_am_a_spooler) { return PyErr_Format(PyExc_ValueError, "The spooler cannot lock/unlock resources"); } if (!PyArg_ParseTuple(args, "|i:unlock", &lock_num)) { return NULL; } if (lock_num < 0 || lock_num > uwsgi.locks) { return PyErr_Format(PyExc_ValueError, "Invalid lock number"); } uwsgi_unlock(uwsgi.user_lock[lock_num]); Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_connection_fd(PyObject * self, PyObject * args) { struct wsgi_request *wsgi_req = py_current_wsgi_req(); return PyInt_FromLong(wsgi_req->fd); } PyObject *py_uwsgi_websocket_handshake(PyObject * self, PyObject * args) { char *key = NULL; Py_ssize_t key_len = 0; char *origin = NULL; Py_ssize_t origin_len = 0; char *proto = NULL; Py_ssize_t proto_len = 0; if (!PyArg_ParseTuple(args, "|s#s#s#:websocket_handshake", &key, &key_len, &origin, &origin_len, &proto, &proto_len)) { return NULL; } struct wsgi_request *wsgi_req = py_current_wsgi_req(); UWSGI_RELEASE_GIL int ret = uwsgi_websocket_handshake(wsgi_req, key, key_len, origin, origin_len, proto, proto_len); UWSGI_GET_GIL if (ret) { return PyErr_Format(PyExc_IOError, "unable to complete websocket handshake"); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_websocket_send(PyObject * self, PyObject * args) { char *message = NULL; Py_ssize_t message_len = 0; if (!PyArg_ParseTuple(args, "s#:websocket_send", &message, &message_len)) { return NULL; } struct wsgi_request *wsgi_req = py_current_wsgi_req(); UWSGI_RELEASE_GIL int ret = uwsgi_websocket_send(wsgi_req, message, message_len); UWSGI_GET_GIL if (ret < 0) { return PyErr_Format(PyExc_IOError, "unable to send websocket message"); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_websocket_send_binary(PyObject * self, PyObject * args) { char *message = NULL; Py_ssize_t message_len = 0; if (!PyArg_ParseTuple(args, "s#:websocket_send_binary", &message, &message_len)) { return NULL; } struct wsgi_request *wsgi_req = py_current_wsgi_req(); UWSGI_RELEASE_GIL int ret = uwsgi_websocket_send_binary(wsgi_req, message, message_len); UWSGI_GET_GIL if (ret < 0) { return PyErr_Format(PyExc_IOError, "unable to send websocket binary message"); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_chunked_read(PyObject * self, PyObject * args) { int timeout = 0; if (!PyArg_ParseTuple(args, "|i:chunked_read", &timeout)) { return NULL; } size_t len = 0; struct wsgi_request *wsgi_req = py_current_wsgi_req(); UWSGI_RELEASE_GIL char *chunk = uwsgi_chunked_read(wsgi_req, &len, timeout, 0); UWSGI_GET_GIL if (!chunk) { return PyErr_Format(PyExc_IOError, "unable to receive chunked part"); } return PyString_FromStringAndSize(chunk, len); } PyObject *py_uwsgi_chunked_read_nb(PyObject * self, PyObject * args) { size_t len = 0; struct wsgi_request *wsgi_req = py_current_wsgi_req(); UWSGI_RELEASE_GIL char *chunk = uwsgi_chunked_read(wsgi_req, &len, 0, 1); UWSGI_GET_GIL if (!chunk) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) { Py_INCREF(Py_None); return Py_None; } return PyErr_Format(PyExc_IOError, "unable to receive chunked part"); } return PyString_FromStringAndSize(chunk, len); } PyObject *py_uwsgi_websocket_recv(PyObject * self, PyObject * args) { struct wsgi_request *wsgi_req = py_current_wsgi_req(); UWSGI_RELEASE_GIL struct uwsgi_buffer *ub = uwsgi_websocket_recv(wsgi_req); UWSGI_GET_GIL if (!ub) { return PyErr_Format(PyExc_IOError, "unable to receive websocket message"); } PyObject *ret = PyString_FromStringAndSize(ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return ret; } PyObject *py_uwsgi_websocket_recv_nb(PyObject * self, PyObject * args) { struct wsgi_request *wsgi_req = py_current_wsgi_req(); UWSGI_RELEASE_GIL struct uwsgi_buffer *ub = uwsgi_websocket_recv_nb(wsgi_req); UWSGI_GET_GIL if (!ub) { return PyErr_Format(PyExc_IOError, "unable to receive websocket message"); } PyObject *ret = PyString_FromStringAndSize(ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return ret; } PyObject *py_uwsgi_embedded_data(PyObject * self, PyObject * args) { char *name; char *symbol; void *sym_ptr_start = NULL; void *sym_ptr_end = NULL; if (!PyArg_ParseTuple(args, "s:embedded_data", &name)) { return NULL; } symbol = uwsgi_concat3("_binary_", name, "_start"); sym_ptr_start = dlsym(RTLD_DEFAULT, symbol); free(symbol); if (!sym_ptr_start) return PyErr_Format(PyExc_ValueError, "unable to find symbol %s", name); symbol = uwsgi_concat3("_binary_", name, "_end"); sym_ptr_end = dlsym(RTLD_DEFAULT, symbol); free(symbol); if (!sym_ptr_end) return PyErr_Format(PyExc_ValueError, "unable to find symbol %s", name); return PyString_FromStringAndSize(sym_ptr_start, sym_ptr_end - sym_ptr_start); } PyObject *py_uwsgi_setprocname(PyObject * self, PyObject * args) { char *name = NULL; if (!PyArg_ParseTuple(args, "s:setprocname", &name)) { return NULL; } uwsgi_set_processname(name); Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_ready(PyObject * self, PyObject * args) { if (ushared->ready) { Py_INCREF(Py_True); return Py_True; } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_in_farm(PyObject * self, PyObject * args) { char *farm_name = NULL; int i; if (!PyArg_ParseTuple(args, "|s:in_farm", &farm_name)) { return NULL; } if (uwsgi.muleid == 0) goto none; for(i=0;imule_queue_pipe[0], message, message_len); UWSGI_GET_GIL } else { if (PyString_Check(mule_obj)) { struct uwsgi_farm *uf = get_farm_by_name(PyString_AsString(mule_obj)); if (uf == NULL) { return PyErr_Format(PyExc_ValueError, "unknown farm"); } fd = uf->queue_pipe[0]; } else if (PyInt_Check(mule_obj)) { mule_id = PyInt_AsLong(mule_obj); if (mule_id < 0 && mule_id > uwsgi.mules_cnt) { return PyErr_Format(PyExc_ValueError, "invalid mule number"); } if (mule_id == 0) { fd = uwsgi.shared->mule_queue_pipe[0]; } else { fd = uwsgi.mules[mule_id-1].queue_pipe[0]; } } else { return PyErr_Format(PyExc_ValueError, "invalid mule"); } if (fd > -1) { UWSGI_RELEASE_GIL resp = mule_send_msg(fd, message, message_len); UWSGI_GET_GIL } } if(!resp) { Py_INCREF(Py_True); return Py_True; } Py_INCREF(Py_False); return Py_False; } PyObject *py_uwsgi_mule_get_msg(PyObject * self, PyObject * args, PyObject *kwargs) { ssize_t len = 0; // this buffer is configurable (default 64k) char *message; PyObject *py_manage_signals = NULL; PyObject *py_manage_farms = NULL; size_t buffer_size = 65536; int timeout = -1; int manage_signals = 1, manage_farms = 1; static char *kwlist[] = {"signals", "farms", "buffer_size", "timeout", NULL}; if (uwsgi.muleid == 0) { return PyErr_Format(PyExc_ValueError, "you can receive mule messages only in a mule !!!"); } if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii:mule_get_msg", kwlist, &py_manage_signals, &py_manage_farms, &buffer_size, &timeout)) { return NULL; } // signals and farms are managed by default if (py_manage_signals == Py_None || py_manage_signals == Py_False) { manage_signals = 0; } if (py_manage_farms == Py_None || py_manage_farms == Py_False) { manage_farms = 0; } message = uwsgi_malloc(buffer_size); UWSGI_RELEASE_GIL; len = uwsgi_mule_get_msg(manage_signals, manage_farms, message, buffer_size, timeout) ; UWSGI_GET_GIL; if (len < 0) { free(message); Py_INCREF(Py_None); return Py_None; } PyObject *msg = PyString_FromStringAndSize(message, len); free(message); return msg; } PyObject *py_uwsgi_farm_get_msg(PyObject * self, PyObject * args) { ssize_t len = 0; // this buffer will be configurable char message[65536]; int i, count = 0, pos = 0, ret; struct pollfd *farmpoll; if (uwsgi.muleid == 0) { return PyErr_Format(PyExc_ValueError, "you can receive farm messages only in a mule !!!"); } UWSGI_RELEASE_GIL; for(i=0;i 0) { return PyString_FromStringAndSize(buf, len); } if (buf) free(buf); Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_sharedarea_inc64(PyObject * self, PyObject * args) { int id; uint64_t pos = 0; int64_t value = 1; if (!PyArg_ParseTuple(args, "iL|l:sharedarea_inc64", &id, &pos, &value)) { return NULL; } UWSGI_RELEASE_GIL int ret = uwsgi_sharedarea_inc64(id, pos, value); UWSGI_GET_GIL if (ret) { return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_inc64()"); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_sharedarea_inc32(PyObject * self, PyObject * args) { int id; uint64_t pos = 0; int32_t value = 1; if (!PyArg_ParseTuple(args, "iL|i:sharedarea_inc32", &id, &pos, &value)) { return NULL; } UWSGI_RELEASE_GIL int ret = uwsgi_sharedarea_inc32(id, pos, value); UWSGI_GET_GIL if (ret) { return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_inc32()"); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_sharedarea_dec64(PyObject * self, PyObject * args) { int id; uint64_t pos = 0; int64_t value = 1; if (!PyArg_ParseTuple(args, "iL|l:sharedarea_dec64", &id, &pos, &value)) { return NULL; } UWSGI_RELEASE_GIL int ret = uwsgi_sharedarea_dec64(id, pos, value); UWSGI_GET_GIL if (ret) { return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_dec64()"); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_sharedarea_dec32(PyObject * self, PyObject * args) { int id; uint64_t pos = 0; int32_t value = 1; if (!PyArg_ParseTuple(args, "iL|i:sharedarea_dec32", &id, &pos, &value)) { return NULL; } UWSGI_RELEASE_GIL int ret = uwsgi_sharedarea_dec32(id, pos, value); UWSGI_GET_GIL if (ret) { return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_dec32()"); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_sharedarea_write32(PyObject * self, PyObject * args) { int id; uint64_t pos = 0; int32_t value = 0; if (!PyArg_ParseTuple(args, "iLI:sharedarea_write32", &id, &pos, &value)) { return NULL; } UWSGI_RELEASE_GIL int ret = uwsgi_sharedarea_write32(id, pos, &value); UWSGI_GET_GIL if (ret) { return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_write32()"); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_sharedarea_write16(PyObject * self, PyObject * args) { int id; uint64_t pos = 0; int16_t value = 0; if (!PyArg_ParseTuple(args, "iLI:sharedarea_write16", &id, &pos, &value)) { return NULL; } UWSGI_RELEASE_GIL int ret = uwsgi_sharedarea_write16(id, pos, &value); UWSGI_GET_GIL if (ret) { return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_write16()"); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_sharedarea_write64(PyObject * self, PyObject * args) { int id; uint64_t pos = 0; int64_t value = 0; if (!PyArg_ParseTuple(args, "iLL:sharedarea_write64", &id, &pos, &value)) { return NULL; } UWSGI_RELEASE_GIL int ret = uwsgi_sharedarea_write64(id, pos, &value); UWSGI_GET_GIL if (ret) { return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_write64()"); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_sharedarea_write(PyObject * self, PyObject * args) { int id; uint64_t pos = 0; char *value; Py_ssize_t value_len = 0; if (!PyArg_ParseTuple(args, "iLs#:sharedarea_write", &id, &pos, &value, &value_len)) { return NULL; } UWSGI_RELEASE_GIL int ret = uwsgi_sharedarea_write(id, pos, value, value_len); UWSGI_GET_GIL if (ret) { return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_write()"); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_sharedarea_update(PyObject * self, PyObject * args) { int id; if (!PyArg_ParseTuple(args, "i:sharedarea_update", &id)) { return NULL; } if (uwsgi_sharedarea_update(id)) { return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_update()"); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_sharedarea_rlock(PyObject * self, PyObject * args) { int id; if (!PyArg_ParseTuple(args, "i:sharedarea_rlock", &id)) { return NULL; } UWSGI_RELEASE_GIL int ret = uwsgi_sharedarea_rlock(id); UWSGI_GET_GIL if (ret) { return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_rlock()"); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_sharedarea_wlock(PyObject * self, PyObject * args) { int id; if (!PyArg_ParseTuple(args, "i:sharedarea_wlock", &id)) { return NULL; } UWSGI_RELEASE_GIL int ret = uwsgi_sharedarea_wlock(id); UWSGI_GET_GIL if (ret) { return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_wlock()"); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_sharedarea_unlock(PyObject * self, PyObject * args) { int id; if (!PyArg_ParseTuple(args, "i:sharedarea_unlock", &id)) { return NULL; } UWSGI_RELEASE_GIL int ret = uwsgi_sharedarea_unlock(id); UWSGI_GET_GIL if (ret) { return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_unlock()"); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_sharedarea_write8(PyObject * self, PyObject * args) { int id; uint64_t pos = 0; int8_t value; if (!PyArg_ParseTuple(args, "iLb:sharedarea_write8", &id, &pos, &value)) { return NULL; } UWSGI_RELEASE_GIL int ret = uwsgi_sharedarea_write8(id, pos, &value); UWSGI_GET_GIL if (ret) { return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_write8()"); } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_sharedarea_read64(PyObject * self, PyObject * args) { int id; uint64_t pos = 0; int64_t value; if (!PyArg_ParseTuple(args, "iL:sharedarea_read64", &id, &pos)) { return NULL; } UWSGI_RELEASE_GIL int ret = uwsgi_sharedarea_read64(id, pos, &value); UWSGI_GET_GIL if (ret) { return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_read64()"); } return PyLong_FromLongLong(value); } PyObject *py_uwsgi_sharedarea_read32(PyObject * self, PyObject * args) { int id; uint64_t pos = 0; int32_t value; if (!PyArg_ParseTuple(args, "iL:sharedarea_read32", &id, &pos)) { return NULL; } UWSGI_RELEASE_GIL int ret = uwsgi_sharedarea_read32(id, pos, &value); UWSGI_GET_GIL if (ret) { return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_read32()"); } return PyInt_FromLong(value); } PyObject *py_uwsgi_sharedarea_read16(PyObject * self, PyObject * args) { int id; uint64_t pos = 0; int16_t value; if (!PyArg_ParseTuple(args, "iL:sharedarea_read16", &id, &pos)) { return NULL; } UWSGI_RELEASE_GIL int ret = uwsgi_sharedarea_read16(id, pos, &value); UWSGI_GET_GIL if (ret) { return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_read16()"); } return PyInt_FromLong(value); } PyObject *py_uwsgi_sharedarea_read8(PyObject * self, PyObject * args) { int id; uint64_t pos = 0; int8_t byte; if (!PyArg_ParseTuple(args, "iL:sharedarea_read8", &id, &pos)) { return NULL; } UWSGI_RELEASE_GIL int ret = uwsgi_sharedarea_read8(id, pos, &byte); UWSGI_GET_GIL if (ret) { return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_read8()"); } return PyInt_FromLong(byte); } PyObject *py_uwsgi_sharedarea_read(PyObject * self, PyObject * args) { int id; uint64_t pos = 0; uint64_t len = 0; if (!PyArg_ParseTuple(args, "iL|L:sharedarea_read", &id, &pos, &len)) { return NULL; } if (!len) { struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, pos); if (!sa) { return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_read()"); } len = (sa->max_pos+1)-pos; } PyObject *ret = PyString_FromStringAndSize(NULL, len); #ifdef PYTHREE char *storage = PyBytes_AsString(ret); #else char *storage = PyString_AS_STRING(ret); #endif UWSGI_RELEASE_GIL int64_t rlen = uwsgi_sharedarea_read(id, pos, storage, len); UWSGI_GET_GIL if (rlen < 0) { Py_DECREF(ret); return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_read()"); } // HACK: we are safe as rlen can only be lower or equal to len Py_SET_SIZE((PyVarObject *) ret, rlen); return ret; } #if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER) #ifndef HAS_NOT_PyMemoryView_FromBuffer PyObject *py_uwsgi_sharedarea_memoryview(PyObject * self, PyObject * args) { int id; if (!PyArg_ParseTuple(args, "i:sharedarea_memoryview", &id)) { return NULL; } struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, 0); if (!sa) { return PyErr_Format(PyExc_ValueError, "cannot get a memoryview object from sharedarea %d", id); } Py_buffer info; if (PyBuffer_FillInfo(&info, NULL, sa->area, sa->max_pos+1, 0, PyBUF_CONTIG) < 0) return PyErr_Format(PyExc_ValueError, "cannot get a memoryview object from sharedarea %d", id); return PyMemoryView_FromBuffer(&info); } #endif PyObject *py_uwsgi_sharedarea_object(PyObject * self, PyObject * args) { int id; if (!PyArg_ParseTuple(args, "i:sharedarea_object", &id)) { return NULL; } struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, 0); if (!sa) { return PyErr_Format(PyExc_ValueError, "cannot get an object from sharedarea %d", id); } return (PyObject *) sa->obj; } #endif PyObject *py_uwsgi_spooler_freq(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple(args, "i", &uwsgi.shared->spooler_frequency)) { return NULL; } Py_INCREF(Py_True); return Py_True; } PyObject *py_uwsgi_spooler_jobs(PyObject * self, PyObject * args) { DIR *sdir; struct dirent *dp; char *abs_path; struct stat sf_lstat; PyObject *jobslist = PyList_New(0); struct uwsgi_spooler *uspool = uwsgi.spoolers; sdir = opendir(uspool->dir); if (sdir) { while ((dp = readdir(sdir)) != NULL) { if (!strncmp("uwsgi_spoolfile_on_", dp->d_name, 19)) { abs_path = malloc(strlen(uspool->dir) + 1 + strlen(dp->d_name) + 1); if (!abs_path) { uwsgi_error("malloc()"); closedir(sdir); goto clear; } memset(abs_path, 0, strlen(uspool->dir) + 1 + strlen(dp->d_name) + 1); memcpy(abs_path, uspool->dir, strlen(uspool->dir)); memcpy(abs_path + strlen(uspool->dir), "/", 1); memcpy(abs_path + strlen(uspool->dir) + 1, dp->d_name, strlen(dp->d_name)); if (lstat(abs_path, &sf_lstat)) { free(abs_path); continue; } if (!S_ISREG(sf_lstat.st_mode)) { free(abs_path); continue; } if (!access(abs_path, R_OK | W_OK)) { if (PyList_Append(jobslist, PyString_FromString(abs_path))) { PyErr_Print(); } } free(abs_path); } } closedir(sdir); } clear: return jobslist; } PyObject *py_uwsgi_send_spool(PyObject * self, PyObject * args, PyObject *kw) { PyObject *spool_dict, *spool_vars; PyObject *zero, *key, *val; uint16_t keysize, valsize; char *body = NULL; size_t body_len= 0; spool_dict = PyTuple_GetItem(args, 0); if (spool_dict) { if (!PyDict_Check(spool_dict)) { return PyErr_Format(PyExc_ValueError, "The argument of spooler callable must be a dictionary"); } } else { // clear the error PyErr_Clear(); spool_dict = kw; } if (!spool_dict) { return PyErr_Format(PyExc_ValueError, "The argument of spooler callable must be a dictionary"); } PyObject *pybody = uwsgi_py_dict_get(spool_dict, "body"); if (pybody) { if (PyString_Check(pybody)) { body = PyString_AsString(pybody); body_len = PyString_Size(pybody); Py_INCREF(pybody); uwsgi_py_dict_del(spool_dict, "body"); } } spool_vars = PyDict_Items(spool_dict); if (!spool_vars) { Py_INCREF(Py_None); return Py_None; } int i; struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); for (i = 0; i < PyList_Size(spool_vars); i++) { zero = PyList_GetItem(spool_vars, i); if (zero) { if (PyTuple_Check(zero)) { key = PyTuple_GetItem(zero, 0); val = PyTuple_GetItem(zero, 1); if (PyString_Check(key)) { keysize = PyString_Size(key); if (PyString_Check(val)) { valsize = PyString_Size(val); if (uwsgi_buffer_append_keyval(ub, PyString_AsString(key), keysize, PyString_AsString(val), valsize)) { uwsgi_buffer_destroy(ub); goto error; } } else { #ifdef PYTHREE PyObject *str = PyObject_Bytes(val); #else PyObject *str = PyObject_Str(val); #endif if (!str) { uwsgi_buffer_destroy(ub); goto error; } if (uwsgi_buffer_append_keyval(ub, PyString_AsString(key), keysize, PyString_AsString(str), PyString_Size(str))) { Py_DECREF(str); uwsgi_buffer_destroy(ub); goto error; } Py_DECREF(str); } } else { uwsgi_buffer_destroy(ub); goto error; } } else { uwsgi_buffer_destroy(ub); goto error; } } else { uwsgi_buffer_destroy(ub); goto error; } } UWSGI_RELEASE_GIL // current_wsgi_req can be NULL, in such a case a non-thread-safe counter will be used char *filename = uwsgi_spool_request(NULL, ub->buf, ub->pos, body, body_len); uwsgi_buffer_destroy(ub); UWSGI_GET_GIL if (pybody) { if (PyString_Check(pybody)) { Py_DECREF(pybody); } } Py_DECREF(spool_vars); if (filename) { PyObject *ret = PyString_FromString(filename); free(filename); return ret; } return PyErr_Format(PyExc_ValueError, "unable to spool job"); error: #ifdef PYTHREE return PyErr_Format(PyExc_ValueError, "spooler callable dictionary must contains only bytes"); #else return PyErr_Format(PyExc_ValueError, "spooler callable dictionary must contains only strings"); #endif } PyObject *py_uwsgi_spooler_pid(PyObject * self, PyObject * args) { struct uwsgi_spooler *uspool = uwsgi.spoolers; if (!uwsgi.spoolers) return PyInt_FromLong(0); return PyInt_FromLong(uspool->pid); } PyObject *py_uwsgi_spooler_pids(PyObject * self, PyObject * args) { PyObject *ret = PyList_New(0); struct uwsgi_spooler *uspool = uwsgi.spoolers; while (uspool) { PyList_Append(ret, PyInt_FromLong(uspool->pid)); uspool = uspool->next; } return ret; } PyObject *py_uwsgi_spooler_get_task(PyObject * self, PyObject * args) { char spool_buf[0xffff]; struct uwsgi_header uh; char *body = NULL; size_t body_len = 0; int spool_fd; char *task_path = NULL; struct stat task_stat; if (!PyArg_ParseTuple(args, "s:spooler_get_task", &task_path)) { return NULL; } if (lstat(task_path, &task_stat)) { Py_INCREF(Py_None); return Py_None; } if (access(task_path, R_OK | W_OK)) { Py_INCREF(Py_None); return Py_None; } spool_fd = open(task_path, O_RDWR); if (spool_fd < 0) { Py_INCREF(Py_None); return Py_None; } if (uwsgi_spooler_read_header(task_path, spool_fd, &uh) || uwsgi_spooler_read_content(spool_fd, spool_buf, &body, &body_len, &uh, &task_stat)) { Py_INCREF(Py_None); return Py_None; } uwsgi_protected_close(spool_fd); PyObject *spool_dict = uwsgi_python_dict_from_spooler_content(task_path, spool_buf, uh.pktsize, body, body_len); if (!spool_dict) { Py_INCREF(Py_None); return Py_None; } return spool_dict; } PyObject *py_uwsgi_connect(PyObject * self, PyObject * args) { char *socket_name = NULL; int timeout = 0; if (!PyArg_ParseTuple(args, "s|i:connect", &socket_name, &timeout)) { return NULL; } return PyInt_FromLong(uwsgi_connect(socket_name, timeout, 0)); } PyObject *py_uwsgi_async_connect(PyObject * self, PyObject * args) { char *socket_name = NULL; if (!PyArg_ParseTuple(args, "s:async_connect", &socket_name)) { return NULL; } return PyInt_FromLong(uwsgi_connect(socket_name, 0, 1)); } /* uWSGI masterpid */ PyObject *py_uwsgi_masterpid(PyObject * self, PyObject * args) { if (uwsgi.master_process) { return PyInt_FromLong(uwsgi.workers[0].pid); } return PyInt_FromLong(0); } /* uWSGI total_requests */ PyObject *py_uwsgi_total_requests(PyObject * self, PyObject * args) { return PyLong_FromUnsignedLongLong(uwsgi.workers[0].requests); } /* uWSGI workers */ PyObject *py_uwsgi_workers(PyObject * self, PyObject * args) { PyObject *worker_dict, *apps_dict, *apps_tuple, *zero; int i, j; struct uwsgi_app *ua; for (i = 0; i < uwsgi.numproc; i++) { worker_dict = PyTuple_GetItem(up.workers_tuple, i); if (!worker_dict) { goto clear; } PyDict_Clear(worker_dict); zero = PyInt_FromLong(uwsgi.workers[i + 1].id); if (PyDict_SetItemString(worker_dict, "id", zero)) { goto clear; } Py_DECREF(zero); zero = PyInt_FromLong(uwsgi.workers[i + 1].pid); if (PyDict_SetItemString(worker_dict, "pid", zero)) { goto clear; } Py_DECREF(zero); zero = PyLong_FromUnsignedLongLong(uwsgi.workers[i + 1].requests); if (PyDict_SetItemString(worker_dict, "requests", zero)) { goto clear; } Py_DECREF(zero); zero = PyLong_FromUnsignedLongLong(uwsgi.workers[i + 1].delta_requests); if (PyDict_SetItemString(worker_dict, "delta_requests", zero)) { goto clear; } Py_DECREF(zero); zero = PyLong_FromUnsignedLongLong(uwsgi.workers[i + 1].signals); if (PyDict_SetItemString(worker_dict, "signals", zero)) { goto clear; } Py_DECREF(zero); zero = PyLong_FromUnsignedLongLong(uwsgi_worker_exceptions(i+1)); if (PyDict_SetItemString(worker_dict, "exceptions", zero)) { goto clear; } Py_DECREF(zero); if (uwsgi.workers[i + 1].cheaped) { zero = PyString_FromString("cheap"); } else if (uwsgi.workers[i + 1].suspended && !uwsgi_worker_is_busy(i+1)) { zero = PyString_FromString("pause"); } else { if (uwsgi.workers[i + 1].sig) { zero = PyString_FromFormat("sig%d",uwsgi.workers[i + 1].signum); } else if (uwsgi_worker_is_busy(i+1)) { zero = PyString_FromString("busy"); } else { zero = PyString_FromString("idle"); } } if (PyDict_SetItemString(worker_dict, "status", zero)) { goto clear; } Py_DECREF(zero); zero = PyLong_FromUnsignedLongLong(uwsgi.workers[i + 1].rss_size); if (PyDict_SetItemString(worker_dict, "rss", zero)) { goto clear; } Py_DECREF(zero); zero = PyLong_FromUnsignedLongLong(uwsgi.workers[i + 1].vsz_size); if (PyDict_SetItemString(worker_dict, "vsz", zero)) { goto clear; } Py_DECREF(zero); zero = PyLong_FromUnsignedLongLong(uwsgi.workers[i + 1].running_time); if (PyDict_SetItemString(worker_dict, "running_time", zero)) { goto clear; } Py_DECREF(zero); zero = PyLong_FromLong(uwsgi.workers[i + 1].last_spawn); if (PyDict_SetItemString(worker_dict, "last_spawn", zero)) { goto clear; } Py_DECREF(zero); zero = PyLong_FromUnsignedLongLong(uwsgi.workers[i + 1].respawn_count-1); if (PyDict_SetItemString(worker_dict, "respawn_count", zero)) { goto clear; } Py_DECREF(zero); zero = PyLong_FromUnsignedLongLong(uwsgi.workers[i + 1].tx); if (PyDict_SetItemString(worker_dict, "tx", zero)) { goto clear; } Py_DECREF(zero); zero = PyLong_FromUnsignedLongLong(uwsgi.workers[i + 1].avg_response_time); if (PyDict_SetItemString(worker_dict, "avg_rt", zero)) { goto clear; } Py_DECREF(zero); apps_tuple = PyTuple_New(uwsgi.workers[i+1].apps_cnt); for(j=0;jmodifier1); PyDict_SetItemString(apps_dict, "modifier1", zero); Py_DECREF(zero); zero = PyString_FromStringAndSize(ua->mountpoint, ua->mountpoint_len); PyDict_SetItemString(apps_dict, "mountpoint", zero); Py_DECREF(zero); zero = PyInt_FromLong((long) ua->startup_time); PyDict_SetItemString(apps_dict, "startup_time", zero); Py_DECREF(zero); zero = PyInt_FromLong((long)ua->interpreter); PyDict_SetItemString(apps_dict, "interpreter", zero); Py_DECREF(zero); zero = PyInt_FromLong((long)ua->callable); PyDict_SetItemString(apps_dict, "callable", zero); Py_DECREF(zero); zero = PyLong_FromUnsignedLongLong(ua->requests); PyDict_SetItemString(apps_dict, "requests", zero); Py_DECREF(zero); zero = PyLong_FromUnsignedLongLong(ua->exceptions); PyDict_SetItemString(apps_dict, "exceptions", zero); Py_DECREF(zero); if (*ua->chdir) { zero = PyString_FromString(ua->chdir); } else { zero = PyString_FromString(""); } PyDict_SetItemString(apps_dict, "chdir", zero); Py_DECREF(zero); PyTuple_SetItem(apps_tuple, j, apps_dict); } PyDict_SetItemString(worker_dict, "apps", apps_tuple); Py_DECREF(apps_tuple); } Py_INCREF(up.workers_tuple); return up.workers_tuple; clear: PyErr_Print(); PyErr_Clear(); Py_INCREF(Py_None); return Py_None; } /* uWSGI reload */ PyObject *py_uwsgi_reload(PyObject * self, PyObject * args) { if (kill(uwsgi.workers[0].pid, SIGHUP)) { uwsgi_error("kill()"); Py_INCREF(Py_None); return Py_None; } Py_INCREF(Py_True); return Py_True; } /* uWSGI stop */ PyObject *py_uwsgi_stop(PyObject * self, PyObject * args) { if (kill(uwsgi.workers[0].pid, SIGQUIT)) { uwsgi_error("kill()"); Py_INCREF(Py_None); return Py_None; } Py_INCREF(Py_True); return Py_True; } PyObject *py_uwsgi_request_id(PyObject * self, PyObject * args) { struct wsgi_request *wsgi_req = py_current_wsgi_req(); return PyLong_FromUnsignedLongLong(uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].requests); } PyObject *py_uwsgi_worker_id(PyObject * self, PyObject * args) { return PyInt_FromLong(uwsgi.mywid); } PyObject *py_uwsgi_mule_id(PyObject * self, PyObject * args) { return PyInt_FromLong(uwsgi.muleid); } PyObject *py_uwsgi_logsize(PyObject * self, PyObject * args) { return PyLong_FromUnsignedLongLong(uwsgi.shared->logsize); } PyObject *py_uwsgi_mem(PyObject * self, PyObject * args) { uint64_t rss=0, vsz = 0; PyObject *ml = PyTuple_New(2); get_memusage(&rss, &vsz); PyTuple_SetItem(ml, 0, PyLong_FromUnsignedLongLong(rss)); PyTuple_SetItem(ml, 1, PyLong_FromUnsignedLongLong(vsz)); return ml; } PyObject *py_uwsgi_cl(PyObject * self, PyObject * args) { struct wsgi_request *wsgi_req = py_current_wsgi_req(); return PyLong_FromUnsignedLongLong(wsgi_req->post_cl); } PyObject *py_uwsgi_disconnect(PyObject * self, PyObject * args) { struct wsgi_request *wsgi_req = py_current_wsgi_req(); uwsgi_disconnect(wsgi_req); Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_ready_fd(PyObject * self, PyObject * args) { struct wsgi_request *wsgi_req = py_current_wsgi_req(); return PyInt_FromLong(uwsgi_ready_fd(wsgi_req)); } PyObject *py_uwsgi_accepting(PyObject * self, PyObject * args) { int accepting = 1; if (!PyArg_ParseTuple(args, "|i", &accepting)) { return NULL; } uwsgi.workers[uwsgi.mywid].accepting = !!accepting; return Py_None; } PyObject *py_uwsgi_parse_file(PyObject * self, PyObject * args) { char *filename; int fd; ssize_t len; char *buffer, *ptrbuf, *bufferend, *keybuf; uint16_t strsize = 0, keysize = 0; struct uwsgi_header uh; PyObject *zero; if (!PyArg_ParseTuple(args, "s:parsefile", &filename)) { return NULL; } UWSGI_RELEASE_GIL fd = open(filename, O_RDONLY); if (fd < 0) { uwsgi_error_open(filename); UWSGI_GET_GIL goto clear; } len = read(fd, &uh, 4); if (len != 4) { uwsgi_error("read()"); UWSGI_GET_GIL goto clear2; } buffer = malloc(uh.pktsize); if (!buffer) { uwsgi_error("malloc()"); UWSGI_GET_GIL goto clear2; } len = read(fd, buffer, uh.pktsize); if (len != uh.pktsize) { uwsgi_error("read()"); free(buffer); UWSGI_GET_GIL goto clear2; } UWSGI_GET_GIL ptrbuf = buffer; bufferend = ptrbuf + uh.pktsize; if (!uh.modifier1 || uh.modifier1 == UWSGI_MODIFIER_SPOOL_REQUEST) { zero = PyDict_New(); while (ptrbuf < bufferend) { if (ptrbuf + 2 < bufferend) { memcpy(&strsize, ptrbuf, 2); #ifdef __BIG_ENDIAN__ strsize = uwsgi_swap16(strsize); #endif /* key cannot be null */ if (!strsize) { uwsgi_log("uwsgi key cannot be null.\n"); goto clear3; } ptrbuf += 2; if (ptrbuf + strsize < bufferend) { // var key keybuf = ptrbuf; keysize = strsize; ptrbuf += strsize; // value can be null (even at the end) so use <= if (ptrbuf + 2 <= bufferend) { memcpy(&strsize, ptrbuf, 2); #ifdef __BIG_ENDIAN__ strsize = uwsgi_swap16(strsize); #endif ptrbuf += 2; if (ptrbuf + strsize <= bufferend) { PyDict_SetItem(zero, PyString_FromStringAndSize(keybuf, keysize), PyString_FromStringAndSize(ptrbuf, strsize)); ptrbuf += strsize; } else { goto clear3; } } else { goto clear3; } } } else { goto clear3; } } close(fd); free(buffer); return zero; } free(buffer); goto clear2; clear3: Py_DECREF(zero); free(buffer); clear2: close(fd); clear: Py_INCREF(Py_None); return Py_None; } static PyMethodDef uwsgi_spooler_methods[] = { #ifdef PYTHREE {"send_to_spooler", (PyCFunction)(void *)py_uwsgi_send_spool, METH_VARARGS|METH_KEYWORDS, ""}, {"spool", (PyCFunction)(void *)py_uwsgi_send_spool, METH_VARARGS|METH_KEYWORDS, ""}, #else {"send_to_spooler", (PyCFunction)(void *)py_uwsgi_send_spool, METH_KEYWORDS, ""}, {"spool", (PyCFunction)(void *)py_uwsgi_send_spool, METH_KEYWORDS, ""}, #endif {"set_spooler_frequency", py_uwsgi_spooler_freq, METH_VARARGS, ""}, {"spooler_jobs", py_uwsgi_spooler_jobs, METH_VARARGS, ""}, {"spooler_pid", py_uwsgi_spooler_pid, METH_VARARGS, ""}, {"spooler_pids", py_uwsgi_spooler_pids, METH_VARARGS, ""}, {"spooler_get_task", py_uwsgi_spooler_get_task, METH_VARARGS, ""}, {NULL, NULL}, }; PyObject *py_uwsgi_suspend(PyObject * self, PyObject * args) { struct wsgi_request *wsgi_req = py_current_wsgi_req(); if (uwsgi.schedule_to_main) uwsgi.schedule_to_main(wsgi_req); Py_INCREF(Py_True); return Py_True; } static PyMethodDef uwsgi_advanced_methods[] = { {"reload", py_uwsgi_reload, METH_VARARGS, ""}, {"stop", py_uwsgi_stop, METH_VARARGS, ""}, {"workers", py_uwsgi_workers, METH_VARARGS, ""}, {"masterpid", py_uwsgi_masterpid, METH_VARARGS, ""}, {"total_requests", py_uwsgi_total_requests, METH_VARARGS, ""}, {"request_id", py_uwsgi_request_id, METH_VARARGS, ""}, {"worker_id", py_uwsgi_worker_id, METH_VARARGS, ""}, {"mule_id", py_uwsgi_mule_id, METH_VARARGS, ""}, {"log", py_uwsgi_log, METH_VARARGS, ""}, {"log_this_request", py_uwsgi_log_this, METH_VARARGS, ""}, {"set_logvar", py_uwsgi_set_logvar, METH_VARARGS, ""}, {"get_logvar", py_uwsgi_get_logvar, METH_VARARGS, ""}, {"alarm", py_uwsgi_alarm, METH_VARARGS, ""}, {"disconnect", py_uwsgi_disconnect, METH_VARARGS, ""}, {"lock", py_uwsgi_lock, METH_VARARGS, ""}, {"is_locked", py_uwsgi_is_locked, METH_VARARGS, ""}, {"unlock", py_uwsgi_unlock, METH_VARARGS, ""}, {"cl", py_uwsgi_cl, METH_VARARGS, ""}, {"accepting", py_uwsgi_accepting, METH_VARARGS, ""}, {"setprocname", py_uwsgi_setprocname, METH_VARARGS, ""}, {"listen_queue", py_uwsgi_listen_queue, METH_VARARGS, ""}, {"register_signal", py_uwsgi_register_signal, METH_VARARGS, ""}, {"signal", py_uwsgi_signal, METH_VARARGS, ""}, {"signal_wait", py_uwsgi_signal_wait, METH_VARARGS, ""}, {"signal_registered", py_uwsgi_signal_registered, METH_VARARGS, ""}, {"signal_received", py_uwsgi_signal_received, METH_VARARGS, ""}, {"add_file_monitor", py_uwsgi_add_file_monitor, METH_VARARGS, ""}, {"add_timer", py_uwsgi_add_timer, METH_VARARGS, ""}, {"add_rb_timer", py_uwsgi_add_rb_timer, METH_VARARGS, ""}, {"add_cron", py_uwsgi_add_cron, METH_VARARGS, ""}, #ifdef UWSGI_ROUTING {"route", py_uwsgi_route, METH_VARARGS, ""}, #endif {"register_rpc", py_uwsgi_register_rpc, METH_VARARGS, ""}, {"rpc", py_uwsgi_rpc, METH_VARARGS, ""}, {"rpc_list", py_uwsgi_rpc_list, METH_VARARGS, ""}, {"call", py_uwsgi_call, METH_VARARGS, ""}, {"sendfile", py_uwsgi_advanced_sendfile, METH_VARARGS, ""}, {"offload", py_uwsgi_offload, METH_VARARGS, ""}, {"set_warning_message", py_uwsgi_warning, METH_VARARGS, ""}, {"mem", py_uwsgi_mem, METH_VARARGS, ""}, {"logsize", py_uwsgi_logsize, METH_VARARGS, ""}, #ifdef UWSGI_SSL {"i_am_the_lord", py_uwsgi_i_am_the_lord, METH_VARARGS, ""}, {"lord_scroll", py_uwsgi_lord_scroll, METH_VARARGS, ""}, {"scrolls", py_uwsgi_scrolls, METH_VARARGS, ""}, #endif {"async_sleep", py_uwsgi_async_sleep, METH_VARARGS, ""}, {"async_connect", py_uwsgi_async_connect, METH_VARARGS, ""}, {"green_schedule", py_uwsgi_suspend, METH_VARARGS, ""}, {"suspend", py_uwsgi_suspend, METH_VARARGS, ""}, {"wait_fd_read", py_eventfd_read, METH_VARARGS, ""}, {"wait_fd_write", py_eventfd_write, METH_VARARGS, ""}, {"connect", py_uwsgi_connect, METH_VARARGS, ""}, {"connection_fd", py_uwsgi_connection_fd, METH_VARARGS, ""}, {"is_connected", py_uwsgi_is_connected, METH_VARARGS, ""}, {"send", py_uwsgi_send, METH_VARARGS, ""}, {"recv", py_uwsgi_recv, METH_VARARGS, ""}, {"close", py_uwsgi_close, METH_VARARGS, ""}, {"i_am_the_spooler", py_uwsgi_i_am_the_spooler, METH_VARARGS, ""}, {"parsefile", py_uwsgi_parse_file, METH_VARARGS, ""}, {"embedded_data", py_uwsgi_embedded_data, METH_VARARGS, ""}, {"extract", py_uwsgi_extract, METH_VARARGS, ""}, {"mule_msg", py_uwsgi_mule_msg, METH_VARARGS, ""}, {"farm_msg", py_uwsgi_farm_msg, METH_VARARGS, ""}, {"mule_get_msg", (PyCFunction)(void *)py_uwsgi_mule_get_msg, METH_VARARGS|METH_KEYWORDS, ""}, {"farm_get_msg", py_uwsgi_farm_get_msg, METH_VARARGS, ""}, {"in_farm", py_uwsgi_in_farm, METH_VARARGS, ""}, {"ready", py_uwsgi_ready, METH_VARARGS, ""}, {"set_user_harakiri", py_uwsgi_set_user_harakiri, METH_VARARGS, ""}, {"websocket_recv", py_uwsgi_websocket_recv, METH_VARARGS, ""}, {"websocket_recv_nb", py_uwsgi_websocket_recv_nb, METH_VARARGS, ""}, {"websocket_send", py_uwsgi_websocket_send, METH_VARARGS, ""}, {"websocket_send_binary", py_uwsgi_websocket_send_binary, METH_VARARGS, ""}, {"websocket_handshake", py_uwsgi_websocket_handshake, METH_VARARGS, ""}, {"chunked_read", py_uwsgi_chunked_read, METH_VARARGS, ""}, {"chunked_read_nb", py_uwsgi_chunked_read_nb, METH_VARARGS, ""}, {"ready_fd", py_uwsgi_ready_fd, METH_VARARGS, ""}, {"add_var", py_uwsgi_add_var, METH_VARARGS, ""}, {"micros", py_uwsgi_micros, METH_VARARGS, ""}, {NULL, NULL}, }; static PyMethodDef uwsgi_sa_methods[] = { {"sharedarea_read", py_uwsgi_sharedarea_read, METH_VARARGS, ""}, {"sharedarea_write", py_uwsgi_sharedarea_write, METH_VARARGS, ""}, {"sharedarea_readbyte", py_uwsgi_sharedarea_read8, METH_VARARGS, ""}, {"sharedarea_writebyte", py_uwsgi_sharedarea_write8, METH_VARARGS, ""}, {"sharedarea_read8", py_uwsgi_sharedarea_read8, METH_VARARGS, ""}, {"sharedarea_write8", py_uwsgi_sharedarea_write8, METH_VARARGS, ""}, {"sharedarea_readlong", py_uwsgi_sharedarea_read64, METH_VARARGS, ""}, {"sharedarea_writelong", py_uwsgi_sharedarea_write64, METH_VARARGS, ""}, {"sharedarea_read64", py_uwsgi_sharedarea_read64, METH_VARARGS, ""}, {"sharedarea_write64", py_uwsgi_sharedarea_write64, METH_VARARGS, ""}, {"sharedarea_read32", py_uwsgi_sharedarea_read32, METH_VARARGS, ""}, {"sharedarea_write32", py_uwsgi_sharedarea_write32, METH_VARARGS, ""}, {"sharedarea_read16", py_uwsgi_sharedarea_read16, METH_VARARGS, ""}, {"sharedarea_write16", py_uwsgi_sharedarea_write16, METH_VARARGS, ""}, {"sharedarea_inclong", py_uwsgi_sharedarea_inc64, METH_VARARGS, ""}, {"sharedarea_inc64", py_uwsgi_sharedarea_inc64, METH_VARARGS, ""}, {"sharedarea_inc32", py_uwsgi_sharedarea_inc32, METH_VARARGS, ""}, {"sharedarea_dec64", py_uwsgi_sharedarea_dec64, METH_VARARGS, ""}, {"sharedarea_dec32", py_uwsgi_sharedarea_dec32, METH_VARARGS, ""}, {"sharedarea_rlock", py_uwsgi_sharedarea_rlock, METH_VARARGS, ""}, {"sharedarea_wlock", py_uwsgi_sharedarea_wlock, METH_VARARGS, ""}, {"sharedarea_unlock", py_uwsgi_sharedarea_unlock, METH_VARARGS, ""}, #if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER) #ifndef HAS_NOT_PyMemoryView_FromBuffer {"sharedarea_memoryview", py_uwsgi_sharedarea_memoryview, METH_VARARGS, ""}, #endif {"sharedarea_object", py_uwsgi_sharedarea_object, METH_VARARGS, ""}, #endif {NULL, NULL}, }; PyObject *py_uwsgi_cache_clear(PyObject * self, PyObject * args) { char *cache = NULL; if (!PyArg_ParseTuple(args, "|s:cache_clear", &cache)) { return NULL; } UWSGI_RELEASE_GIL if (!uwsgi_cache_magic_clear(cache)) { UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; } UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_cache_del(PyObject * self, PyObject * args) { char *key; Py_ssize_t keylen = 0; char *cache = NULL; if (!PyArg_ParseTuple(args, "s#|s:cache_del", &key, &keylen, &cache)) { return NULL; } UWSGI_RELEASE_GIL if (!uwsgi_cache_magic_del(key, keylen, cache)) { UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; } UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_cache_set(PyObject * self, PyObject * args) { char *key; char *value; Py_ssize_t vallen = 0; Py_ssize_t keylen = 0; char *remote = NULL; uint64_t expires = 0; if (!PyArg_ParseTuple(args, "s#s#|ls:cache_set", &key, &keylen, &value, &vallen, &expires, &remote)) { return NULL; } UWSGI_RELEASE_GIL if (uwsgi_cache_magic_set(key, keylen, value, vallen, expires, 0, remote)) { UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; } PyObject *py_uwsgi_cache_update(PyObject * self, PyObject * args) { char *key; char *value; Py_ssize_t vallen = 0; Py_ssize_t keylen = 0; char *remote = NULL; uint64_t expires = 0; if (!PyArg_ParseTuple(args, "s#s#|ls:cache_update", &key, &keylen, &value, &vallen, &expires, &remote)) { return NULL; } UWSGI_RELEASE_GIL if (uwsgi_cache_magic_set(key, keylen, value, vallen, expires, UWSGI_CACHE_FLAG_UPDATE, remote)) { UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; } PyObject *py_uwsgi_cache_inc(PyObject * self, PyObject * args) { char *key; Py_ssize_t keylen = 0; char *remote = NULL; int64_t value = 1; uint64_t expires = 0; if (!PyArg_ParseTuple(args, "s#|lls:cache_inc", &key, &keylen, &value, &expires, &remote)) { return NULL; } UWSGI_RELEASE_GIL if (uwsgi_cache_magic_set(key, keylen, (char *) &value, 8, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE|UWSGI_CACHE_FLAG_INC, remote)) { UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; } PyObject *py_uwsgi_cache_dec(PyObject * self, PyObject * args) { char *key; Py_ssize_t keylen = 0; char *remote = NULL; int64_t value = 1; uint64_t expires = 0; if (!PyArg_ParseTuple(args, "s#|lls:cache_dec", &key, &keylen, &value, &expires, &remote)) { return NULL; } UWSGI_RELEASE_GIL if (uwsgi_cache_magic_set(key, keylen, (char *) &value, 8, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE|UWSGI_CACHE_FLAG_DEC, remote)) { UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; } PyObject *py_uwsgi_cache_mul(PyObject * self, PyObject * args) { char *key; Py_ssize_t keylen = 0; char *remote = NULL; int64_t value = 2; uint64_t expires = 0; if (!PyArg_ParseTuple(args, "s#|lls:cache_mul", &key, &keylen, &value, &expires, &remote)) { return NULL; } UWSGI_RELEASE_GIL if (uwsgi_cache_magic_set(key, keylen, (char *) &value, 8, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE|UWSGI_CACHE_FLAG_MUL, remote)) { UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; } PyObject *py_uwsgi_cache_div(PyObject * self, PyObject * args) { char *key; Py_ssize_t keylen = 0; char *remote = NULL; int64_t value = 2; uint64_t expires = 0; if (!PyArg_ParseTuple(args, "s#|lls:cache_div", &key, &keylen, &value, &expires, &remote)) { return NULL; } UWSGI_RELEASE_GIL if (uwsgi_cache_magic_set(key, keylen, (char *) &value, 8, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE|UWSGI_CACHE_FLAG_DIV, remote)) { UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; } PyObject *py_uwsgi_cache_exists(PyObject * self, PyObject * args) { char *key; Py_ssize_t keylen = 0; char *cache = NULL; if (!PyArg_ParseTuple(args, "s#|s:cache_exists", &key, &keylen, &cache)) { return NULL; } UWSGI_RELEASE_GIL if (uwsgi_cache_magic_exists(key, keylen, cache)) { UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; } UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_queue_push(PyObject * self, PyObject * args) { Py_ssize_t msglen = 0; char *message ; PyObject *res; if (!PyArg_ParseTuple(args, "s#:queue_push", &message, &msglen)) { return NULL; } if (uwsgi.queue_size) { UWSGI_RELEASE_GIL uwsgi_wlock(uwsgi.queue_lock); if (uwsgi_queue_push(message, msglen)) { uwsgi_rwunlock(uwsgi.queue_lock); UWSGI_GET_GIL Py_INCREF(Py_True); res = Py_True; } else { uwsgi_rwunlock(uwsgi.queue_lock); UWSGI_GET_GIL Py_INCREF(Py_None); res = Py_None; } return res; } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_queue_set(PyObject * self, PyObject * args) { Py_ssize_t msglen = 0; uint64_t pos = 0; char *message ; PyObject *res; if (!PyArg_ParseTuple(args, "ls#:queue_set", &pos, &message, &msglen)) { return NULL; } if (uwsgi.queue_size) { UWSGI_RELEASE_GIL uwsgi_wlock(uwsgi.queue_lock); if (uwsgi_queue_set(pos, message, msglen)) { uwsgi_rwunlock(uwsgi.queue_lock); UWSGI_GET_GIL Py_INCREF(Py_True); res = Py_True; } else { uwsgi_rwunlock(uwsgi.queue_lock); UWSGI_GET_GIL Py_INCREF(Py_None); res = Py_None; } return res; } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_queue_slot(PyObject * self, PyObject * args) { return PyLong_FromUnsignedLongLong(uwsgi.queue_header->pos); } PyObject *py_uwsgi_queue_pull_slot(PyObject * self, PyObject * args) { return PyLong_FromUnsignedLongLong(uwsgi.queue_header->pull_pos); } PyObject *py_uwsgi_queue_pull(PyObject * self, PyObject * args) { char *message; uint64_t size; PyObject *res; char *storage; if (uwsgi.queue_size) { UWSGI_RELEASE_GIL uwsgi_wlock(uwsgi.queue_lock); message = uwsgi_queue_pull(&size); if (!message || size == 0) { uwsgi_rwunlock(uwsgi.queue_lock); UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } storage = uwsgi_malloc(size); memcpy(storage, message, size); uwsgi_rwunlock(uwsgi.queue_lock); UWSGI_GET_GIL res = PyString_FromStringAndSize(storage, size); free(storage); return res; } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_queue_pop(PyObject * self, PyObject * args) { char *message; uint64_t size; PyObject *res; char *storage; if (uwsgi.queue_size) { UWSGI_RELEASE_GIL uwsgi_wlock(uwsgi.queue_lock); message = uwsgi_queue_pop(&size); if (!message || size == 0) { uwsgi_rwunlock(uwsgi.queue_lock); UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } storage = uwsgi_malloc(size); memcpy(storage, message, size); uwsgi_rwunlock(uwsgi.queue_lock); UWSGI_GET_GIL res = PyString_FromStringAndSize(storage, size); free(storage); return res; } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_queue_get(PyObject * self, PyObject * args) { long index = 0; uint64_t size = 0; char *message; PyObject *res; char *storage; if (!PyArg_ParseTuple(args, "l:queue_get", &index)) { return NULL; } if (uwsgi.queue_size) { UWSGI_RELEASE_GIL uwsgi_rlock(uwsgi.queue_lock); message = uwsgi_queue_get(index, &size); if (!message || size == 0) { uwsgi_rwunlock(uwsgi.queue_lock); UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } storage = uwsgi_malloc(size); memcpy(storage, message, size); uwsgi_rwunlock(uwsgi.queue_lock); UWSGI_GET_GIL res = PyString_FromStringAndSize(storage, size); free(storage); return res; } Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_queue_last(PyObject * self, PyObject * args) { long i, num = 0; uint64_t size = 0; char *message; PyObject *res = NULL; uint64_t base; char *storage; if (!PyArg_ParseTuple(args, "|l:queue_last", &num)) { return NULL; } if (uwsgi.queue_size) { if (num > 0) { res = PyList_New(0); } UWSGI_RELEASE_GIL uwsgi_rlock(uwsgi.queue_lock); if (uwsgi.queue_header->pos > 0) { base = uwsgi.queue_header->pos-1; } else { base = uwsgi.queue_size-1; } if (num == 0) { message = uwsgi_queue_get(base, &size); if (!message || size == 0) { uwsgi_rwunlock(uwsgi.queue_lock); UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } storage = uwsgi_malloc(size); memcpy(storage, message, size); uwsgi_rwunlock(uwsgi.queue_lock); UWSGI_GET_GIL res = PyString_FromStringAndSize(storage, size); free(storage); return res; } if (num > (long)uwsgi.queue_size) num = uwsgi.queue_size; char **queue_items = uwsgi_malloc(sizeof(char *) * num); uint64_t *queue_items_size = uwsgi_malloc(sizeof(uint64_t) * num); long item_pos = 0; while(num) { message = uwsgi_queue_get(base, &size); if (!message || size == 0) { queue_items[item_pos] = NULL; queue_items_size[item_pos] = 0; } else { queue_items[item_pos] = uwsgi_malloc(size); memcpy(queue_items[item_pos], message, size); queue_items_size[item_pos] = size; } item_pos++; if (base > 0) { base--; } else { base = uwsgi.queue_size-1; } num--; } uwsgi_rwunlock(uwsgi.queue_lock); UWSGI_GET_GIL for(i=0;ilock); for(;;) { uci = uwsgi_cache_keys(uc, &pos, &uci); if (!uci) break; PyObject *ci = PyString_FromStringAndSize(uci->key, uci->keysize); PyList_Append(l, ci); Py_DECREF(ci); } uwsgi_rwunlock(uc->lock); return l; } static PyMethodDef uwsgi_cache_methods[] = { {"cache_get", py_uwsgi_cache_get, METH_VARARGS, ""}, {"cache_set", py_uwsgi_cache_set, METH_VARARGS, ""}, {"cache_update", py_uwsgi_cache_update, METH_VARARGS, ""}, {"cache_del", py_uwsgi_cache_del, METH_VARARGS, ""}, {"cache_exists", py_uwsgi_cache_exists, METH_VARARGS, ""}, {"cache_clear", py_uwsgi_cache_clear, METH_VARARGS, ""}, {"cache_inc", py_uwsgi_cache_inc, METH_VARARGS, ""}, {"cache_dec", py_uwsgi_cache_dec, METH_VARARGS, ""}, {"cache_mul", py_uwsgi_cache_mul, METH_VARARGS, ""}, {"cache_div", py_uwsgi_cache_div, METH_VARARGS, ""}, {"cache_num", py_uwsgi_cache_num, METH_VARARGS, ""}, {"cache_keys", py_uwsgi_cache_keys, METH_VARARGS, ""}, {NULL, NULL}, }; static PyMethodDef uwsgi_queue_methods[] = { {"queue_get", py_uwsgi_queue_get, METH_VARARGS, ""}, {"queue_set", py_uwsgi_queue_set, METH_VARARGS, ""}, {"queue_last", py_uwsgi_queue_last, METH_VARARGS, ""}, {"queue_push", py_uwsgi_queue_push, METH_VARARGS, ""}, {"queue_pull", py_uwsgi_queue_pull, METH_VARARGS, ""}, {"queue_pop", py_uwsgi_queue_pop, METH_VARARGS, ""}, {"queue_slot", py_uwsgi_queue_slot, METH_VARARGS, ""}, {"queue_pull_slot", py_uwsgi_queue_pull_slot, METH_VARARGS, ""}, {NULL, NULL}, }; PyObject *py_uwsgi_metric_inc(PyObject * self, PyObject * args) { char *key; int64_t value = 1; if (!PyArg_ParseTuple(args, "s|l:metric_inc", &key, &value)) return NULL; UWSGI_RELEASE_GIL if (uwsgi_metric_inc(key, NULL, value)) { UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; } PyObject *py_uwsgi_metric_dec(PyObject * self, PyObject * args) { char *key; int64_t value = 1; if (!PyArg_ParseTuple(args, "s|l:metric_dec", &key, &value)) return NULL; UWSGI_RELEASE_GIL if (uwsgi_metric_dec(key, NULL, value)) { UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; } PyObject *py_uwsgi_metric_mul(PyObject * self, PyObject * args) { char *key; int64_t value = 1; if (!PyArg_ParseTuple(args, "s|l:metric_mul", &key, &value)) return NULL; UWSGI_RELEASE_GIL if (uwsgi_metric_mul(key, NULL, value)) { UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; } PyObject *py_uwsgi_metric_div(PyObject * self, PyObject * args) { char *key; int64_t value = 1; if (!PyArg_ParseTuple(args, "s|l:metric_div", &key, &value)) return NULL; UWSGI_RELEASE_GIL if (uwsgi_metric_div(key, NULL, value)) { UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; } PyObject *py_uwsgi_metric_set(PyObject * self, PyObject * args) { char *key; int64_t value = 1; if (!PyArg_ParseTuple(args, "s|l:metric_set", &key, &value)) return NULL; UWSGI_RELEASE_GIL if (uwsgi_metric_set(key, NULL, value)) { UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; } PyObject *py_uwsgi_metric_get(PyObject * self, PyObject * args) { char *key; if (!PyArg_ParseTuple(args, "s:metric_get", &key)) return NULL; UWSGI_RELEASE_GIL int64_t value = uwsgi_metric_get(key, NULL); UWSGI_GET_GIL return PyLong_FromLongLong(value); } PyObject *py_uwsgi_metric_set_max(PyObject * self, PyObject * args) { char *key; int64_t value = 1; if (!PyArg_ParseTuple(args, "s|l:metric_set_max", &key, &value)) return NULL; UWSGI_RELEASE_GIL if (uwsgi_metric_set_max(key, NULL, value)) { UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; } PyObject *py_uwsgi_metric_set_min(PyObject * self, PyObject * args) { char *key; int64_t value = 1; if (!PyArg_ParseTuple(args, "s|l:metric_set_min", &key, &value)) return NULL; UWSGI_RELEASE_GIL if (uwsgi_metric_set_min(key, NULL, value)) { UWSGI_GET_GIL Py_INCREF(Py_None); return Py_None; } UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; } static PyMethodDef uwsgi_metrics_methods[] = { {"metric_inc", py_uwsgi_metric_inc, METH_VARARGS, ""}, {"metric_dec", py_uwsgi_metric_dec, METH_VARARGS, ""}, {"metric_mul", py_uwsgi_metric_mul, METH_VARARGS, ""}, {"metric_div", py_uwsgi_metric_div, METH_VARARGS, ""}, {"metric_get", py_uwsgi_metric_get, METH_VARARGS, ""}, {"metric_set", py_uwsgi_metric_set, METH_VARARGS, ""}, {"metric_set_max", py_uwsgi_metric_set_max, METH_VARARGS, ""}, {"metric_set_min", py_uwsgi_metric_set_min, METH_VARARGS, ""}, {NULL, NULL}, }; void init_uwsgi_module_spooler(PyObject * current_uwsgi_module) { PyMethodDef *uwsgi_function; PyObject *uwsgi_module_dict; uwsgi_module_dict = PyModule_GetDict(current_uwsgi_module); if (!uwsgi_module_dict) { uwsgi_log("could not get uwsgi module __dict__\n"); exit(1); } for (uwsgi_function = uwsgi_spooler_methods; uwsgi_function->ml_name != NULL; uwsgi_function++) { PyObject *func = PyCFunction_New(uwsgi_function, NULL); PyDict_SetItemString(uwsgi_module_dict, uwsgi_function->ml_name, func); Py_DECREF(func); } } void init_uwsgi_module_advanced(PyObject * current_uwsgi_module) { PyMethodDef *uwsgi_function; PyObject *uwsgi_module_dict; uwsgi_module_dict = PyModule_GetDict(current_uwsgi_module); if (!uwsgi_module_dict) { uwsgi_log("could not get uwsgi module __dict__\n"); exit(1); } for (uwsgi_function = uwsgi_advanced_methods; uwsgi_function->ml_name != NULL; uwsgi_function++) { PyObject *func = PyCFunction_New(uwsgi_function, NULL); PyDict_SetItemString(uwsgi_module_dict, uwsgi_function->ml_name, func); Py_DECREF(func); } for (uwsgi_function = uwsgi_metrics_methods; uwsgi_function->ml_name != NULL; uwsgi_function++) { PyObject *func = PyCFunction_New(uwsgi_function, NULL); PyDict_SetItemString(uwsgi_module_dict, uwsgi_function->ml_name, func); Py_DECREF(func); } } void init_uwsgi_module_cache(PyObject * current_uwsgi_module) { PyMethodDef *uwsgi_function; PyObject *uwsgi_module_dict; uwsgi_module_dict = PyModule_GetDict(current_uwsgi_module); if (!uwsgi_module_dict) { uwsgi_log("could not get uwsgi module __dict__\n"); exit(1); } for (uwsgi_function = uwsgi_cache_methods; uwsgi_function->ml_name != NULL; uwsgi_function++) { PyObject *func = PyCFunction_New(uwsgi_function, NULL); PyDict_SetItemString(uwsgi_module_dict, uwsgi_function->ml_name, func); Py_DECREF(func); } } void init_uwsgi_module_queue(PyObject * current_uwsgi_module) { PyMethodDef *uwsgi_function; PyObject *uwsgi_module_dict; uwsgi_module_dict = PyModule_GetDict(current_uwsgi_module); if (!uwsgi_module_dict) { uwsgi_log("could not get uwsgi module __dict__\n"); exit(1); } for (uwsgi_function = uwsgi_queue_methods; uwsgi_function->ml_name != NULL; uwsgi_function++) { PyObject *func = PyCFunction_New(uwsgi_function, NULL); PyDict_SetItemString(uwsgi_module_dict, uwsgi_function->ml_name, func); Py_DECREF(func); } PyDict_SetItemString(uwsgi_module_dict, "queue_size", PyLong_FromUnsignedLongLong(uwsgi.queue_size)); } void init_uwsgi_module_sharedarea(PyObject * current_uwsgi_module) { PyMethodDef *uwsgi_function; PyObject *uwsgi_module_dict; uwsgi_module_dict = PyModule_GetDict(current_uwsgi_module); if (!uwsgi_module_dict) { uwsgi_log("could not get uwsgi module __dict__\n"); exit(1); } for (uwsgi_function = uwsgi_sa_methods; uwsgi_function->ml_name != NULL; uwsgi_function++) { PyObject *func = PyCFunction_New(uwsgi_function, NULL); PyDict_SetItemString(uwsgi_module_dict, uwsgi_function->ml_name, func); Py_DECREF(func); } } PyObject *py_snmp_set_counter32(PyObject * self, PyObject * args) { uint8_t oid_num; uint32_t oid_val = 0; if (!PyArg_ParseTuple(args, "bI:snmp_set_counter32", &oid_num, &oid_val)) { return NULL; } if (oid_num > 100 || oid_num < 1) goto clear; UWSGI_RELEASE_GIL uwsgi_wlock(uwsgi.snmp_lock); uwsgi.shared->snmp_value[oid_num - 1].type = SNMP_COUNTER32; uwsgi.shared->snmp_value[oid_num - 1].val = oid_val; uwsgi_rwunlock(uwsgi.snmp_lock); UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; clear: Py_INCREF(Py_None); return Py_None; } PyObject *py_snmp_set_counter64(PyObject * self, PyObject * args) { uint8_t oid_num; uint64_t oid_val = 0; if (!PyArg_ParseTuple(args, "bK:snmp_set_counter64", &oid_num, &oid_val)) { return NULL; } if (oid_num > 100 || oid_num < 1) goto clear; UWSGI_RELEASE_GIL uwsgi_wlock(uwsgi.snmp_lock); uwsgi.shared->snmp_value[oid_num - 1].type = SNMP_COUNTER64; uwsgi.shared->snmp_value[oid_num - 1].val = oid_val; uwsgi_rwunlock(uwsgi.snmp_lock); UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; clear: Py_INCREF(Py_None); return Py_None; } PyObject *py_snmp_set_gauge(PyObject * self, PyObject * args) { uint8_t oid_num; uint32_t oid_val = 0; if (!PyArg_ParseTuple(args, "bI:snmp_set_gauge", &oid_num, &oid_val)) { return NULL; } if (oid_num > 100 || oid_num < 1) goto clear; UWSGI_RELEASE_GIL uwsgi_wlock(uwsgi.snmp_lock); uwsgi.shared->snmp_value[oid_num - 1].type = SNMP_GAUGE; uwsgi.shared->snmp_value[oid_num - 1].val = oid_val; uwsgi_rwunlock(uwsgi.snmp_lock); UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; clear: Py_INCREF(Py_None); return Py_None; } PyObject *py_snmp_incr_counter32(PyObject * self, PyObject * args) { uint8_t oid_num; uint32_t oid_val = 1; if (!PyArg_ParseTuple(args, "bI:snmp_incr_counter32", &oid_num, &oid_val)) { PyErr_Clear(); if (!PyArg_ParseTuple(args, "b:snmp_incr_counter32", &oid_num)) { return NULL; } } if (oid_num > 100 || oid_num < 1) goto clear; UWSGI_RELEASE_GIL uwsgi_wlock(uwsgi.snmp_lock); uwsgi.shared->snmp_value[oid_num - 1].type = SNMP_COUNTER32; uwsgi.shared->snmp_value[oid_num - 1].val = uwsgi.shared->snmp_value[oid_num - 1].val + oid_val; uwsgi_rwunlock(uwsgi.snmp_lock); UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; clear: Py_INCREF(Py_None); return Py_None; } PyObject *py_snmp_incr_counter64(PyObject * self, PyObject * args) { uint8_t oid_num; uint64_t oid_val = 1; if (!PyArg_ParseTuple(args, "bI:snmp_incr_counter64", &oid_num, &oid_val)) { PyErr_Clear(); if (!PyArg_ParseTuple(args, "b:snmp_incr_counter64", &oid_num)) { return NULL; } } if (oid_num > 100 || oid_num < 1) goto clear; UWSGI_RELEASE_GIL uwsgi_wlock(uwsgi.snmp_lock); uwsgi.shared->snmp_value[oid_num - 1].type = SNMP_COUNTER64; uwsgi.shared->snmp_value[oid_num - 1].val = uwsgi.shared->snmp_value[oid_num - 1].val + oid_val; uwsgi_rwunlock(uwsgi.snmp_lock); UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; clear: Py_INCREF(Py_None); return Py_None; } PyObject *py_snmp_incr_gauge(PyObject * self, PyObject * args) { uint8_t oid_num; uint64_t oid_val = 1; if (!PyArg_ParseTuple(args, "bI:snmp_incr_gauge", &oid_num, &oid_val)) { PyErr_Clear(); if (!PyArg_ParseTuple(args, "b:snmp_incr_gauge", &oid_num)) { return NULL; } } if (oid_num > 100 || oid_num < 1) goto clear; UWSGI_RELEASE_GIL uwsgi_wlock(uwsgi.snmp_lock); uwsgi.shared->snmp_value[oid_num - 1].type = SNMP_GAUGE; uwsgi.shared->snmp_value[oid_num - 1].val = uwsgi.shared->snmp_value[oid_num - 1].val + oid_val; uwsgi_rwunlock(uwsgi.snmp_lock); UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; clear: Py_INCREF(Py_None); return Py_None; } PyObject *py_snmp_decr_counter32(PyObject * self, PyObject * args) { uint8_t oid_num; uint32_t oid_val = 1; if (!PyArg_ParseTuple(args, "bI:snmp_incr_counter32", &oid_num, &oid_val)) { PyErr_Clear(); if (!PyArg_ParseTuple(args, "b:snmp_incr_counter32", &oid_num)) { return NULL; } } if (oid_num > 100 || oid_num < 1) goto clear; UWSGI_RELEASE_GIL uwsgi_wlock(uwsgi.snmp_lock); uwsgi.shared->snmp_value[oid_num - 1].type = SNMP_COUNTER32; uwsgi.shared->snmp_value[oid_num - 1].val = uwsgi.shared->snmp_value[oid_num - 1].val - oid_val; uwsgi_rwunlock(uwsgi.snmp_lock); UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; clear: Py_INCREF(Py_None); return Py_None; } PyObject *py_snmp_decr_counter64(PyObject * self, PyObject * args) { uint8_t oid_num; uint64_t oid_val = 1; if (!PyArg_ParseTuple(args, "bI:snmp_incr_counter64", &oid_num, &oid_val)) { PyErr_Clear(); if (!PyArg_ParseTuple(args, "b:snmp_incr_counter64", &oid_num)) { return NULL; } } if (oid_num > 100 || oid_num < 1) goto clear; UWSGI_RELEASE_GIL uwsgi_wlock(uwsgi.snmp_lock); uwsgi.shared->snmp_value[oid_num - 1].type = SNMP_COUNTER64; uwsgi.shared->snmp_value[oid_num - 1].val = uwsgi.shared->snmp_value[oid_num - 1].val - oid_val; uwsgi_rwunlock(uwsgi.snmp_lock); UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; clear: Py_INCREF(Py_None); return Py_None; } static PyObject *py_snmp_decr_gauge(PyObject * self, PyObject * args) { uint8_t oid_num; uint64_t oid_val = 1; if (!PyArg_ParseTuple(args, "bI:snmp_incr_gauge", &oid_num, &oid_val)) { PyErr_Clear(); if (!PyArg_ParseTuple(args, "b:snmp_incr_gauge", &oid_num)) { return NULL; } } if (oid_num > 100 || oid_num < 1) goto clear; UWSGI_RELEASE_GIL uwsgi_wlock(uwsgi.snmp_lock); uwsgi.shared->snmp_value[oid_num - 1].type = SNMP_GAUGE; uwsgi.shared->snmp_value[oid_num - 1].val = uwsgi.shared->snmp_value[oid_num - 1].val - oid_val; uwsgi_rwunlock(uwsgi.snmp_lock); UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; clear: Py_INCREF(Py_None); return Py_None; } static PyObject *py_snmp_set_community(PyObject * self, PyObject * args) { char *snmp_community; if (!PyArg_ParseTuple(args, "s:snmp_set_community", &snmp_community)) { return NULL; } if (strlen(snmp_community) > 72) { uwsgi_log( "*** warning the supplied SNMP community string will be truncated to 72 chars ***\n"); memcpy(uwsgi.shared->snmp_community, snmp_community, 72); } else { memcpy(uwsgi.shared->snmp_community, snmp_community, strlen(snmp_community) + 1); } Py_INCREF(Py_True); return Py_True; } static PyMethodDef uwsgi_snmp_methods[] = { {"snmp_set_counter32", py_snmp_set_counter32, METH_VARARGS, ""}, {"snmp_set_counter64", py_snmp_set_counter64, METH_VARARGS, ""}, {"snmp_set_gauge", py_snmp_set_gauge, METH_VARARGS, ""}, {"snmp_incr_counter32", py_snmp_incr_counter32, METH_VARARGS, ""}, {"snmp_incr_counter64", py_snmp_incr_counter64, METH_VARARGS, ""}, {"snmp_incr_gauge", py_snmp_incr_gauge, METH_VARARGS, ""}, {"snmp_decr_counter32", py_snmp_decr_counter32, METH_VARARGS, ""}, {"snmp_decr_counter64", py_snmp_decr_counter64, METH_VARARGS, ""}, {"snmp_decr_gauge", py_snmp_decr_gauge, METH_VARARGS, ""}, {"snmp_set_community", py_snmp_set_community, METH_VARARGS, ""}, {NULL, NULL}, }; void init_uwsgi_module_snmp(PyObject * current_uwsgi_module) { PyMethodDef *uwsgi_function; PyObject *uwsgi_module_dict = PyModule_GetDict(current_uwsgi_module); if (!uwsgi_module_dict) { uwsgi_log("could not get uwsgi module __dict__\n"); exit(1); } for (uwsgi_function = uwsgi_snmp_methods; uwsgi_function->ml_name != NULL; uwsgi_function++) { PyObject *func = PyCFunction_New(uwsgi_function, NULL); PyDict_SetItemString(uwsgi_module_dict, uwsgi_function->ml_name, func); Py_DECREF(func); } uwsgi_log( "SNMP python functions initialized.\n"); } uwsgi-2.0.29/plugins/python/uwsgi_python.h000066400000000000000000000242361477626554400207070ustar00rootroot00000000000000#include /* See https://docs.python.org/3.10/whatsnew/3.10.html#id2 */ #define PY_SSIZE_T_CLEAN #include #include #include #define PYTHON_APP_TYPE_WSGI 0 #define PYTHON_APP_TYPE_WEB3 1 #define PYTHON_APP_TYPE_WSGI2 2 #define PYTHON_APP_TYPE_PUMP 3 #define PYTHON_APP_TYPE_WSGI_LITE 4 #if PY_MINOR_VERSION == 4 && PY_MAJOR_VERSION == 2 #define Py_ssize_t ssize_t #define UWSGI_PYTHON_OLD #endif #if (PY_VERSION_HEX >= 0x030b0000) # define UWSGI_PY311 #endif #if (PY_VERSION_HEX >= 0x030c0000) # define UWSGI_PY312 #endif #if (PY_VERSION_HEX >= 0x030d0000) # define UWSGI_PY313 #endif #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 7 #define HAS_NOT_PyMemoryView_FromBuffer #endif #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 7 #define HAS_NOT_PyFrame_GetLineNumber #endif #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 2 #define HAS_NOT_PyFrame_GetLineNumber #endif #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 0 #define HAS_NO_ERRORS_IN_PyFile_FromFd #endif #if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 7) || PY_MAJOR_VERSION < 3 #define HAS_NOT_PYOS_FORK_STABLE_API #endif #if PY_MAJOR_VERSION > 2 #define PYTHREE #endif #if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 7) || PY_MAJOR_VERSION < 3 #define UWSGI_SHOULD_CALL_PYEVAL_INITTHREADS #endif #if (PY_VERSION_HEX < 0x03090000) #ifndef Py_SET_SIZE #define Py_SET_SIZE(o, size) ((o)->ob_size = (size)) #endif #endif #define UWSGI_GET_GIL up.gil_get(); #define UWSGI_RELEASE_GIL up.gil_release(); #ifndef PyVarObject_HEAD_INIT #define PyVarObject_HEAD_INIT(x, y) PyObject_HEAD_INIT(x) y, #endif #define uwsgi_py_write_set_exception(x) if (!uwsgi.disable_write_exception) { PyErr_SetString(PyExc_IOError, "write error"); }; #define uwsgi_py_write_exception(x) uwsgi_py_write_set_exception(x); uwsgi_manage_exception(x, 0); #define uwsgi_py_check_write_errors if (wsgi_req->write_errors > 0 && uwsgi.write_errors_exception_only) {\ uwsgi_py_write_set_exception(wsgi_req);\ }\ else if (wsgi_req->write_errors > uwsgi.write_errors_tolerance)\ PyAPI_FUNC(PyObject *) PyMarshal_WriteObjectToString(PyObject *, int); PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromString(char *, Py_ssize_t); #ifdef PYTHREE #define UWSGI_PYFROMSTRING(x) PyUnicode_FromString(x) #define UWSGI_PYFROMSTRINGSIZE(x, y) PyUnicode_FromStringAndSize(x, y) #define PyInt_FromLong PyLong_FromLong #define PyInt_AsLong PyLong_AsLong #define PyInt_Check PyLong_Check #define PyString_Check PyBytes_Check #define PyString_FromStringAndSize PyBytes_FromStringAndSize #define PyString_FromFormat PyBytes_FromFormat #define PyString_FromString PyBytes_FromString #define PyString_Size PyBytes_Size #define PyString_Concat PyBytes_Concat #define PyString_AsString (char *) PyBytes_AsString #define PyFile_FromFile(A,B,C,D) PyFile_FromFd(fileno((A)), (B), (C), -1, NULL, NULL, NULL, 0) #define uwsgi_py_dict_get(a, b) PyDict_GetItem(a, PyBytes_FromString(b)); #define uwsgi_py_dict_del(a, b) PyDict_DelItem(a, PyBytes_FromString(b)); #else #define UWSGI_PYFROMSTRING(x) PyString_FromString(x) #define UWSGI_PYFROMSTRINGSIZE(x, y) PyString_FromStringAndSize(x, y) #define uwsgi_py_dict_get(a, b) PyDict_GetItemString(a, b) #define uwsgi_py_dict_del(a, b) PyDict_DelItemString(a, b) #endif #define LOADER_DYN 0 #define LOADER_UWSGI 1 #define LOADER_FILE 2 #define LOADER_PASTE 3 #define LOADER_EVAL 4 #define LOADER_CALLABLE 5 #define LOADER_STRING_CALLABLE 6 #define LOADER_MOUNT 7 #define LOADER_PECAN 8 #define LOADER_MAX 9 typedef struct uwsgi_Input { PyObject_HEAD struct wsgi_request *wsgi_req; } uwsgi_Input; struct uwsgi_python { char *home; int optimize; char *argv; int argc; #ifdef PYTHREE wchar_t **py_argv; #else char **py_argv; #endif PyObject *wsgi_spitout; PyObject *wsgi_writeout; PyThreadState *main_thread; char *test_module; char *pyshell; int pyshell_oneshot; struct uwsgi_string_list *python_path; struct uwsgi_string_list *import_list; struct uwsgi_string_list *shared_import_list; struct uwsgi_string_list *spooler_import_list; struct uwsgi_string_list *post_pymodule_alias; struct uwsgi_string_list *pymodule_alias; PyObject *loader_dict; PyObject* (*loaders[LOADER_MAX]) (void *); char *pecan; char *wsgi_config; char *file_config; char *paste; int paste_logger; char *eval; char *web3; char *pump; char *wsgi_lite; char *callable; #ifdef UWSGI_PY313 int *current_c_recursion_remaining; int *current_py_recursion_remaining; struct _PyInterpreterFrame **current_frame; int current_main_c_recursion_remaining; int current_main_py_recursion_remaining; struct _PyInterpreterFrame *current_main_frame; #elif defined UWSGI_PY312 int *current_c_recursion_remaining; int *current_py_recursion_remaining; _PyCFrame **current_frame; int current_main_c_recursion_remaining; int current_main_py_recursion_remaining; _PyCFrame *current_main_frame; #elif defined UWSGI_PY311 int *current_recursion_remaining; _PyCFrame **current_frame; int current_main_recursion_remaining; _PyCFrame *current_main_frame; #else int *current_recursion_depth; struct _frame **current_frame; int current_main_recursion_depth; struct _frame *current_main_frame; #endif void (*swap_ts)(struct wsgi_request *, struct uwsgi_app *); void (*reset_ts)(struct wsgi_request *, struct uwsgi_app *); pthread_key_t upt_save_key; pthread_key_t upt_gil_key; pthread_mutex_t lock_pyloaders; void (*gil_get) (void); void (*gil_release) (void); int auto_reload; char *tracebacker; struct uwsgi_string_list *auto_reload_ignore; PyObject *workers_tuple; PyObject *embedded_dict; char *wsgi_env_behaviour; void *(*wsgi_env_create)(struct wsgi_request *, struct uwsgi_app *); void (*wsgi_env_destroy)(struct wsgi_request *); int pep3333_input; void (*extension)(void); int reload_os_env; PyObject *after_req_hook; PyObject *after_req_hook_args; char *pyrun; int start_response_nodelay; char *programname; int wsgi_strict; int wsgi_accept_buffer; char *raw; PyObject *raw_callable; struct uwsgi_string_list *sharedarea; int call_osafterfork; int wsgi_disable_file_wrapper; char *worker_override; char *executable; int call_uwsgi_fork_hooks; }; void init_uwsgi_vars(void); void init_uwsgi_embedded_module(void); void uwsgi_wsgi_config(char *); void uwsgi_paste_config(char *); void uwsgi_file_config(char *); void uwsgi_eval_config(char *); int init_uwsgi_app(int, void *, struct wsgi_request *, PyThreadState *, int); PyObject *py_eventfd_read(PyObject *, PyObject *); PyObject *py_eventfd_write(PyObject *, PyObject *); int manage_python_response(struct wsgi_request *); int uwsgi_python_call(struct wsgi_request *, PyObject *, PyObject *); PyObject *python_call(PyObject *, PyObject *, int, struct wsgi_request *); PyObject *py_uwsgi_sendfile(PyObject *, PyObject *); PyObject *py_uwsgi_write(PyObject *, PyObject *); PyObject *py_uwsgi_spit(PyObject *, PyObject *); void init_pyargv(void); void *uwsgi_request_subhandler_web3(struct wsgi_request *, struct uwsgi_app *); int uwsgi_response_subhandler_web3(struct wsgi_request *); void *uwsgi_request_subhandler_pump(struct wsgi_request *, struct uwsgi_app *); int uwsgi_response_subhandler_pump(struct wsgi_request *); PyObject *uwsgi_uwsgi_loader(void *); PyObject *uwsgi_dyn_loader(void *); PyObject *uwsgi_file_loader(void *); PyObject *uwsgi_eval_loader(void *); PyObject *uwsgi_pecan_loader(void *); PyObject *uwsgi_paste_loader(void *); PyObject *uwsgi_callable_loader(void *); PyObject *uwsgi_string_callable_loader(void *); PyObject *uwsgi_mount_loader(void *); char *get_uwsgi_pymodule(char *); PyObject *get_uwsgi_pydict(char *); int uwsgi_request_wsgi(struct wsgi_request *); void uwsgi_after_request_wsgi(struct wsgi_request *); void *uwsgi_request_subhandler_wsgi(struct wsgi_request *, struct uwsgi_app*); int uwsgi_response_subhandler_wsgi(struct wsgi_request *); void gil_real_get(void); void gil_real_release(void); void gil_fake_get(void); void gil_fake_release(void); void init_uwsgi_module_advanced(PyObject *); void init_uwsgi_module_spooler(PyObject *); void init_uwsgi_module_sharedarea(PyObject *); void init_uwsgi_module_cache(PyObject *); void init_uwsgi_module_queue(PyObject *); void init_uwsgi_module_snmp(PyObject *); PyObject *uwsgi_python_dict_from_spooler_content(char *, char *, uint16_t, char *, size_t); PyObject *uwsgi_pyimport_by_filename(char *, char *); void threaded_swap_ts(struct wsgi_request *, struct uwsgi_app *); void simple_swap_ts(struct wsgi_request *, struct uwsgi_app *); void simple_threaded_swap_ts(struct wsgi_request *, struct uwsgi_app *); void threaded_reset_ts(struct wsgi_request *, struct uwsgi_app *); void simple_reset_ts(struct wsgi_request *, struct uwsgi_app *); void simple_threaded_reset_ts(struct wsgi_request *, struct uwsgi_app *); int uwsgi_python_profiler_call(PyObject *, PyFrameObject *, int, PyObject *); int uwsgi_python_tracer(PyObject *, PyFrameObject *, int, PyObject *); void uwsgi_python_reset_random_seed(void); char *uwsgi_pythonize(char *); void *uwsgi_python_autoreloader_thread(void *); void *uwsgi_python_tracebacker_thread(void *); int uwsgi_python_do_send_headers(struct wsgi_request *); void *uwsgi_python_tracebacker_thread(void *); PyObject *uwsgi_python_setup_thread(char *); struct uwsgi_buffer *uwsgi_python_exception_class(struct wsgi_request *); struct uwsgi_buffer *uwsgi_python_exception_msg(struct wsgi_request *); struct uwsgi_buffer *uwsgi_python_exception_repr(struct wsgi_request *); struct uwsgi_buffer *uwsgi_python_backtrace(struct wsgi_request *); void uwsgi_python_exception_log(struct wsgi_request *); int uwsgi_python_send_body(struct wsgi_request *, PyObject *); int uwsgi_request_python_raw(struct wsgi_request *); void uwsgi_python_set_thread_name(int); void uwsgi_python_add_item(char *, uint16_t, char *, uint16_t, void *); #define py_current_wsgi_req() current_wsgi_req();\ if (!wsgi_req) {\ return PyErr_Format(PyExc_SystemError, "you can call uwsgi api function only from the main callable");\ } #define uwsgi_pyexit {PyErr_Print();exit(1);} #ifdef __linux__ int uwsgi_init_symbol_import(void); #endif uwsgi-2.0.29/plugins/python/uwsgiplugin.py000066400000000000000000000064641477626554400207310ustar00rootroot00000000000000import os import sys try: from distutils import sysconfig paths = [ sysconfig.get_python_inc(), sysconfig.get_python_inc(plat_specific=True), ] except ImportError: import sysconfig paths = [ sysconfig.get_path('include'), sysconfig.get_path('platinclude'), ] def get_python_version(): version = sysconfig.get_config_var('VERSION') try: version = version + sys.abiflags except: pass return version NAME = 'python' GCC_LIST = [ 'python_plugin', 'pyutils', 'pyloader', 'wsgi_handlers', 'wsgi_headers', 'wsgi_subhandler', 'web3_subhandler', 'pump_subhandler', 'gil', 'uwsgi_pymodule', 'profiler', 'symimporter', 'tracebacker', 'raw' ] CFLAGS = ['-I' + path for path in paths] LDFLAGS = [] if not 'UWSGI_PYTHON_NOLIB' in os.environ: LIBS = sysconfig.get_config_var('LIBS').split() + sysconfig.get_config_var('SYSLIBS').split() # check if it is a non-shared build (but please, add --enable-shared to your python's ./configure script) use_static_lib = not sysconfig.get_config_var('Py_ENABLE_SHARED') if use_static_lib: libdir = sysconfig.get_config_var('LIBPL') # libdir does not exists, try to get it from the venv version = get_python_version() if not os.path.exists(libdir): libdir = '%s/lib/python%s/config' % (sys.prefix, version) # try skipping abiflag if not os.path.exists(libdir) and version.endswith('m'): version = version[:-1] libdir = '%s/lib/python%s/config' % (sys.prefix, version) # try 3.x style config dir if not os.path.exists(libdir): libdir = '%s/lib/python%s/config-%s' % (sys.prefix, version, get_python_version()) # try >=3.6 style config dir with arch as suffix if not os.path.exists(libdir): multiarch = sysconfig.get_config_var('MULTIARCH') libdir = '%s/lib/python%s/config-%s-%s' % (sys.prefix, version, get_python_version(), multiarch) # get cpu type uname = os.uname() if uname[4].startswith('arm'): libpath = '%s/%s' % (libdir, sysconfig.get_config_var('LIBRARY')) if not os.path.exists(libpath): libpath = '%s/%s' % (libdir, sysconfig.get_config_var('LDLIBRARY')) else: libpath = '%s/%s' % (libdir, sysconfig.get_config_var('LDLIBRARY')) if not os.path.exists(libpath): libpath = '%s/%s' % (libdir, sysconfig.get_config_var('LIBRARY')) if not os.path.exists(libpath): libpath = '%s/libpython%s.a' % (libdir, version) if os.path.exists(libpath): LIBS.append(libpath) # hack for messy linkers/compilers if '-lutil' in LIBS: LIBS.append('-lutil') if '-lrt' in LIBS: LIBS.append('-lrt') else: use_static_lib = False if not use_static_lib: try: libdir = sysconfig.get_config_var('LIBDIR') except: libdir = "%s/lib" % sysconfig.PREFIX LDFLAGS.append("-L%s" % libdir) LDFLAGS.append("-Wl,-rpath,%s" % libdir) os.environ['LD_RUN_PATH'] = "%s" % libdir LIBS.append('-lpython%s' % get_python_version()) else: LIBS = [] uwsgi-2.0.29/plugins/python/web3_subhandler.c000066400000000000000000000155741477626554400212170ustar00rootroot00000000000000#include "uwsgi_python.h" extern struct uwsgi_server uwsgi; extern struct uwsgi_python up; extern struct uwsgi_plugin python_plugin; extern PyTypeObject uwsgi_InputType; void *uwsgi_request_subhandler_web3(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) { PyObject *zero; int i; PyObject *pydictkey, *pydictvalue; char *path_info; for (i = 0; i < wsgi_req->var_cnt; i += 2) { #ifdef UWSGI_DEBUG uwsgi_debug("%.*s: %.*s\n", wsgi_req->hvec[i].iov_len, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i+1].iov_len, wsgi_req->hvec[i+1].iov_base); #endif #ifdef PYTHREE pydictkey = PyUnicode_DecodeLatin1(wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, NULL); pydictvalue = PyUnicode_DecodeLatin1(wsgi_req->hvec[i + 1].iov_base, wsgi_req->hvec[i + 1].iov_len, NULL); #else pydictkey = PyString_FromStringAndSize(wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len); pydictvalue = PyString_FromStringAndSize(wsgi_req->hvec[i + 1].iov_base, wsgi_req->hvec[i + 1].iov_len); #endif PyDict_SetItem(wsgi_req->async_environ, pydictkey, pydictvalue); Py_DECREF(pydictkey); Py_DECREF(pydictvalue); } if (wsgi_req->uh->modifier1 == UWSGI_MODIFIER_MANAGE_PATH_INFO) { wsgi_req->uh->modifier1 = python_plugin.modifier1; pydictkey = PyDict_GetItemString(wsgi_req->async_environ, "SCRIPT_NAME"); if (pydictkey) { if (PyString_Check(pydictkey)) { pydictvalue = PyDict_GetItemString(wsgi_req->async_environ, "PATH_INFO"); if (pydictvalue) { if (PyString_Check(pydictvalue)) { path_info = PyString_AsString(pydictvalue); PyDict_SetItemString(wsgi_req->async_environ, "PATH_INFO", PyString_FromString(path_info + PyString_Size(pydictkey))); } } } } } // create wsgi.input custom object wsgi_req->async_input = (PyObject *) PyObject_New(uwsgi_Input, &uwsgi_InputType); ((uwsgi_Input*)wsgi_req->async_input)->wsgi_req = wsgi_req; PyDict_SetItemString(wsgi_req->async_environ, "web3.input", wsgi_req->async_input); PyDict_SetItemString(wsgi_req->async_environ, "web3.version", wi->gateway_version); zero = PyFile_FromFile(stderr, "web3_input", "w", NULL); PyDict_SetItemString(wsgi_req->async_environ, "web3.errors", zero); Py_DECREF(zero); PyDict_SetItemString(wsgi_req->async_environ, "web3.run_once", Py_False); PyDict_SetItemString(wsgi_req->async_environ, "web3.multithread", Py_False); if (uwsgi.numproc == 1) { PyDict_SetItemString(wsgi_req->async_environ, "web3.multiprocess", Py_False); } else { PyDict_SetItemString(wsgi_req->async_environ, "web3.multiprocess", Py_True); } if (wsgi_req->scheme_len > 0) { zero = UWSGI_PYFROMSTRINGSIZE(wsgi_req->scheme, wsgi_req->scheme_len); } else if (wsgi_req->https_len > 0) { if (!strncasecmp(wsgi_req->https, "on", 2) || wsgi_req->https[0] == '1') { zero = UWSGI_PYFROMSTRING("https"); } else { zero = UWSGI_PYFROMSTRING("http"); } } else { zero = UWSGI_PYFROMSTRING("http"); } PyDict_SetItemString(wsgi_req->async_environ, "web3.url_scheme", zero); Py_DECREF(zero); wsgi_req->async_app = wi->callable; // export .env only in non-threaded mode if (uwsgi.threads < 2) { PyDict_SetItemString(up.embedded_dict, "env", wsgi_req->async_environ); } PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.version", wi->uwsgi_version); if (uwsgi.cores > 1) { PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.core", PyInt_FromLong(wsgi_req->async_id)); } PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.node", wi->uwsgi_node); // call if (PyTuple_GetItem(wsgi_req->async_args, 0) != wsgi_req->async_environ) { if (PyTuple_SetItem(wsgi_req->async_args, 0, wsgi_req->async_environ)) { uwsgi_log_verbose("unable to set environ to the python application callable, consider using the holy env allocator\n"); return NULL; } } return python_call(wsgi_req->async_app, wsgi_req->async_args, uwsgi.catch_exceptions, wsgi_req); } int uwsgi_response_subhandler_web3(struct wsgi_request *wsgi_req) { PyObject *pychunk; // ok its a yield if (!wsgi_req->async_placeholder) { if (PyTuple_Check((PyObject *)wsgi_req->async_result)) { if (PyTuple_Size((PyObject *)wsgi_req->async_result) != 3) { uwsgi_log("invalid Web3 response.\n"); goto clear; } wsgi_req->async_placeholder = PyTuple_GetItem((PyObject *)wsgi_req->async_result, 0); Py_INCREF((PyObject *)wsgi_req->async_placeholder); PyObject *spit_args = PyTuple_New(2); PyObject *status = PyTuple_GetItem((PyObject *)wsgi_req->async_result, 1); Py_INCREF(status); PyTuple_SetItem(spit_args, 0, status); PyObject *headers = PyTuple_GetItem((PyObject *)wsgi_req->async_result, 2); Py_INCREF(headers); PyTuple_SetItem(spit_args, 1, headers); if (py_uwsgi_spit(Py_None, spit_args) == NULL) { PyErr_Print(); Py_DECREF(spit_args); goto clear; } Py_DECREF(spit_args); if (PyString_Check((PyObject *)wsgi_req->async_placeholder)) { char *content = PyString_AsString(wsgi_req->async_placeholder); size_t content_len = PyString_Size(wsgi_req->async_placeholder); UWSGI_RELEASE_GIL uwsgi_response_write_body_do(wsgi_req, content, content_len); UWSGI_GET_GIL uwsgi_py_check_write_errors { uwsgi_py_write_exception(wsgi_req); } goto clear; } PyObject *tmp = (PyObject *)wsgi_req->async_placeholder; wsgi_req->async_placeholder = PyObject_GetIter( (PyObject *)wsgi_req->async_placeholder ); Py_DECREF(tmp); if (!wsgi_req->async_placeholder) { goto clear; } if (uwsgi.async > 1) { return UWSGI_AGAIN; } } else { uwsgi_log("invalid Web3 response.\n"); goto clear; } } pychunk = PyIter_Next(wsgi_req->async_placeholder); if (!pychunk) { if (PyErr_Occurred()) { uwsgi_manage_exception(wsgi_req, uwsgi.catch_exceptions); } goto clear; } if (PyString_Check(pychunk)) { char *content = PyString_AsString(pychunk); size_t content_len = PyString_Size(pychunk); UWSGI_RELEASE_GIL uwsgi_response_write_body_do(wsgi_req, content, content_len); UWSGI_GET_GIL uwsgi_py_check_write_errors { uwsgi_py_write_exception(wsgi_req); Py_DECREF(pychunk); goto clear; } } Py_DECREF(pychunk); return UWSGI_AGAIN; clear: Py_XDECREF((PyObject *)wsgi_req->async_placeholder); Py_DECREF((PyObject *)wsgi_req->async_result); PyErr_Clear(); return UWSGI_OK; } uwsgi-2.0.29/plugins/python/wsgi_handlers.c000066400000000000000000000334321477626554400207720ustar00rootroot00000000000000#include "uwsgi_python.h" extern struct uwsgi_server uwsgi; extern struct uwsgi_python up; extern struct uwsgi_plugin python_plugin; PyObject *uwsgi_Input_iter(PyObject *self) { Py_INCREF(self); return self; } PyObject *uwsgi_Input_getline(uwsgi_Input *self, long hint) { struct wsgi_request *wsgi_req = self->wsgi_req; ssize_t rlen = 0; UWSGI_RELEASE_GIL char *buf = uwsgi_request_body_readline(wsgi_req, hint, &rlen); UWSGI_GET_GIL if (buf == uwsgi.empty) { return PyString_FromString(""); } if (buf) { return PyString_FromStringAndSize(buf, rlen); } if (rlen < 0) { return PyErr_Format(PyExc_IOError, "error during readline(%ld) on wsgi.input", hint); } return PyErr_Format(PyExc_IOError, "timeout during readline(%ld) on wsgi.input", hint); } PyObject *uwsgi_Input_next(PyObject* self) { PyObject *line = uwsgi_Input_getline((uwsgi_Input *)self, 0); if (!line) return NULL; if (PyString_Size(line) == 0) { Py_DECREF(line); PyErr_SetNone(PyExc_StopIteration); return NULL; } return line; } static void uwsgi_Input_free(uwsgi_Input *self) { PyObject_Del(self); } static PyObject *uwsgi_Input_read(uwsgi_Input *self, PyObject *args) { long arg_len = 0; if (!PyArg_ParseTuple(args, "|l:read", &arg_len)) { return NULL; } struct wsgi_request *wsgi_req = self->wsgi_req; ssize_t rlen = 0; UWSGI_RELEASE_GIL char *buf = uwsgi_request_body_read(wsgi_req, arg_len, &rlen); UWSGI_GET_GIL if (buf == uwsgi.empty) { return PyString_FromString(""); } if (buf) { return PyString_FromStringAndSize(buf, rlen); } // error ? if (rlen < 0) { return PyErr_Format(PyExc_IOError, "error during read(%ld) on wsgi.input", arg_len); } // timeout ? return PyErr_Format(PyExc_IOError, "timeout during read(%ld) on wsgi.input", arg_len); } static PyObject *uwsgi_Input_readline(uwsgi_Input *self, PyObject *args) { long hint = 0; if (!PyArg_ParseTuple(args, "|l:readline", &hint)) { return NULL; } PyObject *line = uwsgi_Input_getline(self, hint); if (!line) return NULL; if (PyString_Size(line) == 0) { Py_DECREF(line); return PyString_FromString(""); } return line; } static PyObject *uwsgi_Input_readlines(uwsgi_Input *self, PyObject *args) { long hint = 0; if (!PyArg_ParseTuple(args, "|l:readline", &hint)) { return NULL; } PyObject *res = PyList_New(0); for(;;) { PyObject *line = uwsgi_Input_getline(self, hint); if (!line) { Py_DECREF(res); return NULL; } if (PyString_Size(line) == 0) { Py_DECREF(line); return res; } PyList_Append(res, line); Py_DECREF(line); } return res; } static PyObject *uwsgi_Input_close(uwsgi_Input *self, PyObject *args) { Py_INCREF(Py_None); return Py_None; } static PyObject *uwsgi_Input_seek(uwsgi_Input *self, PyObject *args) { long pos = 0; int whence = 0; if (!uwsgi.post_buffering) { return PyErr_Format(PyExc_IOError, "seeking wsgi.input without post_buffering is IMPOSSIBLE !!!"); } if (!PyArg_ParseTuple(args, "l|i:seek", &pos, &whence)) { return NULL; } /* uwsgi_request_body_seek() uses SEEK_SET for positive value and SEEK_CUR for negative yous hould always try to transform the "pos" value to an absolute position. */ // current if (whence == 1) { pos += self->wsgi_req->post_pos; } // end of stream if (whence == 2) { pos += self->wsgi_req->post_cl; } if (pos < 0 || pos > (off_t)self->wsgi_req->post_cl) { return PyErr_Format(PyExc_IOError, "invalid seek position for wsgi.input"); } uwsgi_request_body_seek(self->wsgi_req, pos); Py_INCREF(Py_None); return Py_None; } static PyObject *uwsgi_Input_fileno(uwsgi_Input *self, PyObject *args) { return PyInt_FromLong(self->wsgi_req->fd); } static PyObject *uwsgi_Input_tell(uwsgi_Input *self, PyObject *args) { return PyLong_FromLong(self->wsgi_req->post_pos); } static PyMethodDef uwsgi_Input_methods[] = { { "read", (PyCFunction)uwsgi_Input_read, METH_VARARGS, 0 }, { "readline", (PyCFunction)uwsgi_Input_readline, METH_VARARGS, 0 }, { "readlines", (PyCFunction)uwsgi_Input_readlines, METH_VARARGS, 0 }, // add close to allow mod_wsgi compatibility { "close", (PyCFunction)uwsgi_Input_close, METH_VARARGS, 0 }, { "seek", (PyCFunction)uwsgi_Input_seek, METH_VARARGS, 0 }, { "tell", (PyCFunction)uwsgi_Input_tell, METH_VARARGS, 0 }, { "fileno", (PyCFunction)uwsgi_Input_fileno, METH_VARARGS, 0 }, { NULL, NULL} }; PyTypeObject uwsgi_InputType = { PyVarObject_HEAD_INIT(NULL, 0) "uwsgi._Input", /*tp_name */ sizeof(uwsgi_Input), /*tp_basicsize */ 0, /*tp_itemsize */ (destructor) uwsgi_Input_free, /*tp_dealloc */ 0, /*tp_print */ 0, /*tp_getattr */ 0, /*tp_setattr */ 0, /*tp_compare */ 0, /*tp_repr */ 0, /*tp_as_number */ 0, /*tp_as_sequence */ 0, /*tp_as_mapping */ 0, /*tp_hash */ 0, /*tp_call */ 0, /*tp_str */ 0, /*tp_getattr */ 0, /*tp_setattr */ 0, /*tp_as_buffer */ #if defined(Py_TPFLAGS_HAVE_ITER) Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, #else Py_TPFLAGS_DEFAULT, #endif "uwsgi input object.", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ uwsgi_Input_iter, /* tp_iter: __iter__() method */ uwsgi_Input_next, /* tp_iternext: next() method */ uwsgi_Input_methods, 0,0,0,0,0,0,0,0,0,0,0,0 }; PyObject *py_uwsgi_write(PyObject * self, PyObject * args) { PyObject *data; char *content; size_t content_len; struct wsgi_request *wsgi_req = py_current_wsgi_req(); data = PyTuple_GetItem(args, 0); if (PyString_Check(data)) { content = PyString_AsString(data); content_len = PyString_Size(data); UWSGI_RELEASE_GIL uwsgi_response_write_body_do(wsgi_req, content, content_len); UWSGI_GET_GIL // this is a special case for the write callable // no need to honout write-errors-exception-only if (wsgi_req->write_errors > uwsgi.write_errors_tolerance && !uwsgi.disable_write_exception) { uwsgi_py_write_set_exception(wsgi_req); return NULL; } } Py_INCREF(Py_None); return Py_None; } PyObject *py_eventfd_read(PyObject * self, PyObject * args) { int fd, timeout = 0; struct wsgi_request *wsgi_req = py_current_wsgi_req(); if (!PyArg_ParseTuple(args, "i|i", &fd, &timeout)) { return NULL; } if (async_add_fd_read(wsgi_req, fd, timeout)) { return PyErr_Format(PyExc_IOError, "unable to fd %d to the event queue", fd); } return PyString_FromString(""); } PyObject *py_eventfd_write(PyObject * self, PyObject * args) { int fd, timeout = 0; struct wsgi_request *wsgi_req = py_current_wsgi_req(); if (!PyArg_ParseTuple(args, "i|i", &fd, &timeout)) { return NULL; } if (async_add_fd_write(wsgi_req, fd, timeout)) { return PyErr_Format(PyExc_IOError, "unable to fd %d to the event queue", fd); } return PyString_FromString(""); } int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) { if (wsgi_req->is_raw) return uwsgi_request_python_raw(wsgi_req); struct uwsgi_app *wi; if (wsgi_req->async_force_again) { wi = &uwsgi_apps[wsgi_req->app_id]; wsgi_req->async_force_again = 0; UWSGI_GET_GIL // get rid of timeout if (wsgi_req->async_timed_out) { PyDict_SetItemString(wsgi_req->async_environ, "x-wsgiorg.fdevent.timeout", Py_True); wsgi_req->async_timed_out = 0; } else { PyDict_SetItemString(wsgi_req->async_environ, "x-wsgiorg.fdevent.timeout", Py_None); } if (wsgi_req->async_ready_fd) { PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.ready_fd", PyInt_FromLong(wsgi_req->async_last_ready_fd)); wsgi_req->async_ready_fd = 0; } else { PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.ready_fd", Py_None); } int ret = manage_python_response(wsgi_req); if (ret == UWSGI_OK) goto end; UWSGI_RELEASE_GIL if (ret == UWSGI_AGAIN) { wsgi_req->async_force_again = 1; } return ret; } /* Standard WSGI request */ if (!wsgi_req->uh->pktsize) { uwsgi_log( "Empty python request. skip.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } if (wsgi_req->dynamic) { // this part must be heavy locked in threaded modes if (uwsgi.threads > 1) { pthread_mutex_lock(&up.lock_pyloaders); } } if ( (wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, python_plugin.modifier1)) == -1) { if (wsgi_req->dynamic) { UWSGI_GET_GIL if (uwsgi.single_interpreter) { wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI); } else { wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, NULL, PYTHON_APP_TYPE_WSGI); } UWSGI_RELEASE_GIL } if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) { if (uwsgi_apps[uwsgi.default_app].modifier1 == python_plugin.modifier1) { wsgi_req->app_id = uwsgi.default_app; } } } if (wsgi_req->dynamic) { if (uwsgi.threads > 1) { pthread_mutex_unlock(&up.lock_pyloaders); } } if (wsgi_req->app_id == -1) { uwsgi_500(wsgi_req); uwsgi_log("--- no python application found, check your startup logs for errors ---\n"); goto clear2; } wi = &uwsgi_apps[wsgi_req->app_id]; up.swap_ts(wsgi_req, wi); if (wi->chdir[0] != 0) { #ifdef UWSGI_DEBUG uwsgi_debug("chdir to %s\n", wi->chdir); #endif if (chdir(wi->chdir)) { uwsgi_error("chdir()"); } } UWSGI_GET_GIL // no fear of race conditions for this counter as it is already protected by the GIL wi->requests++; // create WSGI environ wsgi_req->async_environ = up.wsgi_env_create(wsgi_req, wi); wsgi_req->async_result = wi->request_subhandler(wsgi_req, wi); if (wsgi_req->async_result) { while (wi->response_subhandler(wsgi_req) != UWSGI_OK) { if (uwsgi.async > 1) { UWSGI_RELEASE_GIL wsgi_req->async_force_again = 1; return UWSGI_AGAIN; } else { wsgi_req->switches++; } } } // this object must be freed/cleared always end: if (wsgi_req->async_input) { Py_DECREF((PyObject *)wsgi_req->async_input); } if (wsgi_req->async_environ) { up.wsgi_env_destroy(wsgi_req); } UWSGI_RELEASE_GIL up.reset_ts(wsgi_req, wi); clear2: return UWSGI_OK; } void uwsgi_after_request_wsgi(struct wsgi_request *wsgi_req) { if (up.after_req_hook) { if (uwsgi.harakiri_no_arh) { // leave harakiri mode if (uwsgi.workers[uwsgi.mywid].harakiri > 0) set_harakiri(0); } UWSGI_GET_GIL PyObject *arh = python_call(up.after_req_hook, up.after_req_hook_args, 0, NULL); if (!arh) { uwsgi_manage_exception(wsgi_req, 0); } else { Py_DECREF(arh); } PyErr_Clear(); UWSGI_RELEASE_GIL } log_request(wsgi_req); } PyObject *py_uwsgi_sendfile(PyObject * self, PyObject * args) { int chunk_size; PyObject *filelike; struct wsgi_request *wsgi_req = py_current_wsgi_req(); if (!PyArg_ParseTuple(args, "O|i:uwsgi_sendfile", &filelike, &chunk_size)) { return NULL; } if (!PyObject_HasAttrString(filelike, "read")) { PyErr_SetString(PyExc_AttributeError, "object has no attribute 'read'"); return NULL; } // wsgi.file_wrapper called a second time? Forget the old reference. if (wsgi_req->async_sendfile) { Py_DECREF(wsgi_req->async_sendfile); } // XXX: Not 100% sure why twice. // Maybe: We keep one at async_sendfile and transfer // one to the caller (even though he gave it to us). Py_INCREF(filelike); Py_INCREF(filelike); wsgi_req->async_sendfile = filelike; wsgi_req->sendfile_fd_chunk = chunk_size; return filelike; } void threaded_swap_ts(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) { if (uwsgi.single_interpreter == 0 && wi->interpreter != up.main_thread) { UWSGI_GET_GIL PyThreadState_Swap(uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].ts[wsgi_req->app_id]); UWSGI_RELEASE_GIL } } void threaded_reset_ts(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) { if (uwsgi.single_interpreter == 0 && wi->interpreter != up.main_thread) { UWSGI_GET_GIL PyThreadState_Swap((PyThreadState *) pthread_getspecific(up.upt_save_key)); UWSGI_RELEASE_GIL } } void simple_reset_ts(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) { if (uwsgi.single_interpreter == 0 && wi->interpreter != up.main_thread) { // restoring main interpreter PyThreadState_Swap(up.main_thread); } } void simple_swap_ts(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) { if (uwsgi.single_interpreter == 0 && wi->interpreter != up.main_thread) { // set the interpreter PyThreadState_Swap(wi->interpreter); } } void simple_threaded_reset_ts(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) { if (uwsgi.single_interpreter == 0 && wi->interpreter != up.main_thread) { // restoring main interpreter UWSGI_GET_GIL PyThreadState_Swap(up.main_thread); UWSGI_RELEASE_GIL } } void simple_threaded_swap_ts(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) { if (uwsgi.single_interpreter == 0 && wi->interpreter != up.main_thread) { // set the interpreter UWSGI_GET_GIL PyThreadState_Swap(wi->interpreter); UWSGI_RELEASE_GIL } } uwsgi-2.0.29/plugins/python/wsgi_headers.c000066400000000000000000000115601477626554400206030ustar00rootroot00000000000000#include "uwsgi_python.h" extern struct uwsgi_server uwsgi; extern struct uwsgi_python up; // check here PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) { PyObject *headers, *head; PyObject *h_key, *h_value; PyObject *exc_info = NULL; size_t i; struct wsgi_request *wsgi_req = py_current_wsgi_req(); // avoid double sending of headers if (wsgi_req->headers_sent) { return PyErr_Format(PyExc_IOError, "headers already sent"); } // this must be done before headers management if (PyTuple_Size(args) > 2) { exc_info = PyTuple_GetItem(args, 2); if (exc_info && exc_info != Py_None) { PyObject *exc_type = PyTuple_GetItem(exc_info, 0); PyObject *exc_val = PyTuple_GetItem(exc_info, 1); PyObject *exc_tb = PyTuple_GetItem(exc_info, 2); if (!exc_type || !exc_val || !exc_tb) { return NULL; } Py_INCREF(exc_type); Py_INCREF(exc_val); Py_INCREF(exc_tb); // in this way, error will be reported to the log PyErr_Restore(exc_type, exc_val, exc_tb); // the error is reported, let's continue... // return NULL } } head = PyTuple_GetItem(args, 0); if (!head) { return PyErr_Format(PyExc_TypeError, "start_response() takes at least 2 arguments"); } #ifdef PYTHREE // check for web3 if ((self != Py_None && !PyUnicode_Check(head)) || (self == Py_None && !PyBytes_Check(head))) { #else if (!PyString_Check(head)) { #endif return PyErr_Format(PyExc_TypeError, "http status must be a string"); } char *status_line = NULL; size_t status_line_len = 0; #ifdef PYTHREE PyObject *zero = NULL; PyObject *zero2 = NULL; if (self != Py_None) { zero = PyUnicode_AsLatin1String(head); if (!zero) { return PyErr_Format(PyExc_TypeError, "http status string must be encodable in latin1"); } status_line = PyBytes_AsString(zero); status_line_len = PyBytes_Size(zero); } else { status_line = PyBytes_AsString(head); status_line_len = PyBytes_Size(head); } #else status_line = PyString_AsString(head); status_line_len = PyString_Size(head); #endif if (uwsgi_response_prepare_headers(wsgi_req, status_line, status_line_len)) { #ifdef PYTHREE Py_DECREF(zero); #endif goto end; } #ifdef PYTHREE Py_DECREF(zero); #endif headers = PyTuple_GetItem(args, 1); if (!headers) { return PyErr_Format(PyExc_TypeError, "start_response() takes at least 2 arguments"); } if (!PyList_Check(headers)) { return PyErr_Format(PyExc_TypeError, "http headers must be in a python list"); } size_t h_count = PyList_Size(headers); for (i = 0; i < h_count; i++) { head = PyList_GetItem(headers, i); if (!head) { return NULL; } if (!PyTuple_Check(head)) { return PyErr_Format(PyExc_TypeError, "http header must be defined in a tuple"); } h_key = PyTuple_GetItem(head, 0); if (!h_key) { return PyErr_Format(PyExc_TypeError, "http header must be a 2-item tuple"); } #ifdef PYTHREE if ((self != Py_None && !PyUnicode_Check(h_key)) || (self == Py_None && !PyBytes_Check(h_key))) { #else if (!PyString_Check(h_key)) { #endif return PyErr_Format(PyExc_TypeError, "http header key must be a string"); } h_value = PyTuple_GetItem(head, 1); if (!h_value) { return PyErr_Format(PyExc_TypeError, "http header must be a 2-item tuple"); } #ifdef PYTHREE if ((self != Py_None && !PyUnicode_Check(h_value)) || (self == Py_None && !PyBytes_Check(h_value))) { #else if (!PyString_Check(h_value)) { #endif return PyErr_Format(PyExc_TypeError, "http header value must be a string"); } char *k = NULL; size_t kl = 0; char *v = NULL; size_t vl = 0; #ifdef PYTHREE if (self != Py_None) { zero = PyUnicode_AsLatin1String(h_key); if (!zero) { return PyErr_Format(PyExc_TypeError, "http header must be encodable in latin1"); } k = PyBytes_AsString(zero); kl = PyBytes_Size(zero); } else { k = PyBytes_AsString(h_key); kl = PyBytes_Size(h_key); } #else k = PyString_AsString(h_key); kl = PyString_Size(h_key); #endif #ifdef PYTHREE if (self != Py_None) { zero2 = PyUnicode_AsLatin1String(h_value); if (!zero2) { return PyErr_Format(PyExc_TypeError, "http header must be encodable in latin1"); } v = PyBytes_AsString(zero2); vl = PyBytes_Size(zero2); } else { v = PyBytes_AsString(h_value); vl = PyBytes_Size(h_value); } #else v = PyString_AsString(h_value); vl = PyString_Size(h_value); #endif if (uwsgi_response_add_header(wsgi_req, k, kl, v, vl)) { #ifdef PYTHREE Py_DECREF(zero); Py_DECREF(zero2); #endif return PyErr_Format(PyExc_TypeError, "unable to add header to the response"); } #ifdef PYTHREE Py_DECREF(zero); Py_DECREF(zero2); #endif } if (up.start_response_nodelay) { UWSGI_RELEASE_GIL if (uwsgi_response_write_headers_do(wsgi_req)) { UWSGI_GET_GIL return PyErr_Format(PyExc_IOError, "unable to directly send headers"); } UWSGI_GET_GIL } end: Py_INCREF(up.wsgi_writeout); return up.wsgi_writeout; } uwsgi-2.0.29/plugins/python/wsgi_subhandler.c000066400000000000000000000303771477626554400213260ustar00rootroot00000000000000#include "uwsgi_python.h" extern struct uwsgi_server uwsgi; extern struct uwsgi_python up; extern struct uwsgi_plugin python_plugin; extern PyTypeObject uwsgi_InputType; /* Albeit PEP 333/3333 is clear about what kind of return object we must expect from a WSGI callable, we CAN use the buffer api to optimize for lower-level returns type: bytes, bytearray, array.array to enable this optimization add --wsgi-accept-buffer NOTE: this is a violation of the standards !!! use only if you know the implications !!! */ int uwsgi_python_send_body(struct wsgi_request *wsgi_req, PyObject *chunk) { char *content = NULL; size_t content_len = 0; #if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER) Py_buffer pbuf; int has_buffer = 0; #endif if (!up.wsgi_accept_buffer && !wsgi_req->is_raw) goto strict; #if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER) if (PyObject_CheckBuffer(chunk)) { if (!PyObject_GetBuffer(chunk, &pbuf, PyBUF_SIMPLE)) { content = (char *) pbuf.buf; content_len = (size_t) pbuf.len; has_buffer = 1; goto found; } } #else if (PyObject_CheckReadBuffer(chunk)) { #ifdef UWSGI_PYTHON_OLD int buffer_len = 0; if (!PyObject_AsCharBuffer(chunk, (const char **) &content, &buffer_len)) { #else if (!PyObject_AsCharBuffer(chunk, (const char **) &content, (Py_ssize_t *) &content_len)) { #endif PyErr_Clear(); goto found; } #ifdef UWSGI_PYTHON_OLD content_len = buffer_len; #endif } #endif strict: // fallback if (PyString_Check(chunk)) { content = PyString_AsString(chunk); content_len = PyString_Size(chunk); } found: if (content) { UWSGI_RELEASE_GIL uwsgi_response_write_body_do(wsgi_req, content, content_len); UWSGI_GET_GIL #if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER) if (has_buffer) PyBuffer_Release(&pbuf); #endif uwsgi_py_check_write_errors { uwsgi_py_write_exception(wsgi_req); return -1; } return 1; } return 0; } /* * attempt to make a fd from a file-like PyObject - returns -1 on error. */ static int uwsgi_python_try_filelike_as_fd(PyObject *filelike) { int fd; if ((fd = PyObject_AsFileDescriptor(filelike)) < 0) { PyErr_Clear(); } return fd; } /* this is a hack for supporting non-file object passed to wsgi.file_wrapper */ static void uwsgi_python_consume_file_wrapper_read(struct wsgi_request *wsgi_req, PyObject *pychunk) { PyObject *read_method_args = NULL; PyObject *read_method = PyObject_GetAttrString(pychunk, "read"); if (wsgi_req->sendfile_fd_chunk > 0) { read_method_args = PyTuple_New(1); PyTuple_SetItem(read_method_args, 0, PyInt_FromLong(wsgi_req->sendfile_fd_chunk)); } else { read_method_args = PyTuple_New(0); } for(;;) { PyObject *read_method_output = PyObject_CallObject(read_method, read_method_args); if (PyErr_Occurred()) { uwsgi_manage_exception(wsgi_req, 0); break; } if (!read_method_output) break; if (PyString_Check(read_method_output)) { char *content = PyString_AsString(read_method_output); size_t content_len = PyString_Size(read_method_output); if (content_len == 0) { Py_DECREF(read_method_output); break; } UWSGI_RELEASE_GIL uwsgi_response_write_body_do(wsgi_req, content, content_len); UWSGI_GET_GIL } Py_DECREF(read_method_output); if (wsgi_req->sendfile_fd_chunk == 0) break; } Py_DECREF(read_method_args); Py_DECREF(read_method); } void *uwsgi_request_subhandler_wsgi(struct wsgi_request *wsgi_req, struct uwsgi_app *wi) { PyObject *zero; int i; PyObject *pydictkey, *pydictvalue; char *path_info; for (i = 0; i < wsgi_req->var_cnt; i += 2) { #ifdef UWSGI_DEBUG uwsgi_debug("%.*s: %.*s\n", wsgi_req->hvec[i].iov_len, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i+1].iov_len, wsgi_req->hvec[i+1].iov_base); #endif #ifdef PYTHREE pydictkey = PyUnicode_DecodeLatin1(wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, NULL); pydictvalue = PyUnicode_DecodeLatin1(wsgi_req->hvec[i + 1].iov_base, wsgi_req->hvec[i + 1].iov_len, NULL); #else pydictkey = PyString_FromStringAndSize(wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len); pydictvalue = PyString_FromStringAndSize(wsgi_req->hvec[i + 1].iov_base, wsgi_req->hvec[i + 1].iov_len); #endif #ifdef UWSGI_DEBUG uwsgi_log("%p %d %p %d\n", pydictkey, wsgi_req->hvec[i].iov_len, pydictvalue, wsgi_req->hvec[i + 1].iov_len); #endif PyDict_SetItem(wsgi_req->async_environ, pydictkey, pydictvalue); Py_DECREF(pydictkey); Py_DECREF(pydictvalue); } if (wsgi_req->uh->modifier1 == UWSGI_MODIFIER_MANAGE_PATH_INFO) { wsgi_req->uh->modifier1 = python_plugin.modifier1; pydictkey = PyDict_GetItemString(wsgi_req->async_environ, "SCRIPT_NAME"); if (pydictkey) { if (PyString_Check(pydictkey)) { pydictvalue = PyDict_GetItemString(wsgi_req->async_environ, "PATH_INFO"); if (pydictvalue) { if (PyString_Check(pydictvalue)) { path_info = PyString_AsString(pydictvalue); PyDict_SetItemString(wsgi_req->async_environ, "PATH_INFO", PyString_FromString(path_info + PyString_Size(pydictkey))); } } } } } // create wsgi.input custom object wsgi_req->async_input = (PyObject *) PyObject_New(uwsgi_Input, &uwsgi_InputType); ((uwsgi_Input*)wsgi_req->async_input)->wsgi_req = wsgi_req; PyDict_SetItemString(wsgi_req->async_environ, "wsgi.input", wsgi_req->async_input); if (!up.wsgi_disable_file_wrapper) PyDict_SetItemString(wsgi_req->async_environ, "wsgi.file_wrapper", wi->sendfile); if (uwsgi.async > 1) { PyDict_SetItemString(wsgi_req->async_environ, "x-wsgiorg.fdevent.readable", wi->eventfd_read); PyDict_SetItemString(wsgi_req->async_environ, "x-wsgiorg.fdevent.writable", wi->eventfd_write); PyDict_SetItemString(wsgi_req->async_environ, "x-wsgiorg.fdevent.timeout", Py_None); } PyDict_SetItemString(wsgi_req->async_environ, "wsgi.version", wi->gateway_version); PyDict_SetItemString(wsgi_req->async_environ, "wsgi.errors", wi->error); PyDict_SetItemString(wsgi_req->async_environ, "wsgi.run_once", Py_False); if (uwsgi.threads > 1) { PyDict_SetItemString(wsgi_req->async_environ, "wsgi.multithread", Py_True); } else { PyDict_SetItemString(wsgi_req->async_environ, "wsgi.multithread", Py_False); } if (uwsgi.numproc == 1) { PyDict_SetItemString(wsgi_req->async_environ, "wsgi.multiprocess", Py_False); } else { PyDict_SetItemString(wsgi_req->async_environ, "wsgi.multiprocess", Py_True); } if (wsgi_req->scheme_len > 0) { zero = UWSGI_PYFROMSTRINGSIZE(wsgi_req->scheme, wsgi_req->scheme_len); } else if (wsgi_req->https_len > 0) { if (!strncasecmp(wsgi_req->https, "on", 2) || wsgi_req->https[0] == '1') { zero = UWSGI_PYFROMSTRING("https"); } else { zero = UWSGI_PYFROMSTRING("http"); } } else { zero = UWSGI_PYFROMSTRING("http"); } PyDict_SetItemString(wsgi_req->async_environ, "wsgi.url_scheme", zero); Py_DECREF(zero); wsgi_req->async_app = wi->callable; // export .env only in non-threaded mode if (uwsgi.threads < 2) { PyDict_SetItemString(up.embedded_dict, "env", wsgi_req->async_environ); } PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.version", wi->uwsgi_version); if (uwsgi.cores > 1) { zero = PyInt_FromLong(wsgi_req->async_id); PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.core", zero); Py_DECREF(zero); } PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.node", wi->uwsgi_node); // call if (PyTuple_GetItem(wsgi_req->async_args, 0) != wsgi_req->async_environ) { Py_INCREF(wsgi_req->async_environ); if (PyTuple_SetItem(wsgi_req->async_args, 0, wsgi_req->async_environ)) { uwsgi_log_verbose("unable to set environ to the python application callable, consider using the holy env allocator\n"); return NULL; } } return python_call(wsgi_req->async_app, wsgi_req->async_args, uwsgi.catch_exceptions, wsgi_req); } int uwsgi_response_subhandler_wsgi(struct wsgi_request *wsgi_req) { PyObject *pychunk; // return or yield ? // in strict mode we do not optimize apps directly returning strings (or bytes) if (!up.wsgi_strict) { if (uwsgi_python_send_body(wsgi_req, (PyObject *)wsgi_req->async_result)) goto clear; } // Check if wsgi.file_wrapper has been used. if (wsgi_req->async_sendfile == wsgi_req->async_result) { wsgi_req->sendfile_fd = uwsgi_python_try_filelike_as_fd((PyObject *)wsgi_req->async_sendfile); if (wsgi_req->sendfile_fd >= 0) { UWSGI_RELEASE_GIL uwsgi_response_sendfile_do(wsgi_req, wsgi_req->sendfile_fd, 0, 0); UWSGI_GET_GIL } // we do not have an iterable, check for read() method else if (PyObject_HasAttrString((PyObject *)wsgi_req->async_result, "read")) { uwsgi_python_consume_file_wrapper_read(wsgi_req, (PyObject *)wsgi_req->async_result); } uwsgi_py_check_write_errors { uwsgi_py_write_exception(wsgi_req); } goto clear; } // ok its a yield if (!wsgi_req->async_placeholder) { wsgi_req->async_placeholder = PyObject_GetIter(wsgi_req->async_result); if (!wsgi_req->async_placeholder) { goto exception; } if (uwsgi.async > 1) { return UWSGI_AGAIN; } } pychunk = PyIter_Next(wsgi_req->async_placeholder); if (!pychunk) { exception: if (PyErr_Occurred()) { uwsgi_manage_exception(wsgi_req, uwsgi.catch_exceptions); } goto clear; } int ret = uwsgi_python_send_body(wsgi_req, pychunk); if (ret != 0) { if (ret < 0) { Py_DECREF(pychunk); goto clear; } } else if (wsgi_req->async_sendfile == pychunk) { // // XXX: It's not clear whether this can ever be sensibly reached // based on PEP 333/3333 - it would mean the iterator yielded // the result of wsgi.file_wrapper. However, the iterator should // only ever yield `bytes`... // wsgi_req->sendfile_fd = uwsgi_python_try_filelike_as_fd((PyObject *)wsgi_req->async_sendfile); if (wsgi_req->sendfile_fd >= 0) { UWSGI_RELEASE_GIL uwsgi_response_sendfile_do(wsgi_req, wsgi_req->sendfile_fd, 0, 0); UWSGI_GET_GIL } // we do not have an iterable, check for read() method else if (PyObject_HasAttrString(pychunk, "read")) { uwsgi_python_consume_file_wrapper_read(wsgi_req, pychunk); } uwsgi_py_check_write_errors { uwsgi_py_write_exception(wsgi_req); Py_DECREF(pychunk); goto clear; } } else if (pychunk != Py_None) { // The iterator returned something that we were not able to handle. PyObject *pystr = PyObject_Repr(pychunk); #ifdef PYTHREE const char *cstr = PyUnicode_AsUTF8(pystr); #else const char *cstr = PyString_AsString(pystr); #endif uwsgi_log("[ERROR] Unhandled object from iterator: %s (%p)\n", cstr, pychunk); Py_DECREF(pystr); } Py_DECREF(pychunk); return UWSGI_AGAIN; clear: // Release the reference that we took in py_uwsgi_sendfile. if (wsgi_req->async_sendfile != NULL) { Py_DECREF((PyObject *) wsgi_req->async_sendfile); } if (wsgi_req->async_placeholder != NULL) { Py_DECREF((PyObject *)wsgi_req->async_placeholder); } // Call close() on the response, this is required by the WSGI spec if (PyObject_HasAttrString((PyObject *)wsgi_req->async_result, "close")) { PyObject *close_method = PyObject_GetAttrString((PyObject *)wsgi_req->async_result, "close"); PyObject *close_method_args = PyTuple_New(0); #ifdef UWSGI_DEBUG uwsgi_log("calling close() for %.*s %p %p\n", wsgi_req->uri_len, wsgi_req->uri, close_method, close_method_args); #endif PyObject *close_method_output = PyObject_CallObject(close_method, close_method_args); if (PyErr_Occurred()) { uwsgi_manage_exception(wsgi_req, 0); } Py_DECREF(close_method_args); Py_XDECREF(close_method_output); Py_DECREF(close_method); } Py_DECREF((PyObject *)wsgi_req->async_result); PyErr_Clear(); return UWSGI_OK; } uwsgi-2.0.29/plugins/pyuwsgi/000077500000000000000000000000001477626554400161565ustar00rootroot00000000000000uwsgi-2.0.29/plugins/pyuwsgi/pyuwsgi.c000066400000000000000000000205331477626554400200340ustar00rootroot00000000000000#include "../python/uwsgi_python.h" //FIXME: [upstream:python] needs PyAPI_FUNC(void) #ifdef PYTHREE extern void Py_GetArgcArgv(int *, wchar_t ***); #else extern void Py_GetArgcArgv(int *, char ***); #endif extern struct uwsgi_server uwsgi; extern struct uwsgi_python up; extern char **environ; static int new_argc = -1; static int orig_argc = -1; static char **new_argv = NULL; static char **orig_argv = NULL; static char *new_argv_buf = NULL; PyObject *pyuwsgi_setup(PyObject * self, PyObject * args, PyObject * kwds) { if (new_argv) { PyErr_SetString(PyExc_RuntimeError, "uWSGI already setup"); return NULL; } if (uwsgi.mywid) { PyErr_SetString(PyExc_RuntimeError, "uWSGI must be setup by master"); return NULL; } PyObject *iterator; if (args == NULL || PyObject_Size(args) == 0) { PyObject *argv = PySys_GetObject("argv"); if (argv == NULL) return NULL; // during site.py maybe if (argv == Py_None) { argv = PyTuple_New(0); iterator = PyObject_GetIter(argv); Py_DECREF(argv); } else { iterator = PyObject_GetIter(argv); if (PyObject_Size(argv) > 0) { // forward past argv0 PyObject *item = PyIter_Next(iterator); Py_DECREF(item); } } } else if (PyObject_Size(args) == 1 && !PyString_Check(PyTuple_GetItem(args, 0)) ) { iterator = PyObject_GetIter(PyTuple_GetItem(args, 0)); } else { iterator = PyObject_GetIter(args); } if (iterator == NULL) { return NULL; } size_t size = 1; //FIXME: ARGS prior to and including -c/-m are REQUIRED! #ifdef PYTHREE PyObject *item = PyUnicode_FromString(orig_argv[0]); #else PyObject *item = PyString_FromString(orig_argv[0]); #endif PyObject *args_li = PyList_New(0); PyList_Append(args_li, item); size += strlen(orig_argv[0]) + 1; Py_DECREF(item); while ((item = PyIter_Next(iterator))) { PyObject *py_str = PyObject_Str(item); PyList_Append(args_li, py_str); #ifdef PYTHREE const char *str = PyUnicode_AsUTF8(py_str); size += strlen(str) + 1; #else size += PyObject_Length(item) + 1; #endif Py_DECREF(item); Py_DECREF(py_str); } Py_DECREF(iterator); new_argc = PyObject_Length(args_li); new_argv = uwsgi_calloc(sizeof(char *) * (new_argc + 2)); new_argv_buf = uwsgi_calloc(size); int i = 0; char *new_argv_ptr = new_argv_buf; for (i = 0; i < new_argc; i++) { PyObject *arg = PyList_GetItem(args_li, i); #ifdef PYTHREE const char *arg_str = PyUnicode_AsUTF8(arg); #else char *arg_str = PyString_AsString(arg); #endif new_argv[i] = new_argv_ptr; strcpy(new_argv_ptr, arg_str); new_argv_ptr += strlen(arg_str) + 1; } PyObject *args_tup = PyList_AsTuple(args_li); PyObject_SetAttrString(self, "NEW_ARGV", args_tup); Py_DECREF(args_tup); Py_DECREF(args_li); // TODO: convention here is a goto methinks? if (PyErr_Occurred()) { free(new_argv_buf); free(new_argv); new_argv = 0; new_argc = 0; return NULL; } Py_INCREF(self); return self; } PyObject *pyuwsgi_init(PyObject * self, PyObject * args, PyObject * kwds) { if (pyuwsgi_setup(self, args, kwds) == NULL) { return NULL; } uwsgi_setup(orig_argc, orig_argv, environ); int rc = uwsgi_run(); // never(?) here return Py_BuildValue("i", rc); } PyObject *pyuwsgi_run(PyObject * self, PyObject * args, PyObject * kwds) { // backcompat if (new_argv == NULL && pyuwsgi_setup(self, args, kwds) == NULL) { return NULL; } uwsgi_setup(orig_argc, orig_argv, environ); int rc = uwsgi_run(); // never(?) here return Py_BuildValue("i", rc); } PyMethodDef methods[] = { {"run", (PyCFunction) pyuwsgi_run, METH_VARARGS | METH_KEYWORDS, "run(...)" "\n>>> 0" "\n" "\n * Call setup(...) if not configured" "\n * Begin uWSGI mainloop" "\n NOTE: will not return" "\n"} , {"init", (PyCFunction) pyuwsgi_init, METH_VARARGS | METH_KEYWORDS, "init(...)" "\n>>> 0" "\n" "\n * Call setup(...)" "\n * Begin uWSGI mainloop" "\n NOTE: will not return" "\n"} , {"setup", (PyCFunction) pyuwsgi_setup, METH_VARARGS | METH_KEYWORDS, "setup('--master', ...)" "\n>>> " "\n" "\n * Initialize uWSGI core with (...)" "\n MUST only call once [RuntimeException]" "\n MUST only call from master [RuntimeException]" "\n"} , {NULL, NULL, 0, NULL} }; static void pyuwsgi_set_orig_argv(PyObject * self) { // ask python for the original argc/argv saved in Py_Main() #ifdef PYTHREE wchar_t ** tmp_orig_argv = NULL; Py_GetArgcArgv(&orig_argc, &tmp_orig_argv); int j; orig_argv = uwsgi_calloc(sizeof(char *) * (orig_argc + 2)); size_t size = 0; for (j=0;j uwsgi // // want: uwsgi.binary_argv[:] + uwsgi.argv[:]! // binary_argv = [binary_path] + args i_cm = i; } } #ifdef PYTHREE PyTuple_SetItem(m_orig_argv, i, PyUnicode_FromString(arg)); #else PyTuple_SetItem(m_orig_argv, i, PyString_FromString(arg)); #endif } //TODO: howto properly detect uwsgi already running... // orig_argv == uwsgi.orig_argv (?) // ^^^ but if Py_Main not called, python/main.c:orig_argv unset // howto interact/detect things in general PyObject *m_new_argv = PyTuple_New(0); PyObject_SetAttrString(self, "NEW_ARGV", m_new_argv); PyObject_SetAttrString(self, "ORIG_ARGV", m_orig_argv); Py_DECREF(m_new_argv); Py_DECREF(m_orig_argv); } #ifdef PYTHREE static struct PyModuleDef pyuwsgi_module = { PyModuleDef_HEAD_INIT, "pyuwsgi", /* name of module */ NULL, /* module documentation, may be NULL */ -1, /* size of per-interpreter state of the * module, or -1 if the module keeps state in * global variables. */ methods }; #endif #ifndef PYTHREE static PyObject *pyuwsgi_init_as(char *mod_name) { PyObject *m; m = PyImport_GetModuleDict(); if (m == NULL) { return NULL; } m = PyDict_GetItemString(m, mod_name); if (!m) { m = Py_InitModule(mod_name, NULL); } if (orig_argc < 0) { pyuwsgi_set_orig_argv(m); } int i; for (i = 0; methods[i].ml_name != NULL; i++) { PyObject *fun = PyObject_GetAttrString(m, methods[i].ml_name); if (fun != NULL) { // already exists Py_DECREF(fun); continue; } PyErr_Clear(); // rel: Python/modsupport.c:Py_InitModule4 PyObject *name = PyString_FromString(methods[i].ml_name); // fun(self, ...) fun = PyCFunction_NewEx(&methods[i], m, name); Py_DECREF(name); // module.fun PyObject_SetAttrString(m, methods[i].ml_name, fun); Py_DECREF(fun); } return m; } #endif #ifdef PYTHREE PyMODINIT_FUNC PyInit_pyuwsgi() { PyObject *m = PyModule_Create(&pyuwsgi_module); if (orig_argc < 0) { pyuwsgi_set_orig_argv(m); } return m; } #else PyMODINIT_FUNC initpyuwsgi() { (void) pyuwsgi_init_as("pyuwsgi"); } // allow the module to be called `uwsgi` PyMODINIT_FUNC inituwsgi() { (void) pyuwsgi_init_as("uwsgi"); } #endif void pyuwsgi_load() { if (new_argc > -1) { uwsgi.new_argc = new_argc; uwsgi.new_argv = new_argv; } } struct uwsgi_plugin pyuwsgi_plugin = { .name = "pyuwsgi", .on_load = pyuwsgi_load, }; uwsgi-2.0.29/plugins/pyuwsgi/uwsgiplugin.py000066400000000000000000000007161477626554400211110ustar00rootroot00000000000000import os import sys try: from distutils import sysconfig paths = [ sysconfig.get_python_inc(), sysconfig.get_python_inc(plat_specific=True), ] except ImportError: import sysconfig paths = [ sysconfig.get_path('include'), sysconfig.get_path('platinclude'), ] os.environ['UWSGI_PYTHON_NOLIB'] = '1' NAME = 'pyuwsgi' CFLAGS = ['-I' + path for path in paths] LDFLAGS = [] LIBS = [] GCC_LIST = ['pyuwsgi'] uwsgi-2.0.29/plugins/rack/000077500000000000000000000000001477626554400153675ustar00rootroot00000000000000uwsgi-2.0.29/plugins/rack/rack_api.c000066400000000000000000001024341477626554400173100ustar00rootroot00000000000000#include "uwsgi_rack.h" extern struct uwsgi_server uwsgi; extern struct uwsgi_rack ur; extern struct uwsgi_plugin rack_plugin; #define uwsgi_rack_api(x, y, z) rb_define_module_function(rb_uwsgi_embedded, x, y, z) static VALUE rack_uwsgi_metric_get(VALUE class, VALUE key) { Check_Type(key, T_STRING); int64_t value = uwsgi_metric_get(RSTRING_PTR(key), NULL); return LONG2NUM(value); } static VALUE rack_uwsgi_metric_set(VALUE class, VALUE key, VALUE val) { Check_Type(key, T_STRING); Check_Type(val, T_FIXNUM); // should be T_BIGNUM... if (uwsgi_metric_set(RSTRING_PTR(key), NULL, NUM2LONG(val) )) { return Qnil; } return Qtrue; } static VALUE rack_uwsgi_metric_inc(int argc, VALUE *argv, VALUE class) { int64_t value = 1; if (argc == 0) return Qnil; Check_Type(argv[0], T_STRING); if (argc > 1) { Check_Type(argv[1], T_FIXNUM); // should be T_BIGNUM... value = NUM2LONG(argv[1]); } if (uwsgi_metric_inc(RSTRING_PTR(argv[0]), NULL, value )) { return Qnil; } return Qtrue; } static VALUE rack_uwsgi_metric_dec(int argc, VALUE *argv, VALUE class) { int64_t value = 1; if (argc == 0) return Qnil; Check_Type(argv[0], T_STRING); if (argc > 1) { Check_Type(argv[1], T_FIXNUM); // should be T_BIGNUM... value = NUM2LONG(argv[1]); } if (uwsgi_metric_dec(RSTRING_PTR(argv[0]), NULL, value )) { return Qnil; } return Qtrue; } static VALUE rack_uwsgi_metric_mul(int argc, VALUE *argv, VALUE class) { int64_t value = 1; if (argc == 0) return Qnil; Check_Type(argv[0], T_STRING); if (argc > 1) { Check_Type(argv[1], T_FIXNUM); // should be T_BIGNUM... value = NUM2LONG(argv[1]); } if (uwsgi_metric_mul(RSTRING_PTR(argv[0]), NULL, value )) { return Qnil; } return Qtrue; } static VALUE rack_uwsgi_metric_div(int argc, VALUE *argv, VALUE class) { int64_t value = 1; if (argc == 0) return Qnil; Check_Type(argv[0], T_STRING); if (argc > 1) { Check_Type(argv[1], T_FIXNUM); // should be T_BIGNUM... value = NUM2LONG(argv[1]); } if (uwsgi_metric_div(RSTRING_PTR(argv[0]), NULL, value )) { return Qnil; } return Qtrue; } static VALUE rack_uwsgi_warning(VALUE class, VALUE rbmessage) { Check_Type(rbmessage, T_STRING); char *message = RSTRING_PTR(rbmessage); size_t len = RSTRING_LEN(rbmessage); if (len > 80) { uwsgi_log("- warning message must be max 80 chars, it will be truncated -"); memcpy(uwsgi.shared->warning_message, message, 80); uwsgi.shared->warning_message[80] = 0; } else { memcpy(uwsgi.shared->warning_message, message, len); uwsgi.shared->warning_message[len] = 0; } return Qnil; } static VALUE rack_uwsgi_user_harakiri(VALUE class, VALUE sec) { Check_Type(sec, T_FIXNUM); set_user_harakiri(NUM2INT(sec)); return Qnil; } static VALUE rack_uwsgi_log(VALUE class, VALUE msg) { Check_Type(msg, T_STRING); uwsgi_log("%s\n", RSTRING_PTR(msg)); return Qnil; } static VALUE rack_uwsgi_i_am_the_spooler(VALUE class) { if (uwsgi.i_am_a_spooler) { return Qtrue; } return Qfalse; } #ifdef UWSGI_SSL static VALUE rack_uwsgi_i_am_the_lord(VALUE class, VALUE legion_name) { Check_Type(legion_name, T_STRING); if (uwsgi_legion_i_am_the_lord(RSTRING_PTR(legion_name))) { return Qtrue; } return Qfalse; } #endif static VALUE rack_uwsgi_connection_fd(VALUE class) { struct wsgi_request *wsgi_req = current_wsgi_req(); return INT2NUM(wsgi_req->fd); } static VALUE rack_uwsgi_setprocname(VALUE class, VALUE rbname) { Check_Type(rbname, T_STRING); char *name = RSTRING_PTR(rbname); uwsgi_set_processname(name); return Qnil; } static VALUE rack_uwsgi_mem(VALUE class) { uint64_t rss=0, vsz = 0; VALUE ml = rb_ary_new2(2); get_memusage(&rss, &vsz); rb_ary_store(ml, 0, LONG2NUM(rss)); rb_ary_store(ml, 1, LONG2NUM(vsz)); return ml; } static VALUE rack_uwsgi_request_id(VALUE class) { return ULONG2NUM(uwsgi.workers[uwsgi.mywid].requests); } static VALUE rack_uwsgi_worker_id(VALUE class) { return INT2NUM(uwsgi.mywid); } static VALUE rack_uwsgi_mule_id(VALUE class) { return INT2NUM(uwsgi.muleid); } static VALUE rack_uwsgi_logsize(VALUE class) { return ULONG2NUM(uwsgi.shared->logsize); } static VALUE rack_uwsgi_mule_msg(int argc, VALUE *argv, VALUE class) { int fd = -1; int mule_id = -1; if (argc == 0) return Qnil; Check_Type(argv[0], T_STRING); char *message = RSTRING_PTR(argv[0]); size_t message_len = RSTRING_LEN(argv[0]); if (uwsgi.mules_cnt < 1) { rb_raise(rb_eRuntimeError, "no mule configured"); return Qnil; } if (argc == 1) { mule_send_msg(uwsgi.shared->mule_queue_pipe[0], message, message_len); } else { if (TYPE(argv[1]) == T_STRING) { struct uwsgi_farm *uf = get_farm_by_name(RSTRING_PTR(argv[1])); if (uf == NULL) { rb_raise(rb_eRuntimeError, "unknown farm"); return Qnil; } fd = uf->queue_pipe[0]; } else if (TYPE(argv[1]) == T_FIXNUM) { mule_id = NUM2INT(argv[1]); if (mule_id < 0 && mule_id > uwsgi.mules_cnt) { rb_raise(rb_eRuntimeError, "invalid mule number"); return Qnil; } if (mule_id == 0) { fd = uwsgi.shared->mule_queue_pipe[0]; } else { fd = uwsgi.mules[mule_id-1].queue_pipe[0]; } } else { rb_raise(rb_eRuntimeError, "invalid mule"); return Qnil; } if (fd > -1) { mule_send_msg(fd, message, message_len); } } return Qnil; } static int uwsgi_ruby_hash_mule_callback(VALUE key, VALUE val, VALUE arg_array) { Check_Type(key, T_SYMBOL); ID key_id = SYM2ID(key); const char *key_name = rb_id2name(key_id); if (!strcmp(key_name, "signals")) { rb_ary_store(arg_array, 0, val); } else if (!strcmp(key_name, "farms")) { rb_ary_store(arg_array, 1, val); } else if (!strcmp(key_name, "timeout")) { rb_ary_store(arg_array, 2, val); } else if (!strcmp(key_name, "buffer_size")) { rb_ary_store(arg_array, 3, val); } return 0; } static VALUE rack_uwsgi_mule_get_msg(int argc, VALUE *argv, VALUE class) { int manage_signals = 1; int manage_farms = 1; int timeout = -1; size_t buffer_size = 65536; ssize_t len = 0; char *message; if (uwsgi.muleid == 0) { rb_raise(rb_eRuntimeError, "you can receive mule messages only in a mule !!!"); return Qnil; } if (argc > 0) { // 0 = manage_signals // 1 = manage_farms // 2 = timeout // 3 = buffer_size VALUE arg_array = rb_ary_new2(4); Check_Type(argv[0], T_HASH); rb_hash_foreach(argv[0], uwsgi_ruby_hash_mule_callback, arg_array); if (rb_ary_entry(arg_array, 0) == Qfalse) { manage_signals = 0; } if (rb_ary_entry(arg_array, 1) == Qfalse) { manage_farms = 0; } if (TYPE(rb_ary_entry(arg_array,2)) == T_FIXNUM) { timeout = NUM2INT(rb_ary_entry(arg_array,2)); } if (TYPE(rb_ary_entry(arg_array,3)) == T_FIXNUM || TYPE(rb_ary_entry(arg_array,3)) == T_BIGNUM) { buffer_size = NUM2ULONG(rb_ary_entry(arg_array,3)); } } message = uwsgi_malloc(buffer_size); len = uwsgi_mule_get_msg(manage_signals, manage_farms, message, buffer_size, timeout) ; if (len < 0) { free(message); return Qnil; } VALUE msg = rb_str_new(message, len); free(message); return msg; } static VALUE rack_uwsgi_lock(int argc, VALUE *argv, VALUE class) { int lock_num = 0; if (argc > 0) { Check_Type(argv[0], T_FIXNUM); lock_num = NUM2INT(argv[0]); } if (lock_num < 0 || lock_num > uwsgi.locks) { rb_raise(rb_eRuntimeError, "Invalid lock number"); return Qnil; } uwsgi_lock(uwsgi.user_lock[lock_num]); return Qnil; } static VALUE rack_uwsgi_unlock(int argc, VALUE *argv, VALUE class) { int lock_num = 0; if (argc > 0) { Check_Type(argv[0], T_FIXNUM); lock_num = NUM2INT(argv[0]); } if (lock_num < 0 || lock_num > uwsgi.locks) { rb_raise(rb_eRuntimeError, "Invalid lock number"); return Qnil; } uwsgi_unlock(uwsgi.user_lock[lock_num]); return Qnil; } static VALUE rack_uwsgi_cache_set(int argc, VALUE *argv, VALUE class) { if (argc < 2) goto error; Check_Type(argv[0], T_STRING); Check_Type(argv[1], T_STRING); char *key = RSTRING_PTR(argv[0]); uint16_t keylen = RSTRING_LEN(argv[0]); char *value = RSTRING_PTR(argv[1]); uint64_t vallen = RSTRING_LEN(argv[1]); uint64_t expires = 0; char *cache = NULL; if (argc > 2) { Check_Type(argv[2], T_FIXNUM); expires = NUM2INT(argv[2]); if (argc > 3) { Check_Type(argv[3], T_STRING); cache = RSTRING_PTR(argv[3]); } } if (uwsgi_cache_magic_set(key, keylen, value, vallen, expires, 0, cache)) { return Qnil; } return Qtrue; error: rb_raise(rb_eArgError, "you need to specify a cache key and a cache value"); return Qnil; } static VALUE rack_uwsgi_cache_update(int argc, VALUE *argv, VALUE class) { if (argc < 2) goto error; Check_Type(argv[0], T_STRING); Check_Type(argv[1], T_STRING); char *key = RSTRING_PTR(argv[0]); uint16_t keylen = RSTRING_LEN(argv[0]); char *value = RSTRING_PTR(argv[1]); uint64_t vallen = RSTRING_LEN(argv[1]); uint64_t expires = 0; char *cache = NULL; if (argc > 2) { Check_Type(argv[2], T_FIXNUM); expires = NUM2INT(argv[2]); if (argc > 3) { Check_Type(argv[3], T_STRING); cache = RSTRING_PTR(argv[3]); } } if (uwsgi_cache_magic_set(key, keylen, value, vallen, expires, UWSGI_CACHE_FLAG_UPDATE, cache)) { return Qnil; } return Qtrue; error: rb_raise(rb_eArgError, "you need to specify a cache key and a cache value"); return Qnil; } static VALUE rack_uwsgi_cache_set_exc(int argc, VALUE *argv, VALUE class) { VALUE ret = rack_uwsgi_cache_set(argc, argv, class); if (ret == Qnil) { rb_raise(rb_eRuntimeError, "unable to set value in uWSGI cache"); } return ret; } static VALUE rack_uwsgi_cache_update_exc(int argc, VALUE *argv, VALUE class) { VALUE ret = rack_uwsgi_cache_update(argc, argv, class); if (ret == Qnil) { rb_raise(rb_eRuntimeError, "unable to update value in uWSGI cache"); } return ret; } static VALUE rack_uwsgi_cache_del(int argc, VALUE *argv, VALUE class) { if (argc == 0) goto error; Check_Type(argv[0], T_STRING); char *key = RSTRING_PTR(argv[0]); uint16_t keylen = RSTRING_LEN(argv[0]); char *cache = NULL; if (argc > 1) { Check_Type(argv[0], T_STRING); cache = RSTRING_PTR(argv[0]); } if (!uwsgi_cache_magic_del(key, keylen, cache)) { return Qtrue; } return Qnil; error: rb_raise(rb_eArgError, "you need to specify a cache key"); return Qnil; } static VALUE rack_uwsgi_cache_del_exc(int argc, VALUE *argv, VALUE class) { VALUE ret = rack_uwsgi_cache_del(argc, argv, class); if (ret == Qnil) { rb_raise(rb_eRuntimeError, "unable to delete object from uWSGI cache"); } return ret; } static VALUE rack_uwsgi_cache_exists(int argc, VALUE *argv, VALUE class) { if (argc == 0) goto error; Check_Type(argv[0], T_STRING); char *key = RSTRING_PTR(argv[0]); uint16_t keylen = RSTRING_LEN(argv[0]); char *cache = NULL; if (argc > 1) { Check_Type(argv[0], T_STRING); cache = RSTRING_PTR(argv[0]); } if (uwsgi_cache_magic_exists(key, keylen, cache)) { return Qtrue; } return Qnil; error: rb_raise(rb_eArgError, "you need to specify a cache key"); return Qnil; } static VALUE rack_uwsgi_cache_clear(int argc, VALUE *argv, VALUE class) { char *cache = NULL; if (argc > 0) { Check_Type(argv[0], T_STRING); cache = RSTRING_PTR(argv[0]); } if (!uwsgi_cache_magic_clear(cache)) { return Qtrue; } return Qnil; } static VALUE rack_uwsgi_cache_clear_exc(int argc, VALUE *argv, VALUE class) { VALUE ret = rack_uwsgi_cache_clear(argc, argv, class); if (ret == Qnil) { rb_raise(rb_eRuntimeError, "unable to clear the uWSGI cache"); } return ret; } static VALUE rack_uwsgi_cache_get(int argc, VALUE *argv, VALUE class) { if (argc == 0) goto error; Check_Type(argv[0], T_STRING); char *key = RSTRING_PTR(argv[0]); uint16_t keylen = RSTRING_LEN(argv[0]); char *cache = NULL; if (argc > 1) { Check_Type(argv[1], T_STRING); cache = RSTRING_PTR(argv[1]); } uint64_t vallen = 0;; char *value = uwsgi_cache_magic_get(key, keylen, &vallen, NULL, cache); if (value) { VALUE res = rb_str_new(value, vallen); free(value); return res; } return Qnil; error: rb_raise(rb_eArgError, "you need to specify a cache key"); return Qnil; } static VALUE rack_uwsgi_cache_get_exc(int argc, VALUE *argv, VALUE class) { VALUE ret = rack_uwsgi_cache_get(argc, argv, class); if (ret == Qnil) { rb_raise(rb_eRuntimeError, "unable to get value from uWSGI cache"); } return ret; } static VALUE rack_uwsgi_add_cron(VALUE class, VALUE rbsignum, VALUE rbmin, VALUE rbhour, VALUE rbday, VALUE rbmon, VALUE rbweek) { Check_Type(rbsignum, T_FIXNUM); Check_Type(rbmin, T_FIXNUM); Check_Type(rbhour, T_FIXNUM); Check_Type(rbday, T_FIXNUM); Check_Type(rbmon, T_FIXNUM); Check_Type(rbweek, T_FIXNUM); uint8_t uwsgi_signal = NUM2INT(rbsignum); int minute = NUM2INT(rbmin); int hour = NUM2INT(rbhour); int day = NUM2INT(rbday); int month = NUM2INT(rbmon); int week = NUM2INT(rbweek); if (uwsgi_signal_add_cron(uwsgi_signal, minute, hour, day, month, week)) { rb_raise(rb_eRuntimeError, "unable to add cron"); return Qnil; } return Qtrue; } static VALUE rack_uwsgi_add_timer(VALUE class, VALUE rbsignum, VALUE secs) { Check_Type(rbsignum, T_FIXNUM); Check_Type(secs, T_FIXNUM); uint8_t uwsgi_signal = NUM2INT(rbsignum); int seconds = NUM2INT(secs); if (uwsgi_add_timer(uwsgi_signal, seconds)) { rb_raise(rb_eRuntimeError, "unable to add timer"); return Qnil; } return Qtrue; } static VALUE rack_uwsgi_add_rb_timer(VALUE class, VALUE rbsignum, VALUE secs) { Check_Type(rbsignum, T_FIXNUM); Check_Type(secs, T_FIXNUM); uint8_t uwsgi_signal = NUM2INT(rbsignum); int seconds = NUM2INT(secs); if (uwsgi_signal_add_rb_timer(uwsgi_signal, seconds, 0)) { rb_raise(rb_eRuntimeError, "unable to add rb_timer"); return Qnil; } return Qtrue; } static VALUE rack_uwsgi_alarm(VALUE class, VALUE alarm, VALUE msg) { Check_Type(alarm, T_STRING); Check_Type(msg, T_STRING); uwsgi_alarm_trigger(RSTRING_PTR(alarm), RSTRING_PTR(msg), RSTRING_LEN(msg)); return Qnil; } static VALUE rack_uwsgi_add_file_monitor(VALUE class, VALUE rbsignum, VALUE rbfilename) { Check_Type(rbsignum, T_FIXNUM); Check_Type(rbfilename, T_STRING); uint8_t uwsgi_signal = NUM2INT(rbsignum); char *filename = RSTRING_PTR(rbfilename); if (uwsgi_add_file_monitor(uwsgi_signal, filename)) { rb_raise(rb_eRuntimeError, "unable to add file monitor"); return Qnil; } return Qtrue; } static VALUE uwsgi_ruby_wait_fd_read(VALUE class, VALUE arg1, VALUE arg2) { Check_Type(arg1, T_FIXNUM); Check_Type(arg2, T_FIXNUM); struct wsgi_request *wsgi_req = current_wsgi_req(); int fd = NUM2INT(arg1); int timeout = NUM2INT(arg2); if (async_add_fd_read(wsgi_req, fd, timeout)) { rb_raise(rb_eRuntimeError, "unable to add fd %d to the event queue", fd); } return Qtrue; } static VALUE uwsgi_ruby_wait_fd_write(VALUE class, VALUE arg1, VALUE arg2) { Check_Type(arg1, T_FIXNUM); Check_Type(arg2, T_FIXNUM); struct wsgi_request *wsgi_req = current_wsgi_req(); int fd = NUM2INT(arg1); int timeout = NUM2INT(arg2); if (async_add_fd_write(wsgi_req, fd, timeout)) { rb_raise(rb_eRuntimeError, "unable to add fd %d to the event queue", fd); } return Qtrue; } static VALUE uwsgi_ruby_async_connect(VALUE class, VALUE arg) { Check_Type(arg, T_STRING); int fd = uwsgi_connect(RSTRING_PTR(arg), 0, 1); return INT2FIX(fd); } static VALUE uwsgi_ruby_async_sleep(VALUE class, VALUE arg) { Check_Type(arg, T_FIXNUM); struct wsgi_request *wsgi_req = current_wsgi_req(); int timeout = NUM2INT(arg); if (timeout >= 0) { async_add_timeout(wsgi_req, timeout); } return Qtrue; } static VALUE uwsgi_ruby_masterpid(VALUE class) { if (uwsgi.master_process) { return INT2NUM(uwsgi.workers[0].pid); } return INT2NUM(0); } static VALUE uwsgi_ruby_suspend(VALUE class) { struct wsgi_request *wsgi_req = current_wsgi_req(); uwsgi.schedule_to_main(wsgi_req); return Qtrue; } static VALUE uwsgi_ruby_signal_wait(int argc, VALUE *argv, VALUE class) { struct wsgi_request *wsgi_req = current_wsgi_req(); int wait_for_specific_signal = 0; uint8_t uwsgi_signal = 0; int received_signal; wsgi_req->signal_received = -1; if (argc > 0) { Check_Type(argv[0], T_FIXNUM); uwsgi_signal = NUM2INT(argv[0]); wait_for_specific_signal = 1; } if (wait_for_specific_signal) { received_signal = uwsgi_signal_wait(uwsgi_signal); } else { received_signal = uwsgi_signal_wait(-1); } if (received_signal < 0) { rb_raise(rb_eRuntimeError, "unable to call rpc function"); } else { wsgi_req->signal_received = received_signal; } return Qnil; } static VALUE uwsgi_ruby_signal_received(VALUE class) { struct wsgi_request *wsgi_req = current_wsgi_req(); return INT2NUM(wsgi_req->signal_received); } static VALUE uwsgi_ruby_signal_registered(VALUE class, VALUE signum) { Check_Type(signum, T_FIXNUM); uint8_t uwsgi_signal = NUM2INT(signum); if (uwsgi_signal_registered(uwsgi_signal)) { return Qtrue; } return Qfalse; } static VALUE uwsgi_ruby_do_rpc(int argc, VALUE *rpc_argv, VALUE class) { char *node = NULL, *func; uint64_t size = 0; char *argv[256]; uint16_t argvs[256]; int i; // TODO better error reporting if (argc < 2) goto clear; VALUE rpc_node = rpc_argv[0]; if (TYPE(rpc_node) == T_STRING) { node = RSTRING_PTR(rpc_node); } VALUE rpc_func = rpc_argv[1]; if (TYPE(rpc_func) != T_STRING) goto clear; func = RSTRING_PTR(rpc_func); for (i = 0; i < (argc - 2); i++) { VALUE rpc_str = rpc_argv[i + 2]; if (TYPE(rpc_str) != T_STRING) goto clear; argv[i] = RSTRING_PTR(rpc_str); argvs[i] = RSTRING_LEN(rpc_str); } // response must always be freed char *response = uwsgi_do_rpc(node, func, argc - 2, argv, argvs, &size); if (response) { VALUE ret = rb_str_new(response, size); free(response); return ret; } clear: rb_raise(rb_eRuntimeError, "unable to call rpc function"); return Qnil; } static VALUE uwsgi_ruby_register_rpc(int argc, VALUE *argv, VALUE class) { int rb_argc = 0; if (argc < 2) goto clear; if (argc > 2) { Check_Type(argv[2], T_FIXNUM); rb_argc = NUM2INT(argv[2]); } Check_Type(argv[0], T_STRING); char *name = RSTRING_PTR(argv[0]); void *func = (void *) argv[1]; if (uwsgi_register_rpc(name, &rack_plugin, rb_argc, func)) { clear: rb_raise(rb_eRuntimeError, "unable to register rpc function"); return Qnil; } rb_gc_register_address(&argv[1]); rb_ary_push(ur.rpc_protector, argv[1]); return Qtrue; } static VALUE uwsgi_ruby_register_signal(VALUE class, VALUE signum, VALUE sigkind, VALUE rbhandler) { Check_Type(signum, T_FIXNUM); Check_Type(sigkind, T_STRING); uint8_t uwsgi_signal = NUM2INT(signum); char *signal_kind = RSTRING_PTR(sigkind); if (uwsgi_register_signal(uwsgi_signal, signal_kind, (void *) rbhandler, rack_plugin.modifier1)) { rb_raise(rb_eRuntimeError, "unable to register signal %d", uwsgi_signal); return Qnil; } rb_gc_register_address(&rbhandler); rb_ary_push(ur.signals_protector, rbhandler); return Qtrue; } static VALUE uwsgi_ruby_signal(int argc, VALUE *argv, VALUE class) { if (argc < 1) { rb_raise(rb_eRuntimeError, "you have to specify a signum"); return Qnil; } Check_Type(argv[0], T_FIXNUM); uint8_t uwsgi_signal = NUM2INT(argv[0]); if (argc > 1) { Check_Type(argv[1], T_STRING); char *remote = RSTRING_PTR(argv[1]); int ret = uwsgi_remote_signal_send(remote, uwsgi_signal); if (ret == 1) return Qtrue; if (ret == -1) { rb_raise(rb_eRuntimeError, "unable to deliver signal %d to node %s", uwsgi_signal, remote); return Qnil; } if (ret == 0) { rb_raise(rb_eRuntimeError, "node %s rejected signal %d", remote, uwsgi_signal); return Qnil; } } else { uwsgi_signal_send(uwsgi.signal_socket, uwsgi_signal); } return Qtrue; } static int rack_uwsgi_build_spool(VALUE rbkey, VALUE rbval, VALUE argv) { struct uwsgi_buffer *ub = (struct uwsgi_buffer *) argv; if (TYPE(rbkey) != T_STRING) { rb_raise(rb_eRuntimeError, "spool hash must contains only strings"); return ST_STOP; } char *key = RSTRING_PTR(rbkey); uint16_t keylen = RSTRING_LEN(rbkey); if (TYPE(rbval) == T_STRING) { char *val = RSTRING_PTR(rbval); uint16_t vallen = RSTRING_LEN(rbval); if (uwsgi_buffer_append_keyval(ub, key, keylen, val, vallen)) { rb_raise(rb_eRuntimeError, "error building the spool packet"); return ST_STOP; } } else { //VALUE str = rb_any_to_s(rbval); VALUE str = rb_funcall( rbval, rb_intern("to_s"), 0); if (!str) { rb_raise(rb_eRuntimeError, "error building the spool packet"); return ST_STOP; } char *val = RSTRING_PTR(str); uint16_t vallen = RSTRING_LEN(str); if (uwsgi_buffer_append_keyval(ub, key, keylen, val, vallen)) { rb_raise(rb_eRuntimeError, "error building the spool packet"); return ST_STOP; } } return ST_CONTINUE; } static VALUE rack_uwsgi_send_spool(VALUE class, VALUE args) { char *body = NULL; size_t body_len= 0; Check_Type(args, T_HASH); // body #ifdef RUBY19 VALUE rbbody = rb_hash_lookup(args, rb_str_new2("body")); #else VALUE rbbody = rb_hash_aref(args, rb_str_new2("body")); #endif if (TYPE(rbbody) == T_STRING) { body = RSTRING_PTR(rbbody); body_len = RSTRING_LEN(rbbody); rb_hash_delete(args, rb_str_new2("body")); } struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); rb_hash_foreach(args, rack_uwsgi_build_spool, (VALUE) ub); char *filename = uwsgi_spool_request(NULL, ub->buf, ub->pos, body, body_len); uwsgi_buffer_destroy(ub); if (filename) { VALUE ret = rb_str_new2(filename); free(filename); return ret; } rb_raise(rb_eRuntimeError, "unable to spool job"); return Qnil; } static VALUE uwsgi_ruby_websocket_handshake(int argc, VALUE *argv, VALUE class) { struct wsgi_request *wsgi_req = current_wsgi_req(); char *key = NULL, *origin = NULL, *proto = NULL; size_t key_len = 0, origin_len = 0, proto_len = 0; if (argc > 0) { Check_Type(argv[0], T_STRING); key = RSTRING_PTR(argv[0]); key_len = RSTRING_LEN(argv[0]); if (argc > 1) { Check_Type(argv[1], T_STRING); origin = RSTRING_PTR(argv[1]); origin_len = RSTRING_LEN(argv[1]); if (argc > 2) { Check_Type(argv[2], T_STRING); proto = RSTRING_PTR(argv[2]); proto_len = RSTRING_LEN(argv[2]); } } } if (uwsgi_websocket_handshake(wsgi_req, key, key_len, origin, origin_len, proto, proto_len)) { rb_raise(rb_eRuntimeError, "unable to complete websocket handshake"); } return Qnil; } static VALUE uwsgi_ruby_websocket_send(VALUE class, VALUE msg) { Check_Type(msg, T_STRING); char *message = RSTRING_PTR(msg); size_t message_len = RSTRING_LEN(msg); struct wsgi_request *wsgi_req = current_wsgi_req(); if (uwsgi_websocket_send(wsgi_req, message, message_len)) { rb_raise(rb_eRuntimeError, "unable to send websocket message"); } return Qnil; } static VALUE uwsgi_ruby_websocket_recv(VALUE class) { struct wsgi_request *wsgi_req = current_wsgi_req(); struct uwsgi_buffer *ub = uwsgi_websocket_recv(wsgi_req); if (!ub) { rb_raise(rb_eRuntimeError, "unable to receive websocket message"); return Qnil; } VALUE ret = rb_str_new(ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return ret; } static VALUE uwsgi_ruby_websocket_recv_nb(VALUE class) { struct wsgi_request *wsgi_req = current_wsgi_req(); struct uwsgi_buffer *ub = uwsgi_websocket_recv_nb(wsgi_req); if (!ub) { rb_raise(rb_eRuntimeError, "unable to receive websocket message"); return Qnil; } VALUE ret = rb_str_new(ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return ret; } void uwsgi_rack_init_api() { VALUE rb_uwsgi_embedded = rb_define_module("UWSGI"); uwsgi_rack_api("suspend", uwsgi_ruby_suspend, 0); uwsgi_rack_api("masterpid", uwsgi_ruby_masterpid, 0); uwsgi_rack_api("async_sleep", uwsgi_ruby_async_sleep, 1); uwsgi_rack_api("wait_fd_read", uwsgi_ruby_wait_fd_read, 2); uwsgi_rack_api("wait_fd_write", uwsgi_ruby_wait_fd_write, 2); uwsgi_rack_api("async_connect", uwsgi_ruby_async_connect, 1); uwsgi_rack_api("signal", uwsgi_ruby_signal, -1); uwsgi_rack_api("register_signal", uwsgi_ruby_register_signal, 3); uwsgi_rack_api("register_rpc", uwsgi_ruby_register_rpc, -1); uwsgi_rack_api("signal_registered", uwsgi_ruby_signal_registered, 1); uwsgi_rack_api("signal_wait", uwsgi_ruby_signal_wait, -1); uwsgi_rack_api("signal_received", uwsgi_ruby_signal_received, 0); uwsgi_rack_api("add_cron", rack_uwsgi_add_cron, 6); uwsgi_rack_api("add_timer", rack_uwsgi_add_timer, 2); uwsgi_rack_api("add_rb_timer", rack_uwsgi_add_rb_timer, 2); uwsgi_rack_api("add_file_monitor", rack_uwsgi_add_file_monitor, 2); uwsgi_rack_api("alarm", rack_uwsgi_alarm, 2); uwsgi_rack_api("websocket_handshake", uwsgi_ruby_websocket_handshake, -1); uwsgi_rack_api("websocket_send", uwsgi_ruby_websocket_send, 1); uwsgi_rack_api("websocket_recv", uwsgi_ruby_websocket_recv, 0); uwsgi_rack_api("websocket_recv_nb", uwsgi_ruby_websocket_recv_nb, 0); uwsgi_rack_api("setprocname", rack_uwsgi_setprocname, 1); uwsgi_rack_api("mem", rack_uwsgi_mem, 0); uwsgi_rack_api("lock", rack_uwsgi_lock, -1); uwsgi_rack_api("unlock", rack_uwsgi_unlock, -1); uwsgi_rack_api("mule_get_msg", rack_uwsgi_mule_get_msg, -1); uwsgi_rack_api("mule_msg", rack_uwsgi_mule_msg, -1); uwsgi_rack_api("request_id", rack_uwsgi_request_id, 0); uwsgi_rack_api("worker_id", rack_uwsgi_worker_id, 0); uwsgi_rack_api("mule_id", rack_uwsgi_mule_id, 0); uwsgi_rack_api("i_am_the_spooler", rack_uwsgi_i_am_the_spooler, 0); uwsgi_rack_api("send_to_spooler", rack_uwsgi_send_spool, 1); uwsgi_rack_api("spool", rack_uwsgi_send_spool, 1); uwsgi_rack_api("log", rack_uwsgi_log, 1); uwsgi_rack_api("logsize", rack_uwsgi_logsize, 0); uwsgi_rack_api("set_warning_message", rack_uwsgi_warning, 1); uwsgi_rack_api("set_user_harakiri", rack_uwsgi_user_harakiri, 1); uwsgi_rack_api("rpc", uwsgi_ruby_do_rpc, -1); #ifdef UWSGI_SSL uwsgi_rack_api("i_am_the_lord", rack_uwsgi_i_am_the_lord, 1); #endif uwsgi_rack_api("connection_fd", rack_uwsgi_connection_fd, 0); uwsgi_rack_api("cache_get", rack_uwsgi_cache_get, -1); uwsgi_rack_api("cache_get!", rack_uwsgi_cache_get_exc, -1); uwsgi_rack_api("cache_exists", rack_uwsgi_cache_exists, -1); uwsgi_rack_api("cache_exists?", rack_uwsgi_cache_exists, -1); uwsgi_rack_api("cache_del", rack_uwsgi_cache_del, -1); uwsgi_rack_api("cache_del!", rack_uwsgi_cache_del_exc, -1); uwsgi_rack_api("cache_set", rack_uwsgi_cache_set, -1); uwsgi_rack_api("cache_set!", rack_uwsgi_cache_set_exc, -1); uwsgi_rack_api("cache_update", rack_uwsgi_cache_update, -1); uwsgi_rack_api("cache_update!", rack_uwsgi_cache_update_exc, -1); uwsgi_rack_api("cache_clear", rack_uwsgi_cache_clear, -1); uwsgi_rack_api("cache_clear!", rack_uwsgi_cache_clear_exc, -1); uwsgi_rack_api("metric_get", rack_uwsgi_metric_get, 1); uwsgi_rack_api("metric_set", rack_uwsgi_metric_set, 2); uwsgi_rack_api("metric_inc", rack_uwsgi_metric_inc, -1); uwsgi_rack_api("metric_dec", rack_uwsgi_metric_dec, -1); uwsgi_rack_api("metric_mul", rack_uwsgi_metric_mul, -1); uwsgi_rack_api("metric_div", rack_uwsgi_metric_div, -1); VALUE uwsgi_rb_opt_hash = rb_hash_new(); int i; for (i = 0; i < uwsgi.exported_opts_cnt; i++) { VALUE rb_uwsgi_opt_key = rb_str_new2(uwsgi.exported_opts[i]->key); if ( rb_funcall(uwsgi_rb_opt_hash, rb_intern("has_key?"), 1, rb_uwsgi_opt_key) == Qtrue) { VALUE rb_uwsgi_opt_item = rb_hash_aref(uwsgi_rb_opt_hash, rb_uwsgi_opt_key); if (TYPE(rb_uwsgi_opt_item) == T_ARRAY) { if (uwsgi.exported_opts[i]->value == NULL) { rb_ary_push(rb_uwsgi_opt_item, Qtrue); } else { rb_ary_push(rb_uwsgi_opt_item, rb_str_new2(uwsgi.exported_opts[i]->value)); } } else { VALUE rb_uwsgi_opt_list = rb_ary_new(); rb_ary_push(rb_uwsgi_opt_list, rb_uwsgi_opt_item); if (uwsgi.exported_opts[i]->value == NULL) { rb_ary_push(rb_uwsgi_opt_list, Qtrue); } else { rb_ary_push(rb_uwsgi_opt_list, rb_str_new2(uwsgi.exported_opts[i]->value)); } rb_hash_aset(uwsgi_rb_opt_hash, rb_uwsgi_opt_key, rb_uwsgi_opt_list); } } else { if (uwsgi.exported_opts[i]->value == NULL) { rb_hash_aset(uwsgi_rb_opt_hash, rb_uwsgi_opt_key, Qtrue); } else { rb_hash_aset(uwsgi_rb_opt_hash, rb_uwsgi_opt_key, rb_str_new2(uwsgi.exported_opts[i]->value)); } } } rb_const_set(rb_uwsgi_embedded, rb_intern("OPT"), uwsgi_rb_opt_hash); rb_const_set(rb_uwsgi_embedded, rb_intern("SPOOL_OK"), INT2NUM(-2)); rb_const_set(rb_uwsgi_embedded, rb_intern("SPOOL_IGNORE"), INT2NUM(0)); rb_const_set(rb_uwsgi_embedded, rb_intern("SPOOL_RETRY"), INT2NUM(-1)); rb_const_set(rb_uwsgi_embedded, rb_intern("VERSION"), rb_str_new2(UWSGI_VERSION)); rb_const_set(rb_uwsgi_embedded, rb_intern("HOSTNAME"), rb_str_new(uwsgi.hostname, uwsgi.hostname_len)); if (uwsgi.pidfile) { rb_const_set(rb_uwsgi_embedded, rb_intern("PIDFILE"), rb_str_new2(uwsgi.pidfile)); } rb_const_set(rb_uwsgi_embedded, rb_intern("NUMPROC"), INT2NUM(uwsgi.numproc)); } uwsgi-2.0.29/plugins/rack/rack_plugin.c000066400000000000000000001111551477626554400200350ustar00rootroot00000000000000#include "uwsgi_rack.h" extern struct uwsgi_server uwsgi; struct uwsgi_rack ur; struct uwsgi_plugin rack_plugin; static void uwsgi_opt_rbshell(char *opt, char *value, void *foobar) { uwsgi.honour_stdin = 1; if (value) { ur.rbshell = value; } else { ur.rbshell = ""; } if (!strcmp("rbshell-oneshot", opt)) { ur.rb_shell_oneshot = 1; } } struct uwsgi_option uwsgi_rack_options[] = { {"rails", required_argument, 0, "load a rails <= 2.x app", uwsgi_opt_set_str, &ur.rails, UWSGI_OPT_POST_BUFFERING}, {"rack", required_argument, 0, "load a rack app", uwsgi_opt_set_str, &ur.rack, UWSGI_OPT_POST_BUFFERING}, {"ruby-gc-freq", required_argument, 0, "set ruby GC frequency", uwsgi_opt_set_int, &ur.gc_freq, 0}, {"rb-gc-freq", required_argument, 0, "set ruby GC frequency", uwsgi_opt_set_int, &ur.gc_freq, 0}, #ifdef RUBY19 {"rb-lib", required_argument, 0, "add a directory to the ruby libdir search path", uwsgi_opt_add_string_list, &ur.libdir, 0}, {"ruby-lib", required_argument, 0, "add a directory to the ruby libdir search path", uwsgi_opt_add_string_list, &ur.libdir, 0}, #endif {"rb-require", required_argument, 0, "import/require a ruby module/script", uwsgi_opt_add_string_list, &ur.rbrequire, 0}, {"ruby-require", required_argument, 0, "import/require a ruby module/script", uwsgi_opt_add_string_list, &ur.rbrequire, 0}, {"rbrequire", required_argument, 0, "import/require a ruby module/script", uwsgi_opt_add_string_list, &ur.rbrequire, 0}, {"rubyrequire", required_argument, 0, "import/require a ruby module/script", uwsgi_opt_add_string_list, &ur.rbrequire, 0}, {"require", required_argument, 0, "import/require a ruby module/script", uwsgi_opt_add_string_list, &ur.rbrequire, 0}, {"shared-rb-require", required_argument, 0, "import/require a ruby module/script (shared)", uwsgi_opt_add_string_list, &ur.shared_rbrequire, 0}, {"shared-ruby-require", required_argument, 0, "import/require a ruby module/script (shared)", uwsgi_opt_add_string_list, &ur.shared_rbrequire, 0}, {"shared-rbrequire", required_argument, 0, "import/require a ruby module/script (shared)", uwsgi_opt_add_string_list, &ur.shared_rbrequire, 0}, {"shared-rubyrequire", required_argument, 0, "import/require a ruby module/script (shared)", uwsgi_opt_add_string_list, &ur.shared_rbrequire, 0}, {"shared-require", required_argument, 0, "import/require a ruby module/script (shared)", uwsgi_opt_add_string_list, &ur.shared_rbrequire, 0}, {"gemset", required_argument, 0, "load the specified gemset (rvm)", uwsgi_opt_set_str, &ur.gemset, 0}, {"rvm", required_argument, 0, "load the specified gemset (rvm)", uwsgi_opt_set_str, &ur.gemset, 0}, {"rvm-path", required_argument, 0, "search for rvm in the specified directory", uwsgi_opt_add_string_list, &ur.rvm_path, 0}, {"rbshell", optional_argument, 0, "run a ruby/irb shell", uwsgi_opt_rbshell, NULL, 0}, {"rbshell-oneshot", no_argument, 0, "set ruby/irb shell (one shot)", uwsgi_opt_rbshell, NULL, 0}, {0, 0, 0, 0, 0, 0 ,0}, }; static struct uwsgi_buffer *uwsgi_ruby_exception_class(struct wsgi_request *wsgi_req) { VALUE err = rb_errinfo(); VALUE e = rb_class_name(rb_class_of(err)); struct uwsgi_buffer *ub = uwsgi_buffer_new(RSTRING_LEN(e)); if (uwsgi_buffer_append(ub, RSTRING_PTR(e), RSTRING_LEN(e))) { uwsgi_buffer_destroy(ub); return NULL; } return ub; } static struct uwsgi_buffer *uwsgi_ruby_exception_msg(struct wsgi_request *wsgi_req) { VALUE err = rb_errinfo(); VALUE e = rb_funcall(err, rb_intern("message"), 0, 0); struct uwsgi_buffer *ub = uwsgi_buffer_new(RSTRING_LEN(e)); if (uwsgi_buffer_append(ub, RSTRING_PTR(e), RSTRING_LEN(e))) { uwsgi_buffer_destroy(ub); return NULL; } return ub; } static struct uwsgi_buffer *uwsgi_ruby_exception_repr(struct wsgi_request *wsgi_req) { struct uwsgi_buffer *ub_class = uwsgi_ruby_exception_class(wsgi_req); if (!ub_class) return NULL; struct uwsgi_buffer *ub_msg = uwsgi_ruby_exception_msg(wsgi_req); if (!ub_msg) { uwsgi_buffer_destroy(ub_class); return NULL; } struct uwsgi_buffer *ub = uwsgi_buffer_new(ub_class->pos + 3 + ub_msg->pos); if (uwsgi_buffer_append(ub, ub_msg->buf, ub_msg->pos)) goto error; if (uwsgi_buffer_append(ub, " (", 2)) goto error; if (uwsgi_buffer_append(ub, ub_class->buf, ub_class->pos)) goto error; if (uwsgi_buffer_append(ub, ")", 1)) goto error; uwsgi_buffer_destroy(ub_class); uwsgi_buffer_destroy(ub_msg); return ub; error: uwsgi_buffer_destroy(ub_class); uwsgi_buffer_destroy(ub_msg); uwsgi_buffer_destroy(ub); return NULL; } // simulate ruby_error_print (this is sad... but it works well) static void uwsgi_ruby_exception_log(struct wsgi_request *wsgi_req) { VALUE err = rb_errinfo(); VALUE eclass = rb_class_name(rb_class_of(err)); VALUE msg = rb_funcall(err, rb_intern("message"), 0, 0); VALUE ary = rb_funcall(err, rb_intern("backtrace"), 0); int i; for (i=0; i 0) { if (RARRAY_PTR(args)[0] != Qnil) { hint = NUM2LONG(RARRAY_PTR(args)[0]); length_given = 1; } } ssize_t rlen = 0; char *buf = uwsgi_request_body_read(wsgi_req, hint, &rlen); if (buf) { if (length_given && buf == uwsgi.empty) { return Qnil; } if (RARRAY_LEN(args) > 1) { rb_str_cat(RARRAY_PTR(args)[1], buf, rlen); } return rb_str_new(buf, rlen); } return Qnil; } VALUE rb_uwsgi_io_rewind(VALUE obj) { struct wsgi_request *wsgi_req; Data_Get_Struct(obj, struct wsgi_request, wsgi_req); uwsgi_request_body_seek(wsgi_req, 0); return Qnil; } #ifdef RUBY19 #ifdef RUBY_GLOBAL_SETUP RUBY_GLOBAL_SETUP #endif #endif VALUE uwsgi_require_file(VALUE arg) { return rb_funcall(rb_cObject, rb_intern("require"), 1, arg); } VALUE require_rack(VALUE arg) { return rb_funcall(rb_cObject, rb_intern("require"), 1, rb_str_new2("rack")); } VALUE require_rails(VALUE arg) { #ifdef RUBY19 return rb_require("./config/environment"); #else return rb_require("config/environment"); #endif } VALUE require_thin(VALUE arg) { return rb_funcall(rb_cObject, rb_intern("require"), 1, rb_str_new2("thin")); } VALUE init_rack_app(VALUE); VALUE rack_call_rpc_handler(VALUE args) { VALUE rpc_args = rb_ary_entry(args, 1); return rb_funcall2(rb_ary_entry(args, 0), rb_intern("call"), (int) RARRAY_LEN(rpc_args), RARRAY_PTR(rpc_args)); } uint64_t uwsgi_ruby_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char **buffer) { uint8_t i; VALUE rb_args = rb_ary_new2(2); VALUE rb_rpc_args = rb_ary_new2(argc); VALUE ret; int error = 0; char *rv; size_t rl; rb_ary_store(rb_args, 0, (VALUE) func); for (i = 0; i < argc; i++) { rb_ary_store(rb_rpc_args, i, rb_str_new(argv[i], argvs[i])); } rb_ary_store(rb_args, 1, rb_rpc_args); ret = rb_protect(rack_call_rpc_handler, rb_args, &error); if (error) { uwsgi_ruby_exception_log(NULL); return 0; } if (TYPE(ret) == T_STRING) { rv = RSTRING_PTR(ret); rl = RSTRING_LEN(ret); if (rl > 0) { *buffer = uwsgi_malloc(rl); memcpy(*buffer, rv, rl); return rl; } } return 0; } void uwsgi_ruby_gem_set_apply(char *gemset) { int in_pipe[2]; int out_pipe[2]; size_t size; int waitpid_status; size_t i; if (pipe(in_pipe)) { uwsgi_error("pipe()"); exit(1); } if (pipe(out_pipe)) { uwsgi_error("pipe()"); exit(1); } pid_t pid = uwsgi_run_command("bash", in_pipe, out_pipe[1] ); char *gemset_code = uwsgi_open_and_read(gemset, &size, 0, NULL); if (write(in_pipe[1], gemset_code, size) != (ssize_t) size ) { uwsgi_error("write()"); } free(gemset_code); if (write(in_pipe[1], "printenv\n", 9) != 9 ) { uwsgi_error("write()"); } close(in_pipe[1]); size = 0; char *buffer = uwsgi_read_fd(out_pipe[0], &size, 0); close(out_pipe[0]); char *ptr = buffer; for(i=0;ivalue, "/environments/", gemset); if (uwsgi_file_exists(filename)) { uwsgi_ruby_gem_set_apply(filename); free(filename); return; } free(filename); rvm_paths = rvm_paths->next; } char *home = getenv("HOME"); if (home) { char *filename = uwsgi_concat3(home, "/.rvm/environments/", gemset); if (uwsgi_file_exists(filename)) { uwsgi_ruby_gem_set_apply(filename); free(filename); return; } free(filename); } char *filename = uwsgi_concat2("/usr/local/rvm/environments/", gemset); if (uwsgi_file_exists(filename)) { uwsgi_ruby_gem_set_apply(filename); free(filename); return; } free(filename); uwsgi_log("ERROR: unable to load gemset %s !!!\n", gemset); exit(1); } static void rack_hack_dollar_zero(VALUE name, ID id, VALUE *_) { ur.dollar_zero = rb_obj_as_string(name); // From ruby 2.7 onwards this is a noop, from ruby 3.2 onwards // this function no longer exists #if !defined(RUBY27) rb_obj_taint(ur.dollar_zero); #endif } #ifndef RUBY19 void Init_stack(VALUE*); #endif int uwsgi_rack_init(){ #ifdef RUBY19 int argc = 2; char *sargv[] = { (char *) "uwsgi", (char *) "-e0" }; char **argv = sargv; #endif if (ur.gemset) { uwsgi_ruby_gemset(ur.gemset); } #ifdef RUBY19 ruby_sysinit(&argc, &argv); RUBY_INIT_STACK #ifdef UWSGI_RUBY_HEROKU uwsgi_log("*** Heroku system detected ***\n"); #endif #ifdef RUBY_EXEC_PREFIX if (!strcmp(RUBY_EXEC_PREFIX, "")) { uwsgi_log("*** detected a ruby vm built with --enable-load-relative ***\n"); uwsgi_log("*** if you get errors about rubygems.rb, you can:\n"); uwsgi_log("*** 1) add a directory to the libdir search path using --ruby-libdir ***\n"); uwsgi_log("*** 2) force the RUBY_EXEC_PREFIX with --chdir ***\n"); } #endif #ifdef UWSGI_RUBY_LIBDIR uwsgi_string_new_list(&ur.libdir, UWSGI_RUBY_LIBDIR); #endif #ifdef UWSGI_RUBY_ARCHDIR uwsgi_string_new_list(&ur.libdir, UWSGI_RUBY_ARCHDIR); #endif ruby_init(); struct uwsgi_string_list *usl = ur.libdir; while(usl) { ruby_incpush(usl->value); uwsgi_log("[ruby-libdir] pushed %s\n", usl->value); usl = usl->next; } ruby_options(argc, argv); #else ruby_init(); VALUE dummy; Init_stack(&dummy); ruby_init_loadpath(); #endif ruby_show_version(); ruby_script("uwsgi"); ur.dollar_zero = rb_str_new2("uwsgi"); rb_define_hooked_variable("$0", &ur.dollar_zero, 0, rack_hack_dollar_zero); rb_define_hooked_variable("$PROGRAM_NAME", &ur.dollar_zero, 0, rack_hack_dollar_zero); ur.signals_protector = rb_ary_new(); ur.rpc_protector = rb_ary_new(); rb_gc_register_address(&ur.signals_protector); rb_gc_register_address(&ur.rpc_protector); uwsgi_rack_init_api(); return 0; } void uwsgi_rack_preinit_apps() { struct uwsgi_string_list *usl = ur.shared_rbrequire; while(usl) { int error = 0; rb_protect( uwsgi_require_file, rb_str_new2(usl->value), &error ) ; if (error) { uwsgi_ruby_exception_log(NULL); } usl = usl->next; } } VALUE uwsgi_rb_call_new(VALUE obj) { return rb_funcall(obj, rb_intern("new"), 0); } void uwsgi_rack_init_apps(void) { int error; if (uwsgi_apps_cnt >= uwsgi.max_apps) { uwsgi_log("ERROR: you cannot load more than %d apps in a worker\n", uwsgi.max_apps); return; } ur.app_id = uwsgi_apps_cnt; struct uwsgi_string_list *usl = ur.rbrequire; time_t now = uwsgi_now(); while(usl) { error = 0; rb_protect( uwsgi_require_file, rb_str_new2(usl->value), &error ) ; if (error) { uwsgi_ruby_exception_log(NULL); } usl = usl->next; } if (ur.rack) { ur.dispatcher = rb_protect(init_rack_app, rb_str_new2(ur.rack), &error); if (error) { uwsgi_ruby_exception_log(NULL); exit(1); } if (ur.dispatcher == Qnil) { uwsgi_log("unable to find RACK entry point\n"); exit(1); } rb_gc_register_address(&ur.dispatcher); goto ready; } else if (ur.rails) { if (chdir(ur.rails)) { uwsgi_error("chdir()"); exit(1); } if (!access("config.ru", R_OK)) { uwsgi_log("!!! a config.ru file has been found in yor rails app, please use --rack instead of the old --rails !!!\n"); } uwsgi_log("loading rails app %s\n", ur.rails); rb_protect( require_rails, 0, &error ) ; if (error) { uwsgi_ruby_exception_log(NULL); exit(1); } uwsgi_log("rails app %s ready\n", ur.rails); VALUE ac = rb_const_get(rb_cObject, rb_intern("ActionController")); ur.dispatcher = Qnil; if (rb_funcall(ac, rb_intern("const_defined?"), 1, ID2SYM(rb_intern("Dispatcher"))) == Qtrue) { VALUE ac_dispatcher = rb_const_get(ac, rb_intern("Dispatcher")); VALUE acd_instance_methods = rb_funcall( ac_dispatcher, rb_intern("instance_methods"), 0); VALUE acim_call = rb_funcall( acd_instance_methods, rb_intern("include?"), 1, ID2SYM(rb_intern("call"))); if (acim_call == Qfalse) { acim_call = rb_funcall( acd_instance_methods, rb_intern("include?"), 1, rb_str_new2("call")); } if (acim_call == Qtrue) { ur.dispatcher = rb_protect(uwsgi_rb_call_new, ac_dispatcher, &error); if (error) { uwsgi_ruby_exception_log(NULL); exit(1); } } } if (ur.dispatcher == Qnil) { uwsgi_log("non-rack rails version detected...loading thin adapter...\n"); rb_protect( require_thin, 0, &error ) ; if (error) { uwsgi_ruby_exception_log(NULL); exit(1); } VALUE thin_rack = rb_const_get(rb_cObject, rb_intern("Rack")); VALUE thin_rack_adapter = rb_const_get(thin_rack, rb_intern("Adapter")); VALUE thin_rack_adapter_rails = rb_const_get(thin_rack_adapter, rb_intern("Rails")); ur.dispatcher = rb_protect( uwsgi_rb_call_new, thin_rack_adapter_rails, &error); if (error) { uwsgi_ruby_exception_log(NULL); exit(1); } } if (ur.dispatcher == Qnil) { uwsgi_log("unable to load rails dispatcher\n"); exit(1); } rb_gc_register_address(&ur.dispatcher); goto ready; } return; ready: ur.call = rb_intern("call"); if (!ur.call) { uwsgi_log("unable to find RACK entry point\n"); return; } rb_gc_register_address(&ur.call); ur.rb_uwsgi_io_class = rb_define_class("Uwsgi_IO", rb_cObject); rb_gc_register_address(&ur.rb_uwsgi_io_class); rb_define_singleton_method(ur.rb_uwsgi_io_class, "new", rb_uwsgi_io_new, 1); rb_define_method(ur.rb_uwsgi_io_class, "initialize", rb_uwsgi_io_init, -1); rb_define_method(ur.rb_uwsgi_io_class, "gets", rb_uwsgi_io_gets, 0); rb_define_method(ur.rb_uwsgi_io_class, "each", rb_uwsgi_io_each, 0); rb_define_method(ur.rb_uwsgi_io_class, "read", rb_uwsgi_io_read, -2); rb_define_method(ur.rb_uwsgi_io_class, "rewind", rb_uwsgi_io_rewind, 0); struct uwsgi_app *ua = uwsgi_add_app(ur.app_id, rack_plugin.modifier1, (char*)"", 0, NULL, NULL); ua->started_at = now; ua->startup_time = uwsgi_now() - now; uwsgi_emulate_cow_for_apps(ur.app_id); if (ur.gc_freq <= 1) { uwsgi_log("RACK app %d loaded in %d seconds at %p (GC frequency: AGGRESSIVE)\n", ur.app_id, (int) ua->startup_time, ur.call); } else { uwsgi_log("RACK app %d loaded in %d seconds at %p (GC frequency: %d)\n", ur.app_id, (int) ua->startup_time, ur.call, ur.gc_freq); } } VALUE call_dispatch(VALUE env) { return rb_funcall(ur.dispatcher, ur.call, 1, env); } static VALUE send_body(VALUE obj, VALUE data, int argc, const VALUE *argv, VALUE blockarg) { struct wsgi_request *wsgi_req = current_wsgi_req(); //uwsgi_log("sending body\n"); if (TYPE(obj) == T_STRING) { uwsgi_response_write_body_do(wsgi_req, RSTRING_PTR(obj), RSTRING_LEN(obj)); } else { uwsgi_log("UNMANAGED BODY TYPE %d\n", TYPE(obj)); } return Qnil; } VALUE body_to_path(VALUE body) { return rb_funcall( body, rb_intern("to_path"), 0); } VALUE close_body(VALUE body) { return rb_funcall( body, rb_intern("close"), 0); } VALUE iterate_body(VALUE body) { #ifdef RUBY19 return rb_block_call(body, rb_intern("each"), 0, 0, send_body, 0); #else return rb_iterate(rb_each, body, send_body, 0); #endif } VALUE send_header(VALUE obj, VALUE headers, int argc, const VALUE *argv, VALUE blockarg) { struct wsgi_request *wsgi_req = current_wsgi_req(); VALUE hkey, hval; //uwsgi_log("HEADERS %d\n", TYPE(obj)); if (TYPE(obj) == T_ARRAY) { if (RARRAY_LEN(obj) >= 2) { hkey = rb_obj_as_string( RARRAY_PTR(obj)[0]); hval = rb_obj_as_string( RARRAY_PTR(obj)[1]); } else { goto clear; } } else if (TYPE(obj) == T_STRING) { hkey = obj; #ifdef RUBY19 hval = rb_hash_lookup(headers, obj); #else hval = rb_hash_aref(headers, obj); #endif } else { goto clear; } if (TYPE(hkey) != T_STRING || TYPE(hval) != T_STRING) { goto clear; } char *header_value = RSTRING_PTR(hval); size_t header_value_len = RSTRING_LEN(hval); size_t i,cnt=0; char *this_header = header_value; for(i=0;i 0) { uwsgi_response_add_header(wsgi_req, RSTRING_PTR(hkey), RSTRING_LEN(hkey), this_header, cnt); } clear: return Qnil; } VALUE iterate_headers(VALUE headers) { #ifdef RUBY19 return rb_block_call(headers, rb_intern("each"), 0, 0, send_header, headers); #else return rb_iterate(rb_each, headers, send_header, headers); #endif } int uwsgi_rack_request(struct wsgi_request *wsgi_req) { int error = 0; int i; VALUE env, ret, status, headers, body; if (!ur.call) { uwsgi_500(wsgi_req); uwsgi_log("--- ruby application not found ---\n"); return -1; } /* Standard RACK request */ if (!wsgi_req->uh->pktsize) { uwsgi_log("Empty RACK request. skip.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } wsgi_req->app_id = ur.app_id; uwsgi_apps[wsgi_req->app_id].requests++; env = rb_hash_new(); // the following vars have to always been defined (we skip REQUEST_METHOD and PATH_INFO as they should always be available) rb_hash_aset(env, rb_str_new2("SCRIPT_NAME"), rb_str_new2("")); rb_hash_aset(env, rb_str_new2("QUERY_STRING"), rb_str_new2("")); rb_hash_aset(env, rb_str_new2("SERVER_NAME"), rb_str_new2(uwsgi.hostname)); // SERVER_PORT char *server_port = strchr(wsgi_req->socket->name, ':'); if (server_port) { rb_hash_aset(env, rb_str_new2("SERVER_PORT"), rb_str_new(server_port+1, strlen(server_port+1))); } else { rb_hash_aset(env, rb_str_new2("SERVER_PORT"), rb_str_new2("80")); } // fill ruby hash for(i=0;ivar_cnt;i++) { // put the var only if it is not 0 size or required (rack requirement... very inefficient) if (wsgi_req->hvec[i+1].iov_len > 0 || !uwsgi_strncmp((char *)"REQUEST_METHOD", 14, wsgi_req->hvec[i].iov_base, (int) wsgi_req->hvec[i].iov_len) || !uwsgi_strncmp((char *)"SCRIPT_NAME", 11, wsgi_req->hvec[i].iov_base, (int) wsgi_req->hvec[i].iov_len) || !uwsgi_strncmp((char *)"PATH_INFO", 10, wsgi_req->hvec[i].iov_base, (int) wsgi_req->hvec[i].iov_len) || !uwsgi_strncmp((char *)"QUERY_STRING", 12, wsgi_req->hvec[i].iov_base, (int) wsgi_req->hvec[i].iov_len) || !uwsgi_strncmp((char *)"SERVER_NAME", 11, wsgi_req->hvec[i].iov_base, (int) wsgi_req->hvec[i].iov_len) || !uwsgi_strncmp((char *)"SERVER_PORT", 11, wsgi_req->hvec[i].iov_base, (int) wsgi_req->hvec[i].iov_len) ) { rb_hash_aset(env, rb_str_new(wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len), rb_str_new(wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len)); //uwsgi_log("%.*s = %.*s\n", wsgi_req->hvec[i].iov_len, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i+1].iov_len, wsgi_req->hvec[i+1].iov_base); } i++; } VALUE rbv = rb_ary_new(); rb_ary_store(rbv, 0, INT2NUM(1)); rb_ary_store(rbv, 1, INT2NUM(1)); rb_hash_aset(env, rb_str_new2("rack.version"), rbv); if (wsgi_req->scheme_len > 0) { rb_hash_aset(env, rb_str_new2("rack.url_scheme"), rb_str_new(wsgi_req->scheme, wsgi_req->scheme_len)); } else if (wsgi_req->https_len > 0) { if (!strncasecmp(wsgi_req->https, "on", 2) || wsgi_req->https[0] == '1') { rb_hash_aset(env, rb_str_new2("rack.url_scheme"), rb_str_new2("https")); } else { rb_hash_aset(env, rb_str_new2("rack.url_scheme"), rb_str_new2("http")); } } else { rb_hash_aset(env, rb_str_new2("rack.url_scheme"), rb_str_new2("http")); } if (uwsgi.threads > 1) { rb_hash_aset(env, rb_str_new2("rack.multithread"), Qtrue); } else { rb_hash_aset(env, rb_str_new2("rack.multithread"), Qfalse); } if (uwsgi.numproc > 1) { rb_hash_aset(env, rb_str_new2("rack.multiprocess"), Qtrue); } else { rb_hash_aset(env, rb_str_new2("rack.multiprocess"), Qfalse); } rb_hash_aset(env, rb_str_new2("rack.run_once"), Qfalse); VALUE dws_wr = Data_Wrap_Struct(ur.rb_uwsgi_io_class, 0, 0, wsgi_req); rb_hash_aset(env, rb_str_new2("rack.input"), rb_funcall(ur.rb_uwsgi_io_class, rb_intern("new"), 1, dws_wr )); rb_hash_aset(env, rb_str_new2("rack.errors"), rb_funcall( rb_const_get(rb_cObject, rb_intern("IO")), rb_intern("new"), 2, INT2NUM(2), rb_str_new("w",1) )); rb_hash_aset(env, rb_str_new2("uwsgi.core"), INT2NUM(wsgi_req->async_id)); rb_hash_aset(env, rb_str_new2("uwsgi.version"), rb_str_new2(UWSGI_VERSION)); rb_hash_aset(env, rb_str_new2("uwsgi.node"), rb_str_new2(uwsgi.hostname)); // remove HTTP_CONTENT_LENGTH and HTTP_CONTENT_TYPE rb_hash_delete(env, rb_str_new2("HTTP_CONTENT_LENGTH")); rb_hash_delete(env, rb_str_new2("HTTP_CONTENT_TYPE")); if (ur.unprotected) { ret = call_dispatch(env); } else { ret = rb_protect( call_dispatch, env, &error); if (error) { uwsgi_manage_exception(wsgi_req, uwsgi.catch_exceptions); goto clear; } } if (TYPE(ret) == T_ARRAY) { if (RARRAY_LEN(ret) != 3) { uwsgi_log("Invalid RACK response size: %ld\n", RARRAY_LEN(ret)); return -1; } // manage Status status = rb_obj_as_string(RARRAY_PTR(ret)[0]); // get the status code if (uwsgi_response_prepare_headers(wsgi_req, RSTRING_PTR(status), RSTRING_LEN(status))) { goto clear; } headers = RARRAY_PTR(ret)[1] ; if (rb_respond_to( headers, rb_intern("each") )) { rb_protect( iterate_headers, headers, &error); if (error) { uwsgi_manage_exception(wsgi_req, uwsgi.catch_exceptions); goto clear; } } body = RARRAY_PTR(ret)[2] ; if (rb_respond_to( body, rb_intern("to_path") )) { VALUE sendfile_path = rb_protect( body_to_path, body, &error); if (error) { uwsgi_manage_exception(wsgi_req, uwsgi.catch_exceptions); } else { int fd = open(RSTRING_PTR(sendfile_path), O_RDONLY); if (fd < 0) goto clear; // the following function will close the descriptor uwsgi_response_sendfile_do(wsgi_req, fd, 0, 0); } } else if (rb_respond_to( body, rb_intern("each") )) { if (ur.unprotected) { iterate_body(body); } else { rb_protect( iterate_body, body, &error); if (error) { uwsgi_manage_exception(wsgi_req, uwsgi.catch_exceptions); } } } if (rb_respond_to( body, rb_intern("close") )) { //uwsgi_log("calling close\n"); rb_protect( close_body, body, &error); if (error) { uwsgi_manage_exception(wsgi_req, uwsgi.catch_exceptions); } } } else { uwsgi_500(wsgi_req); uwsgi_log("invalid RACK response\n"); } clear: if (ur.gc_freq <= 1 || ur.cycles%ur.gc_freq == 0) { #ifdef UWSGI_DEBUG uwsgi_log("calling ruby GC\n"); #endif // try to limit damanges if threads are enabled... if (wsgi_req->async_id == 0) { rb_gc(); } } ur.cycles++; return 0; } void uwsgi_rack_after_request(struct wsgi_request *wsgi_req) { log_request(wsgi_req); } void uwsgi_rack_suspend(struct wsgi_request *wsgi_req) { //uwsgi_log("SUSPENDING RUBY\n"); } void uwsgi_rack_resume(struct wsgi_request *wsgi_req) { //uwsgi_log("RESUMING RUBY\n"); } VALUE init_rack_app( VALUE script ) { int error; #ifndef RUBY19 rb_require("rubygems"); #endif rb_protect( require_rack, 0, &error ) ; if (error) { uwsgi_ruby_exception_log(NULL); return Qnil; } VALUE rack = rb_const_get(rb_cObject, rb_intern("Rack")); #ifdef RUBY19 if (rb_funcall(rack, rb_intern("const_defined?"), 1, ID2SYM(rb_intern("BodyProxy"))) == Qtrue) { VALUE bodyproxy = rb_const_get(rack, rb_intern("BodyProxy")); // get the list of available instance_methods VALUE argv = Qfalse; VALUE methods_list = rb_class_instance_methods(1, &argv, bodyproxy); #ifdef UWSGI_DEBUG uwsgi_log("%s\n", RSTRING_PTR(rb_inspect(methods_list))); #endif if (rb_ary_includes(methods_list, ID2SYM(rb_intern("each"))) == Qfalse) { if (rb_eval_string("module Rack;class BodyProxy;def each(&block);@body.each(&block);end;end;end")) { if (uwsgi.mywid <= 1) { uwsgi_log("Rack::BodyProxy successfully patched for ruby 1.9.x\n"); } } } } #endif VALUE rackup = rb_funcall( rb_const_get(rack, rb_intern("Builder")), rb_intern("parse_file"), 1, script); if (TYPE(rackup) == T_OBJECT) { // rack +3 return rackup; } else if (TYPE(rackup) == T_ARRAY) { // rack << 3 if (RARRAY_LEN(rackup) < 1) { uwsgi_log("invalid rack config file: %s\n", RSTRING_PTR(script)); return Qnil; } return RARRAY_PTR(rackup)[0] ; } else { uwsgi_log("unable to parse %s file %d\n", RSTRING_PTR(script), TYPE(rackup)); return Qnil; } } int uwsgi_rack_magic(char *mountpoint, char *lazy) { if (!strcmp(lazy+strlen(lazy)-3, ".ru")) { ur.rack = lazy; return 1; } else if (!strcmp(lazy+strlen(lazy)-3, ".rb")) { ur.rack = lazy; return 1; } return 0; } int uwsgi_rack_mount_app(char *mountpoint, char *app) { if (uwsgi_endswith(app, ".ru") || uwsgi_endswith(app, ".rb")) { ur.rack = app; uwsgi_rack_init_apps(); return 0; } return -1; } VALUE run_irb(VALUE arg) { rb_funcall(rb_cObject, rb_intern("require"), 1, rb_str_new2("irb")); VALUE irb = rb_const_get(rb_cObject, rb_intern("IRB")); return rb_funcall(irb, rb_intern("start"), 0); } static void uwsgi_rack_hijack(void) { if (ur.rb_shell_oneshot && uwsgi.workers[uwsgi.mywid].hijacked_count > 0) { uwsgi.workers[uwsgi.mywid].hijacked = 0; return; } if (ur.rbshell && uwsgi.mywid == 1) { uwsgi.workers[uwsgi.mywid].hijacked = 1; uwsgi.workers[uwsgi.mywid].hijacked_count++; // re-map stdin to stdout and stderr if we are logging to a file if (uwsgi.logfile) { if (dup2(0, 1) < 0) { uwsgi_error("dup2()"); } if (dup2(0, 2) < 0) { uwsgi_error("dup2()"); } } int error = 0; if (ur.rbshell[0] != 0) { rb_eval_string(ur.rbshell); } else { rb_protect( run_irb, 0, &error ) ; if (error) { uwsgi_ruby_exception_log(NULL); exit(1); } } if (ur.rb_shell_oneshot) { exit(UWSGI_DE_HIJACKED_CODE); } exit(0); } } int uwsgi_rack_mule(char *opt) { int error = 0; if (uwsgi_endswith(opt, (char *)".rb")) { rb_protect( uwsgi_require_file, rb_str_new2(opt), &error ) ; if (error) { uwsgi_ruby_exception_log(NULL); return 0; } return 1; } return 0; } VALUE uwsgi_rb_pfh(VALUE args) { VALUE uwsgi_rb_embedded = rb_const_get(rb_cObject, rb_intern("UWSGI")); if (rb_respond_to(uwsgi_rb_embedded, rb_intern("post_fork_hook"))) { return rb_funcall(uwsgi_rb_embedded, rb_intern("post_fork_hook"), 0); } return Qnil; } void uwsgi_rb_post_fork() { int error = 0; // call the post_fork_hook rb_protect(uwsgi_rb_pfh, 0, &error); if (error) { uwsgi_ruby_exception_log(NULL); } } VALUE uwsgi_rb_mmh(VALUE args) { VALUE uwsgi_rb_embedded = rb_const_get(rb_cObject, rb_intern("UWSGI")); return rb_funcall(uwsgi_rb_embedded, rb_intern("mule_msg_hook"), 1, args); } int uwsgi_rack_mule_msg(char *message, size_t len) { int error = 0; VALUE uwsgi_rb_embedded = rb_const_get(rb_cObject, rb_intern("UWSGI")); if (rb_respond_to(uwsgi_rb_embedded, rb_intern("mule_msg_hook"))) { VALUE arg = rb_str_new(message, len); rb_protect(uwsgi_rb_mmh, arg, &error); if (error) { uwsgi_ruby_exception_log(NULL); } return 1; } return 0; } VALUE rack_call_signal_handler(VALUE args) { return rb_funcall(rb_ary_entry(args, 0), rb_intern("call"), 1, rb_ary_entry(args, 1)); } int uwsgi_rack_signal_handler(uint8_t sig, void *handler) { int error = 0; VALUE rbhandler = (VALUE) handler; VALUE args = rb_ary_new2(2); rb_ary_store(args, 0, rbhandler); VALUE rbsig = INT2NUM(sig); rb_ary_store(args, 1, rbsig); rb_protect(rack_call_signal_handler, args, &error); if (error) { uwsgi_ruby_exception_log(NULL); rb_gc(); return -1; } rb_gc(); return 0; } VALUE uwsgi_rb_do_spooler(VALUE args) { VALUE uwsgi_rb_embedded = rb_const_get(rb_cObject, rb_intern("UWSGI")); return rb_funcall(uwsgi_rb_embedded, rb_intern("spooler"), 1, args); } void uwsgi_ruby_add_item(char *key, uint16_t keylen, char *val, uint16_t vallen, void *data) { VALUE *spool_dict = (VALUE*) data; rb_hash_aset(*spool_dict, rb_str_new(key, keylen), rb_str_new(val, vallen)); } int uwsgi_rack_spooler(char *filename, char *buf, uint16_t len, char *body, size_t body_len) { int error = 0; VALUE uwsgi_rb_embedded = rb_const_get(rb_cObject, rb_intern("UWSGI")); if (!rb_respond_to(uwsgi_rb_embedded, rb_intern("spooler"))) { rb_gc(); return 0; } VALUE spool_dict = rb_hash_new(); if (uwsgi_hooked_parse(buf, len, uwsgi_ruby_add_item, (void *) &spool_dict)) { rb_gc(); // malformed packet, destroy it return 0; } rb_hash_aset(spool_dict, rb_str_new2("spooler_task_name"), rb_str_new2(filename)); if (body && body_len > 0) { rb_hash_aset(spool_dict, rb_str_new2("body"), rb_str_new(body, body_len)); } VALUE ret = rb_protect(uwsgi_rb_do_spooler, spool_dict, &error); if (error) { uwsgi_ruby_exception_log(NULL); rb_gc(); return -1; } if (TYPE(ret) == T_FIXNUM) { rb_gc(); return NUM2INT(ret); } // error, retry rb_gc(); return -1; } void uwsgi_ruby_enable_native_threads() { uwsgi_log("DANGER: native threads do not work under ruby !!!\n"); } void uwsgi_ruby_init_thread(int core_id) { uwsgi_log("DANGER: native threads do not work under ruby !!!\n"); } void uwsgi_rack_postinit_apps(void) { } /* If the ruby VM has rb_reserved_fd_p, we avoid closign the filedescriptor needed by modern ruby (the Matz ones) releases. */ static void uwsgi_ruby_cleanup() { int (*uptr_rb_reserved_fd_p)(int) = dlsym(RTLD_DEFAULT, "rb_reserved_fd_p"); if (!uptr_rb_reserved_fd_p) return; int i; for (i = 3; i < (int) uwsgi.max_fd; i++) { if (uptr_rb_reserved_fd_p(i)) { uwsgi_add_safe_fd(i); } } } struct uwsgi_plugin rack_plugin = { .name = "rack", .modifier1 = 7, .init = uwsgi_rack_init, .options = uwsgi_rack_options, .request = uwsgi_rack_request, .after_request = uwsgi_rack_after_request, .signal_handler = uwsgi_rack_signal_handler, .hijack_worker = uwsgi_rack_hijack, .post_fork = uwsgi_rb_post_fork, .spooler = uwsgi_rack_spooler, .preinit_apps = uwsgi_rack_preinit_apps, .init_apps = uwsgi_rack_init_apps, .mount_app = uwsgi_rack_mount_app, .postinit_apps = uwsgi_rack_postinit_apps, .magic = uwsgi_rack_magic, .mule = uwsgi_rack_mule, .mule_msg = uwsgi_rack_mule_msg, .rpc = uwsgi_ruby_rpc, .enable_threads = uwsgi_ruby_enable_native_threads, .init_thread = uwsgi_ruby_init_thread, .suspend = uwsgi_rack_suspend, .resume = uwsgi_rack_resume, .exception_class = uwsgi_ruby_exception_class, .exception_msg = uwsgi_ruby_exception_msg, .exception_repr = uwsgi_ruby_exception_repr, .exception_log = uwsgi_ruby_exception_log, .backtrace = uwsgi_ruby_backtrace, .master_cleanup = uwsgi_ruby_cleanup, }; uwsgi-2.0.29/plugins/rack/uwsgi_rack.h000066400000000000000000000017031477626554400176770ustar00rootroot00000000000000#include #include #ifndef RUBY19 #include #define rb_errinfo() ruby_errinfo #endif #ifndef RARRAY_LEN #define RARRAY_LEN(x) RARRAY(x)->len #endif #ifndef RARRAY_PTR #define RARRAY_PTR(x) RARRAY(x)->ptr #endif #ifndef RSTRING_PTR #define RSTRING_PTR(x) RSTRING(x)->ptr #endif #ifndef RSTRING_LEN #define RSTRING_LEN(x) RSTRING(x)->len #endif struct uwsgi_rack { char *rails; char *rack; int gc_freq; uint64_t cycles; int call_gc; // why why why !!!!????!!!??? VALUE signals_protector; VALUE rpc_protector; VALUE dollar_zero; VALUE dispatcher; VALUE rb_uwsgi_io_class; ID call; char *rbshell; int rb_shell_oneshot; int app_id; int unprotected; struct uwsgi_string_list *rbrequire; struct uwsgi_string_list *shared_rbrequire; struct uwsgi_string_list *rvm_path; char *gemset; struct uwsgi_string_list *libdir; }; void uwsgi_rack_init_api(void); uwsgi-2.0.29/plugins/rack/uwsgiplugin.py000066400000000000000000000062521477626554400203230ustar00rootroot00000000000000import os,sys NAME='rack' try: RUBYPATH = os.environ['UWSGICONFIG_RUBYPATH'] except: RUBYPATH = 'ruby' rbconfig = 'Config' version = os.popen(RUBYPATH + " -e \"print RUBY_VERSION\"").read().rstrip() v = version.split('.') GCC_LIST = ['rack_plugin', 'rack_api'] if (v[0] == '1' and v[1] == '9') or v[0] >= '2': CFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print RbConfig::CONFIG['CFLAGS']\"").read().rstrip().split() CFLAGS.append('-DRUBY19') if version >= '2.7': CFLAGS.append('-DRUBY27') CFLAGS.append('-Wno-unused-parameter') rbconfig = 'RbConfig' else: CFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['CFLAGS']\"" % rbconfig).read().rstrip().split() includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['rubyhdrdir']\"" % rbconfig).read().rstrip() if includedir == 'nil': includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['archdir']\"" % rbconfig).read().rstrip() CFLAGS.append('-I' + includedir) else: CFLAGS.append('-I' + includedir) archdir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['archdir']\"" % rbconfig).read().rstrip() arch = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['arch']\"" % rbconfig).read().rstrip() archdir2 = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['rubyarchhdrdir']\"" % rbconfig).read().rstrip() CFLAGS.append('-I' + archdir) CFLAGS.append('-I' + archdir + '/' + arch) CFLAGS.append('-I' + includedir + '/' + arch) if archdir2: CFLAGS.append('-I' + archdir2) LDFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['LDFLAGS']\"" % rbconfig).read().rstrip().split() libpath = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['libdir']\"" % rbconfig).read().rstrip() has_shared = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['ENABLE_SHARED']\"" % rbconfig).read().rstrip() LIBS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['LIBS']\"" % rbconfig).read().rstrip().split() if has_shared == 'yes': LDFLAGS.append('-L' + libpath ) os.environ['LD_RUN_PATH'] = libpath LIBS.append(os.popen(RUBYPATH + " -e \"require 'rbconfig';print '-l' + %s::CONFIG['RUBY_SO_NAME']\"" % rbconfig).read().rstrip()) else: rubylibdir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print RbConfig::CONFIG['rubylibdir']\"").read().rstrip() rubyarchdir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print RbConfig::CONFIG['archdir']\"").read().rstrip() # detect Heroku system heroku = False if rubylibdir.startswith('/tmp/build_'): heroku = True rubylibdir = '/app/' + '/'.join(rubylibdir.split('/')[3:]) if rubyarchdir.startswith('/tmp/build_'): heroku = True rubyarchdir = '/app/' + '/'.join(rubyarchdir.split('/')[3:]) if heroku: CFLAGS.append('-DUWSGI_RUBY_HEROKU') CFLAGS.append('-DUWSGI_RUBY_LIBDIR="\\"%s\\""' % rubylibdir) CFLAGS.append('-DUWSGI_RUBY_ARCHDIR="\\"%s\\""' % rubyarchdir) GCC_LIST.append("%s/%s" % (libpath, os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['LIBRUBY_A']\"" % rbconfig).read().rstrip())) uwsgi-2.0.29/plugins/rados/000077500000000000000000000000001477626554400155575ustar00rootroot00000000000000uwsgi-2.0.29/plugins/rados/rados.c000066400000000000000000000445331477626554400170440ustar00rootroot00000000000000#include #include extern struct uwsgi_server uwsgi; /* Author: Javier Guerra Author: Marcin Deranek Author: Roberto De Ioris --rados-mount mountpoint=/foo,pool=unbit001,config=/etc/ceph.conf,timeout=30,allow_put=1,allow_delete=1 */ struct uwsgi_plugin rados_plugin; // this structure is preallocated (only the pipe part is per-request) struct uwsgi_rados_io { int fds[2]; // this is increased at every usage (in locked context) uint64_t rid; pthread_mutex_t mutex; }; // this structure is allocated for each async transaction struct uwsgi_rados_cb { // this is copied from the current uwsgi_rados_io->rid uint64_t rid; struct uwsgi_rados_io *urio; }; static struct uwsgi_rados { int timeout; struct uwsgi_string_list *mountpoints; struct uwsgi_rados_io *urio; } urados; struct uwsgi_rados_mountpoint { rados_t cluster; char *mountpoint; char *config; char *pool; char *str_timeout; int timeout; char *allow_put; char *allow_delete; char *allow_mkcol; }; static struct uwsgi_option uwsgi_rados_options[] = { {"rados-mount", required_argument, 0, "virtual mount the specified rados volume in a uri", uwsgi_opt_add_string_list, &urados.mountpoints, UWSGI_OPT_MIME}, {"rados-timeout", required_argument, 0, "timeout for async operations", uwsgi_opt_set_int, &urados.timeout, 0}, {0, 0, 0, 0, 0, 0, 0}, }; static int uwsgi_rados_read_sync(struct wsgi_request *wsgi_req, rados_ioctx_t ctx, const char *key, size_t remains) { uint64_t off = 0; while(remains > 0) { char buf[8192]; int rlen = rados_read(ctx, key, buf, UMIN(remains, 8192), off); if (rlen <= 0) return -1; if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) return -1; remains -= rlen; off += rlen; } return 0; } // callback used to asynchronously signal the completion static void uwsgi_rados_read_async_cb(rados_completion_t comp, void *data) { struct uwsgi_rados_cb *urcb = (struct uwsgi_rados_cb *) data; struct uwsgi_rados_io *urio = urcb->urio; pthread_mutex_lock(&urio->mutex); if (urcb->rid != urio->rid) { uwsgi_log_verbose("[uwsgi-rados] callback %llu woke up too late\n", (unsigned long long) urcb->rid); } else { // signal the core if (write(urio->fds[1], "\1", 1) <= 0) { uwsgi_error("uwsgi_rados_read_async_cb()/write()"); } } pthread_mutex_unlock(&urio->mutex); free(urcb); } static int uwsgi_rados_delete(struct wsgi_request *wsgi_req, rados_ioctx_t ctx, char *key, int timeout) { if (uwsgi.async <= 1) { return rados_remove(ctx, key); } struct uwsgi_rados_io *urio = &urados.urio[wsgi_req->async_id]; int ret = -1; // increase request counter pthread_mutex_lock(&urio->mutex); urio->rid++; pthread_mutex_unlock(&urio->mutex); struct uwsgi_rados_cb *urcb = uwsgi_malloc(sizeof(struct uwsgi_rados_cb)); // map the current request id to the callback urcb->rid = urio->rid; // map urio to the callback urcb->urio = urio; rados_completion_t comp; // we use the safe cb here if (rados_aio_create_completion(urcb, NULL, uwsgi_rados_read_async_cb, &comp) < 0) { free(urcb); goto end; } if (rados_aio_remove(ctx, key, comp) < 0) { free(urcb); rados_aio_release(comp); goto end; } // wait for the callback to be executed if (uwsgi.wait_read_hook(urio->fds[0], timeout) <= 0) { rados_aio_release(comp); goto end; } char ack = 1; if (read(urio->fds[0], &ack, 1) != 1) { rados_aio_release(comp); uwsgi_error("uwsgi_rados_delete()/read()"); goto end; } if (rados_aio_is_safe_and_cb(comp)) { ret = rados_aio_get_return_value(comp); } rados_aio_release(comp); end: return ret; } static int uwsgi_rados_put(struct wsgi_request *wsgi_req, rados_ioctx_t ctx, char *key, int timeout) { struct uwsgi_rados_io *urio = &urados.urio[wsgi_req->async_id]; size_t remains = wsgi_req->post_cl; uint64_t off = 0; while(remains > 0) { ssize_t body_len = 0; char *body = uwsgi_request_body_read(wsgi_req, UMIN(remains, 32768) , &body_len); if (!body || body == uwsgi.empty) goto error; if (uwsgi.async <= 1) { if (rados_write_full(ctx, key, body, body_len) < 0) { return -1; } } else { // increase request counter pthread_mutex_lock(&urio->mutex); urio->rid++; pthread_mutex_unlock(&urio->mutex); struct uwsgi_rados_cb *urcb = uwsgi_malloc(sizeof(struct uwsgi_rados_cb)); // map the current request id to the callback urcb->rid = urio->rid; // map urio to the callback urcb->urio = urio; rados_completion_t comp; // use safe for write if (rados_aio_create_completion(urcb, NULL, uwsgi_rados_read_async_cb, &comp) < 0) { free(urcb); goto error; } if (rados_aio_write_full(ctx, key, comp, body, body_len) < 0) { free(urcb); rados_aio_release(comp); goto error; } // wait for the callback to be executed if (uwsgi.wait_read_hook(urio->fds[0], timeout) <= 0) { rados_aio_release(comp); goto error; } char ack = 1; if (read(urio->fds[0], &ack, 1) != 1) { rados_aio_release(comp); uwsgi_error("uwsgi_rados_read_async()/read()"); goto error; } if (rados_aio_is_safe_and_cb(comp)) { if (rados_aio_get_return_value(comp) < 0) { rados_aio_release(comp); goto error; } } rados_aio_release(comp); } remains -= body_len; off += body_len; } return 0; error: return -1; } // async stat static int uwsgi_rados_async_stat(struct uwsgi_rados_io *urio, rados_ioctx_t ctx, const char *key, uint64_t *stat_size, time_t *stat_mtime, int timeout) { int ret = -1; // increase request counter pthread_mutex_lock(&urio->mutex); urio->rid++; pthread_mutex_unlock(&urio->mutex); struct uwsgi_rados_cb *urcb = uwsgi_malloc(sizeof(struct uwsgi_rados_cb)); // map the current request id to the callback urcb->rid = urio->rid; // map urio to the callback urcb->urio = urio; rados_completion_t comp; if (rados_aio_create_completion(urcb, uwsgi_rados_read_async_cb, NULL, &comp) < 0) { free(urcb); goto end; } if (rados_aio_stat(ctx, key, comp, stat_size, stat_mtime) < 0) { free(urcb); rados_aio_release(comp); goto end; } // wait for the callback to be executed if (uwsgi.wait_read_hook(urio->fds[0], timeout) <= 0) { rados_aio_release(comp); goto end; } char ack = 1; if (read(urio->fds[0], &ack, 1) != 1) { rados_aio_release(comp); uwsgi_error("uwsgi_rados_read_async()/read()"); goto end; } if (rados_aio_is_complete_and_cb(comp)) { ret = rados_aio_get_return_value(comp); } rados_aio_release(comp); end: return ret; } static int uwsgi_rados_read_async(struct wsgi_request *wsgi_req, rados_ioctx_t ctx, const char *key, size_t remains, int timeout) { uint64_t off = 0; int ret = -1; char buf[8192]; struct uwsgi_rados_io *urio = &urados.urio[wsgi_req->async_id]; // increase request counter pthread_mutex_lock(&urio->mutex); urio->rid++; pthread_mutex_unlock(&urio->mutex); while(remains > 0) { struct uwsgi_rados_cb *urcb = uwsgi_malloc(sizeof(struct uwsgi_rados_cb)); // map the current request id to the callback urcb->rid = urio->rid; // map urio to the callback urcb->urio = urio; rados_completion_t comp; if (rados_aio_create_completion(urcb, uwsgi_rados_read_async_cb, NULL, &comp) < 0) { free(urcb); break; } // trigger an async read if (rados_aio_read(ctx, key, comp, buf, UMIN(remains, 8192), off) < 0) { free(urcb); rados_aio_release(comp); break; } // wait for the callback to be executed if (uwsgi.wait_read_hook(urio->fds[0], timeout) <= 0) { rados_aio_release(comp); break; } char ack = 1; if (read(urio->fds[0], &ack, 1) != 1) { rados_aio_release(comp); uwsgi_error("uwsgi_rados_read_async()/read()"); break; } int rlen = -1; if (rados_aio_is_complete_and_cb(comp)) { rlen = rados_aio_get_return_value(comp); } rados_aio_release(comp); if (rlen <= 0) break; if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) break; remains -= rlen; off += rlen; } if (remains == 0) ret = 0; pthread_mutex_lock(&urio->mutex); // increase the counter again urio->rid++; pthread_mutex_unlock(&urio->mutex); return ret; } static void uwsgi_rados_add_mountpoint(char *arg, size_t arg_len) { struct uwsgi_rados_mountpoint *urmp = uwsgi_calloc(sizeof(struct uwsgi_rados_mountpoint)); if (uwsgi_kvlist_parse(arg, arg_len, ',', '=', "mountpoint", &urmp->mountpoint, "config", &urmp->config, "pool", &urmp->pool, "timeout", &urmp->str_timeout, "allow_put", &urmp->allow_put, "allow_delete", &urmp->allow_delete, "allow_mkcol", &urmp->allow_mkcol, NULL)) { uwsgi_log("unable to parse rados mountpoint definition\n"); exit(1); } if (!urmp->mountpoint|| !urmp->pool) { uwsgi_log("[rados] mount requires a mountpoint, and a pool name.\n"); exit(1); } if (urmp->str_timeout) { urmp->timeout = atoi(urmp->str_timeout); } time_t now = uwsgi_now(); uwsgi_log("[rados] mounting %s ...\n", urmp->mountpoint); rados_t cluster; if (rados_create(&cluster, NULL) < 0) { uwsgi_error("can't create Ceph cluster handle"); exit(1); } urmp->cluster = cluster; if (urmp->config) uwsgi_log("using Ceph conf:%s\n", urmp->config); else uwsgi_log("using default Ceph conf.\n"); if (rados_conf_read_file(cluster, urmp->config) < 0) { uwsgi_error("can't configure Ceph cluster handle"); exit(1); } int timeout = urmp->timeout ? urmp->timeout : urados.timeout; char *timeout_str = uwsgi_num2str(timeout); rados_conf_set(cluster, "client_mount_timeout", timeout_str); rados_conf_set(cluster, "rados_mon_op_timeout", timeout_str); rados_conf_set(cluster, "rados_osd_op_timeout", timeout_str); free(timeout_str); if (rados_connect(cluster) < 0) { uwsgi_error("can't connect with Ceph cluster"); exit(1); } void *ctx_ptr; if (uwsgi.threads > 1) { int i; rados_ioctx_t *ctxes = uwsgi_calloc(sizeof(rados_ioctx_t) * uwsgi.threads); for(i=0;ipool, &ctxes[i]) < 0) { uwsgi_error("can't open rados pool") rados_shutdown(cluster); exit(1); } } ctx_ptr = ctxes; } else { rados_ioctx_t ctx; if (rados_ioctx_create(cluster, urmp->pool, &ctx) < 0) { uwsgi_error("can't open rados pool") rados_shutdown(cluster); exit(1); } ctx_ptr = ctx; } char fsid[37]; rados_cluster_fsid(cluster, fsid, 37); uwsgi_log("connected to Ceph pool: %s on cluster %.*s\n", urmp->pool, 37, fsid); int id = uwsgi_apps_cnt; struct uwsgi_app *ua = uwsgi_add_app(id, rados_plugin.modifier1, urmp->mountpoint, strlen(urmp->mountpoint), NULL, NULL); if (!ua) { uwsgi_log("[rados] unable to mount %s\n", urmp->mountpoint); rados_shutdown(cluster); exit(1); } ua->responder0 = ctx_ptr; ua->responder1 = urmp; ua->started_at = now; ua->startup_time = uwsgi_now() - now; uwsgi_log("Rados app/mountpoint %d (%s) loaded in %d seconds at %p\n", id, urmp->mountpoint, (int) ua->startup_time, ctx_ptr); } // we translate the string list to an app representation // this happens before fork() if not in lazy/lazy-apps mode static void uwsgi_rados_setup() { if (!urados.timeout) { urados.timeout = uwsgi.socket_timeout; } struct uwsgi_string_list *usl = urados.mountpoints; while(usl) { uwsgi_rados_add_mountpoint(usl->value, usl->len); usl = usl->next; } // now initialize a pthread_mutex for each async core if (uwsgi.async > 1) { int i; urados.urio = uwsgi_calloc(sizeof(struct uwsgi_rados_io) * uwsgi.async); for(i=0;iuh->pktsize) { uwsgi_log( "Empty request. skip.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } // blocks empty paths if (wsgi_req->path_info_len == 0 || wsgi_req->path_info_len > PATH_MAX) { uwsgi_403(wsgi_req); return UWSGI_OK; } wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, rados_plugin.modifier1); if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) { if (uwsgi_apps[uwsgi.default_app].modifier1 == rados_plugin.modifier1) { wsgi_req->app_id = uwsgi.default_app; } } if (wsgi_req->app_id == -1) { uwsgi_404(wsgi_req); return UWSGI_OK; } struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id]; if (wsgi_req->path_info_len > ua->mountpoint_len && memcmp(wsgi_req->path_info, ua->mountpoint, ua->mountpoint_len) == 0) { memcpy(filename, wsgi_req->path_info+ua->mountpoint_len, wsgi_req->path_info_len-ua->mountpoint_len); filename[wsgi_req->path_info_len-ua->mountpoint_len] = 0; } else { memcpy(filename, wsgi_req->path_info, wsgi_req->path_info_len); filename[wsgi_req->path_info_len] = 0; } // in multithread mode the memory is different (as we need a ctx for each thread) !!! rados_ioctx_t ctx; if (uwsgi.threads > 1) { rados_ioctx_t *ctxes = (rados_ioctx_t *) ua->responder0; ctx = ctxes[wsgi_req->async_id]; } else { ctx = (rados_ioctx_t) ua->responder0; } struct uwsgi_rados_mountpoint *urmp = (struct uwsgi_rados_mountpoint *) ua->responder1; uint64_t stat_size = 0; time_t stat_mtime = 0; struct uwsgi_rados_io *urio = &urados.urio[wsgi_req->async_id]; if (uwsgi.async > 1) { // no need to lock here (the rid protect us) if (pipe(urio->fds)) { uwsgi_error("uwsgi_rados_read_async()/pipe()"); uwsgi_500(wsgi_req); return UWSGI_OK; } } int ret = -1; int timeout = urmp->timeout ? urmp->timeout : urados.timeout; if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "OPTIONS", 7)) { if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end; if (uwsgi_response_add_header(wsgi_req, "Dav", 3, "1", 1)) goto end; struct uwsgi_buffer *ub_allow = uwsgi_buffer_new(64); if (uwsgi_buffer_append(ub_allow, "OPTIONS, GET, HEAD", 18)) { uwsgi_buffer_destroy(ub_allow); goto end; } if (urmp->allow_put) { if (uwsgi_buffer_append(ub_allow, ", PUT", 5)) { uwsgi_buffer_destroy(ub_allow); goto end; } } if (urmp->allow_delete) { if (uwsgi_buffer_append(ub_allow, ", DELETE", 8)) { uwsgi_buffer_destroy(ub_allow); goto end; } } if (urmp->allow_mkcol) { if (uwsgi_buffer_append(ub_allow, ", MKCOL", 7)) { uwsgi_buffer_destroy(ub_allow); goto end; } } uwsgi_response_add_header(wsgi_req, "Allow", 5, ub_allow->buf, ub_allow->pos); uwsgi_buffer_destroy(ub_allow); goto end; } // MKCOL does not require stat if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "MKCOL", 5)) { if (!urmp->allow_mkcol) { uwsgi_405(wsgi_req); goto end; } ret = rados_pool_create(urmp->cluster, filename); if (ret < 0) { if (ret == -EEXIST) { uwsgi_405(wsgi_req); } else { uwsgi_500(wsgi_req); } goto end; } uwsgi_response_prepare_headers(wsgi_req, "201 Created", 11); goto end; } if (uwsgi.async > 1) { ret = uwsgi_rados_async_stat(urio, ctx, filename, &stat_size, &stat_mtime, timeout); } else { ret = rados_stat(ctx, filename, &stat_size, &stat_mtime); } // PUT AND MKCOL can be used for non-existent objects if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PUT", 3)) { if (!urmp->allow_put) { uwsgi_405(wsgi_req); goto end; } if (ret == 0) { if (uwsgi_rados_delete(wsgi_req, ctx, filename, timeout)) { uwsgi_500(wsgi_req); goto end; } } if (uwsgi_rados_put(wsgi_req, ctx, filename, timeout)) { uwsgi_500(wsgi_req); goto end; } uwsgi_response_prepare_headers(wsgi_req, "201 Created", 11); goto end; } else if (ret < 0) { if (ret == -ENOENT) uwsgi_404(wsgi_req); else uwsgi_403(wsgi_req); goto end; } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "DELETE", 6)) { if (!urmp->allow_delete) { uwsgi_405(wsgi_req); goto end; } if (uwsgi_rados_delete(wsgi_req, ctx, filename, timeout)) { uwsgi_403(wsgi_req); goto end; } uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6); goto end; } if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4) && uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "GET", 3)) { uwsgi_405(wsgi_req); goto end; } if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end; size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(wsgi_req->path_info, wsgi_req->path_info_len, &mime_type_len); if (mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end; } if (uwsgi_response_add_last_modified(wsgi_req, (uint64_t) stat_mtime)) goto end; if (uwsgi_response_add_content_length(wsgi_req, stat_size)) goto end; // skip body on HEAD if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) { size_t remains = stat_size; if (uwsgi.async > 1) { if (uwsgi_rados_read_async(wsgi_req, ctx, filename, remains, timeout)) goto end; } else { if (uwsgi_rados_read_sync(wsgi_req, ctx, filename, remains)) goto end; } } end: if (uwsgi.async > 1) { close(urio->fds[0]); close(urio->fds[1]); } return UWSGI_OK; } struct uwsgi_plugin rados_plugin = { .name = "rados", .modifier1 = 28, .options = uwsgi_rados_options, .post_fork = uwsgi_rados_setup, .request = uwsgi_rados_request, .after_request = log_request, }; uwsgi-2.0.29/plugins/rados/uwsgiplugin.py000066400000000000000000000001311477626554400205010ustar00rootroot00000000000000import os NAME='rados' CFLAGS = [] LDFLAGS = [] LIBS = ['-lrados'] GCC_LIST = ['rados'] uwsgi-2.0.29/plugins/rawrouter/000077500000000000000000000000001477626554400165015ustar00rootroot00000000000000uwsgi-2.0.29/plugins/rawrouter/rawrouter.c000066400000000000000000000234501477626554400207030ustar00rootroot00000000000000/* uWSGI rawrouter */ #include "../../uwsgi.h" #include "../corerouter/cr.h" static struct uwsgi_rawrouter { struct uwsgi_corerouter cr; int xclient; } urr; extern struct uwsgi_server uwsgi; struct rawrouter_session { struct corerouter_session session; // XCLIENT ADDR=xxx\r\n struct uwsgi_buffer *xclient; size_t xclient_pos; // placeholder for \r\n size_t xclient_rn; }; static struct uwsgi_option rawrouter_options[] = { {"rawrouter", required_argument, 0, "run the rawrouter on the specified port", uwsgi_opt_undeferred_corerouter, &urr, 0}, {"rawrouter-processes", required_argument, 0, "prefork the specified number of rawrouter processes", uwsgi_opt_set_int, &urr.cr.processes, 0}, {"rawrouter-workers", required_argument, 0, "prefork the specified number of rawrouter processes", uwsgi_opt_set_int, &urr.cr.processes, 0}, {"rawrouter-zerg", required_argument, 0, "attach the rawrouter to a zerg server", uwsgi_opt_corerouter_zerg, &urr, 0}, {"rawrouter-use-cache", optional_argument, 0, "use uWSGI cache as hostname->server mapper for the rawrouter", uwsgi_opt_set_str, &urr.cr.use_cache, 0}, {"rawrouter-use-pattern", required_argument, 0, "use a pattern for rawrouter hostname->server mapping", uwsgi_opt_corerouter_use_pattern, &urr, 0}, {"rawrouter-use-base", required_argument, 0, "use a base dir for rawrouter hostname->server mapping", uwsgi_opt_corerouter_use_base, &urr, 0}, {"rawrouter-fallback", required_argument, 0, "fallback to the specified node in case of error", uwsgi_opt_add_string_list, &urr.cr.fallback, 0}, {"rawrouter-use-code-string", required_argument, 0, "use code string as hostname->server mapper for the rawrouter", uwsgi_opt_corerouter_cs, &urr, 0}, {"rawrouter-use-socket", optional_argument, 0, "forward request to the specified uwsgi socket", uwsgi_opt_corerouter_use_socket, &urr, 0}, {"rawrouter-to", required_argument, 0, "forward requests to the specified uwsgi server (you can specify it multiple times for load balancing)", uwsgi_opt_add_string_list, &urr.cr.static_nodes, 0}, {"rawrouter-gracetime", required_argument, 0, "retry connections to dead static nodes after the specified amount of seconds", uwsgi_opt_set_int, &urr.cr.static_node_gracetime, 0}, {"rawrouter-events", required_argument, 0, "set the maximum number of concurrent events", uwsgi_opt_set_int, &urr.cr.nevents, 0}, {"rawrouter-max-retries", required_argument, 0, "set the maximum number of retries/fallbacks to other nodes", uwsgi_opt_set_int, &urr.cr.max_retries, 0}, {"rawrouter-quiet", required_argument, 0, "do not report failed connections to instances", uwsgi_opt_true, &urr.cr.quiet, 0}, {"rawrouter-cheap", no_argument, 0, "run the rawrouter in cheap mode", uwsgi_opt_true, &urr.cr.cheap, 0}, {"rawrouter-subscription-server", required_argument, 0, "run the rawrouter subscription server on the spcified address", uwsgi_opt_corerouter_ss, &urr, 0}, {"rawrouter-subscription-slot", required_argument, 0, "*** deprecated ***", uwsgi_opt_deprecated, (void *) "useless thanks to the new implementation", 0}, {"rawrouter-timeout", required_argument, 0, "set rawrouter timeout", uwsgi_opt_set_int, &urr.cr.socket_timeout, 0}, {"rawrouter-stats", required_argument, 0, "run the rawrouter stats server", uwsgi_opt_set_str, &urr.cr.stats_server, 0}, {"rawrouter-stats-server", required_argument, 0, "run the rawrouter stats server", uwsgi_opt_set_str, &urr.cr.stats_server, 0}, {"rawrouter-ss", required_argument, 0, "run the rawrouter stats server", uwsgi_opt_set_str, &urr.cr.stats_server, 0}, {"rawrouter-harakiri", required_argument, 0, "enable rawrouter harakiri", uwsgi_opt_set_int, &urr.cr.harakiri, 0}, {"rawrouter-xclient", no_argument, 0, "use the xclient protocol to pass the client addres", uwsgi_opt_true, &urr.xclient, 0}, {"rawrouter-buffer-size", required_argument, 0, "set internal buffer size (default: page size)", uwsgi_opt_set_64bit, &urr.cr.buffer_size, 0}, {0, 0, 0, 0, 0, 0, 0}, }; // write to backend static ssize_t rr_instance_write(struct corerouter_peer *peer) { ssize_t len = cr_write(peer, "rr_instance_write()"); // end on empty write if (!len) return 0; // the chunk has been sent, start (again) reading from client and instances if (cr_write_complete(peer)) { // reset the buffer peer->out->pos = 0; cr_reset_hooks(peer); } return len; } // write to client static ssize_t rr_write(struct corerouter_peer *main_peer) { ssize_t len = cr_write(main_peer, "rr_write()"); // end on empty write if (!len) return 0; // ok this response chunk is sent, let's start reading again if (cr_write_complete(main_peer)) { // reset the buffer main_peer->out->pos = 0; cr_reset_hooks(main_peer); } return len; } // read from backend static ssize_t rr_instance_read(struct corerouter_peer *peer) { ssize_t len = cr_read(peer, "rr_instance_read()"); if (!len) return 0; // set the input buffer as the main output one peer->session->main_peer->out = peer->in; peer->session->main_peer->out_pos = 0; cr_write_to_main(peer, rr_write); return len; } // write the xclient banner static ssize_t rr_xclient_write(struct corerouter_peer *peer) { struct corerouter_session *cs = peer->session; struct rawrouter_session *rr = (struct rawrouter_session *) cs; ssize_t len = cr_write_buf(peer, rr->xclient, "rr_xclient_write()"); if (!len) return 0; if (cr_write_complete_buf(peer, rr->xclient)) { if (peer->session->main_peer->out_pos > 0) { // (eventually) send previous data peer->last_hook_read = rr_instance_read; cr_write_to_main(peer, rr_write); } else { // reset to standard behaviour peer->in->pos = 0; cr_reset_hooks_and_read(peer, rr_instance_read); } } return len; } // read the first line from the backend and skip it static ssize_t rr_xclient_read(struct corerouter_peer *peer) { struct corerouter_session *cs = peer->session; struct rawrouter_session *rr = (struct rawrouter_session *) cs; ssize_t len = cr_read(peer, "rr_xclient_read()"); if (!len) return 0; char *ptr = (peer->in->buf + peer->in->pos) - len; ssize_t i; for(i=0;ixclient_rn == 1) { if (ptr[i] != '\n') { return -1; } // banner received (skip it, will be sent later) size_t remains = len - (i+1); if (remains > 0) { peer->session->main_peer->out = peer->in; peer->session->main_peer->out_pos = (peer->in->pos - remains) ; } cr_write_to_backend(peer, rr_xclient_write); return len; } else if (ptr[i] == '\r') { rr->xclient_rn = 1; } } return len; } // the instance is connected now we cannot retry connections static ssize_t rr_instance_connected(struct corerouter_peer *peer) { struct corerouter_session *cs = peer->session; struct rawrouter_session *rr = (struct rawrouter_session *) cs; cr_peer_connected(peer, "rr_instance_connected()"); peer->can_retry = 0; if (rr->xclient) { cr_reset_hooks_and_read(peer, rr_xclient_read); return 1; } cr_reset_hooks_and_read(peer, rr_instance_read); return 1; } // read from client static ssize_t rr_read(struct corerouter_peer *main_peer) { ssize_t len = cr_read(main_peer, "rr_read()"); if (!len) return 0; main_peer->session->peers->out = main_peer->in; main_peer->session->peers->out_pos = 0; cr_write_to_backend(main_peer->session->peers, rr_instance_write); return len; } // retry the connection static int rr_retry(struct corerouter_peer *peer) { struct corerouter_session *cs = peer->session; struct uwsgi_corerouter *ucr = cs->corerouter; if (peer->instance_address_len > 0) goto retry; if (ucr->mapper(ucr, peer)) { return -1; } if (peer->instance_address_len == 0) { return -1; } retry: // start async connect (again) cr_connect(peer, rr_instance_connected); return 0; } static void rr_session_close(struct corerouter_session *cs) { struct rawrouter_session *rr = (struct rawrouter_session *) cs; if (rr->xclient) { uwsgi_buffer_destroy(rr->xclient); } } // allocate a new session static int rawrouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket *ugs, struct corerouter_session *cs, struct sockaddr *sa, socklen_t s_len) { // set default read hook cs->main_peer->last_hook_read = rr_read; // set close hook cs->close = rr_session_close; // set retry hook cs->retry = rr_retry; if (sa && sa->sa_family == AF_INET) { if (urr.xclient) { struct rawrouter_session *rr = (struct rawrouter_session *) cs; rr->xclient = uwsgi_buffer_new(13+sizeof(cs->client_address)+2); if (uwsgi_buffer_append(rr->xclient, "XCLIENT ADDR=", 13)) return -1; if (uwsgi_buffer_append(rr->xclient, cs->client_address, strlen(cs->client_address))) return -1; if (uwsgi_buffer_append(rr->xclient, "\r\n", 2)) return -1; } } // add a new peer struct corerouter_peer *peer = uwsgi_cr_peer_add(cs); // set default peer hook peer->last_hook_read = rr_instance_read; // use the address as hostname memcpy(peer->key, cs->ugs->name, cs->ugs->name_len); peer->key_len = cs->ugs->name_len; // the mapper hook if (ucr->mapper(ucr, peer)) { return -1; } if (peer->instance_address_len == 0) { return -1; } peer->can_retry = 1; cr_connect(peer, rr_instance_connected); return 0; } static int rawrouter_init() { urr.cr.session_size = sizeof(struct rawrouter_session); urr.cr.alloc_session = rawrouter_alloc_session; uwsgi_corerouter_init((struct uwsgi_corerouter *) &urr); return 0; } static void rawrouter_setup() { urr.cr.name = uwsgi_str("uWSGI rawrouter"); urr.cr.short_name = uwsgi_str("rawrouter"); } struct uwsgi_plugin rawrouter_plugin = { .name = "rawrouter", .options = rawrouter_options, .init = rawrouter_init, .on_load = rawrouter_setup }; uwsgi-2.0.29/plugins/rawrouter/uwsgiplugin.py000066400000000000000000000001521477626554400214260ustar00rootroot00000000000000 NAME='rawrouter' CFLAGS = [] LDFLAGS = [] LIBS = [] REQUIRES = ['corerouter'] GCC_LIST = ['rawrouter'] uwsgi-2.0.29/plugins/rbthreads/000077500000000000000000000000001477626554400164255ustar00rootroot00000000000000uwsgi-2.0.29/plugins/rbthreads/rbthreads.c000066400000000000000000000142611477626554400205530ustar00rootroot00000000000000#include #include /* Author: Roberto De Ioris Why a loop engine ??? The ruby 1.9/2.x threading model is very unique First of all we cannot attach to already spawned pthread, for this reason the "rbthreads" loop engine must create pthreads with rb_thread_create() The second reason is for how the GVL is managed. We do not have functions (like in CPython) to explicitely release and acquire it. All happens via a function (rb_thread_call_without_gvl) calling the specified hook whenever the code blocks. Fortunately, thanks to the 1.9 async api, we can "patch" all of the server blocking parts with 2 simple hooks: uwsgi.wait_write_hook and uwsgi.wait_read_hook in addition to this we need to release the GVL in the accept() loop (but this is really easy) */ extern struct uwsgi_server uwsgi; /* for some strange reason, some version of ruby 1.9 does not expose this declaration... */ void *rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2); struct uwsgi_rbthreads { int rbthreads; int (*orig_wait_write_hook) (int, int); int (*orig_wait_read_hook) (int, int); int (*orig_wait_milliseconds_hook) (int); } urbts; static struct uwsgi_option rbthreads_options[] = { {"rbthreads", no_argument, 0, "enable ruby native threads", uwsgi_opt_true, &urbts.rbthreads, 0}, {"rb-threads", no_argument, 0, "enable ruby native threads", uwsgi_opt_true, &urbts.rbthreads, 0}, {"rbthread", no_argument, 0, "enable ruby native threads", uwsgi_opt_true, &urbts.rbthreads, 0}, {"rb-thread", no_argument, 0, "enable ruby native threads", uwsgi_opt_true, &urbts.rbthreads, 0}, { 0, 0, 0, 0, 0, 0, 0 } }; // this structure is passed between threads struct uwsgi_rbthread { int queue; int core_id; struct wsgi_request *wsgi_req; // return value int ret; // fd to monitor int fd; // non-blockign timeout int timeout; }; // this is called without the gvl static void * uwsgi_rb_thread_accept(void *arg) { struct uwsgi_rbthread *urbt = (struct uwsgi_rbthread *) arg; urbt->ret = 0; if (wsgi_req_accept(urbt->queue, urbt->wsgi_req)) { urbt->ret = -1; } return NULL; } static VALUE uwsgi_rb_thread_core(void *arg) { long core_id = (long) arg; struct wsgi_request *wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[core_id].req; uwsgi_setup_thread_req(core_id, wsgi_req); struct uwsgi_rbthread *urbt = uwsgi_malloc(sizeof(struct uwsgi_rbthread)); // initialize the main event queue to monitor sockets urbt->queue = event_queue_init(); urbt->wsgi_req = wsgi_req; uwsgi_add_sockets_to_queue(urbt->queue, (int)core_id); if (uwsgi.signal_socket > -1) { event_queue_add_fd_read(urbt->queue, uwsgi.signal_socket); event_queue_add_fd_read(urbt->queue, uwsgi.my_signal_socket); } // ok we are ready, let's start managing requests and signals while (uwsgi.workers[uwsgi.mywid].manage_next_request) { wsgi_req_setup(wsgi_req, (int)core_id, NULL); rb_thread_call_without_gvl(uwsgi_rb_thread_accept, urbt, NULL, NULL); // accept failed ? if (urbt->ret) continue; if (wsgi_req_recv(urbt->queue, wsgi_req)) { uwsgi_destroy_request(wsgi_req); continue; } uwsgi_close_request(wsgi_req); } return Qnil; } static void rbthread_noop0() { } static void rbthread_noop(int core_id) { } static void *rbthreads_wait_fd_write_do(void *arg) { struct uwsgi_rbthread *urbt = (struct uwsgi_rbthread *) arg; urbt->ret = urbts.orig_wait_write_hook(urbt->fd, urbt->timeout); return NULL; } static int rbthreads_wait_fd_write(int fd, int timeout) { struct uwsgi_rbthread urbt; urbt.fd = fd; urbt.timeout = timeout; rb_thread_call_without_gvl(rbthreads_wait_fd_write_do, &urbt, NULL, NULL); return urbt.ret; } static void *rbthreads_wait_fd_read_do(void *arg) { struct uwsgi_rbthread *urbt = (struct uwsgi_rbthread *) arg; urbt->ret = urbts.orig_wait_read_hook(urbt->fd, urbt->timeout); return NULL; } static int rbthreads_wait_fd_read(int fd, int timeout) { struct uwsgi_rbthread urbt; urbt.fd = fd; urbt.timeout = timeout; rb_thread_call_without_gvl(rbthreads_wait_fd_read_do, &urbt, NULL, NULL); return urbt.ret; } static void *rbthreads_wait_milliseconds_do(void *arg) { struct uwsgi_rbthread *urbt = (struct uwsgi_rbthread *) arg; urbt->ret = urbts.orig_wait_milliseconds_hook(urbt->timeout); return NULL; } static int rbthreads_wait_milliseconds(int timeout) { struct uwsgi_rbthread urbt; urbt.timeout = timeout; rb_thread_call_without_gvl(rbthreads_wait_milliseconds_do, &urbt, NULL, NULL); return urbt.ret; } static void rbthreads_loop() { struct uwsgi_plugin *rup = uwsgi_plugin_get("rack"); // disable init_thread warning if (rup) { rup->init_thread = rbthread_noop; } // override read/write nb hooks urbts.orig_wait_write_hook = uwsgi.wait_write_hook; urbts.orig_wait_read_hook = uwsgi.wait_read_hook; urbts.orig_wait_milliseconds_hook = uwsgi.wait_milliseconds_hook; uwsgi.wait_write_hook = rbthreads_wait_fd_write; uwsgi.wait_read_hook = rbthreads_wait_fd_read; uwsgi.wait_milliseconds_hook = rbthreads_wait_milliseconds; int i; for(i=1;ienable_threads = rbthread_noop0; } // set loop engine uwsgi.loop = "rbthreads"; } return 0; } struct uwsgi_plugin rbthreads_plugin = { .name = "rbthreads", .on_load = rbthreads_setup, .init = rbthreads_init, .options = rbthreads_options, }; uwsgi-2.0.29/plugins/rbthreads/uwsgiplugin.py000066400000000000000000000023571477626554400213630ustar00rootroot00000000000000import os NAME='rbthreads' try: RUBYPATH = os.environ['UWSGICONFIG_RUBYPATH'] except: RUBYPATH = 'ruby' CFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print RbConfig::CONFIG['CFLAGS']\"").read().rstrip().split() CFLAGS.append('-DRUBY19') CFLAGS.append('-Wno-unused-parameter') rbconfig = 'RbConfig' includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['rubyhdrdir']\"" % rbconfig).read().rstrip() if includedir == 'nil': includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['archdir']\"" % rbconfig).read().rstrip() CFLAGS.append('-I' + includedir) else: CFLAGS.append('-I' + includedir) archdir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['archdir']\"" % rbconfig).read().rstrip() arch = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['arch']\"" % rbconfig).read().rstrip() CFLAGS.append('-I' + archdir) CFLAGS.append('-I' + archdir + '/' + arch) CFLAGS.append('-I' + includedir + '/' + arch) archdir2 = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['rubyarchhdrdir']\"" % rbconfig).read().rstrip() if archdir2: CFLAGS.append('-I' + archdir2) LDFLAGS = [] LIBS = [] GCC_LIST = ['rbthreads'] uwsgi-2.0.29/plugins/redislog/000077500000000000000000000000001477626554400162575ustar00rootroot00000000000000uwsgi-2.0.29/plugins/redislog/redislog_plugin.c000066400000000000000000000125461477626554400216210ustar00rootroot00000000000000#include extern struct uwsgi_server uwsgi; struct uwsgi_redislog_state { int fd; char *password; char *address; char *id; char *command; char *prefix; char msgsize[11]; struct iovec iovec[7]; char response[8]; }; static char *uwsgi_redis_logger_build_command(char *src) { ssize_t len = 4096; char *dst = uwsgi_calloc(len); char *orig_dst = dst; int count = 2; char *ptr = src; // first of all, count the number of spaces while(*ptr++) { if (*ptr == ' ') count++; } int pos = snprintf(dst, 4096, "*%d\r\n", count); dst+=pos; len -= pos; ptr = src; char *base = src; while(*ptr++) { if (*ptr == ' ') { pos = snprintf(dst, len, "$%d\r\n%.*s\r\n", (int) (ptr-base), (int) (ptr-base), base); if (pos >= len || pos < 0) { // i do not know what to do, better to exit... exit(1); } base = ptr+1; dst+=pos; len-= pos; } } pos = snprintf(dst, len, "$%d\r\n%.*s\r\n", (int) ((ptr-1)-base), (int) ((ptr-1)-base), base); if (pos > len || pos < 0) { // i do not know what to do, better to exit... exit(1); } return orig_dst; } static ssize_t uwsgi_redis_logger_discard_response(struct uwsgi_redislog_state *uredislog) { ssize_t ret = 0, ret2; again: // read til a \n is found (ugly but fast) ret2 = read(uredislog->fd, uredislog->response, 8); if (ret2 <= 0) { close(uredislog->fd); uredislog->fd = -1; return -1; } ret += ret2; if (!memchr(uredislog->response, '\n', ret2)) { goto again; } return ret; } ssize_t uwsgi_redis_logger(struct uwsgi_logger *ul, char *message, size_t len) { ssize_t ret; struct uwsgi_redislog_state *uredislog = NULL; if (!ul->configured) { if (!ul->data) { ul->data = uwsgi_calloc(sizeof(struct uwsgi_redislog_state)); uredislog = (struct uwsgi_redislog_state *) ul->data; } if (ul->arg != NULL) { char *logarg = uwsgi_str(ul->arg); char *at = strchr(logarg, '@'); if (at) { *at = 0; uredislog->password = logarg; logarg = at + 1; } char *comma1 = strchr(logarg, ','); if (!comma1) { char *slash = strchr(logarg, '/'); if (slash) { *slash = 0; uredislog->id = slash + 1; } uredislog->address = uwsgi_resolve_ip(logarg); goto done; } *comma1 = 0; char *slash = strchr(logarg, '/'); if (slash) { *slash = 0; uredislog->id = slash + 1; } uredislog->address = logarg; comma1++; if (*comma1 == 0) goto done; char *comma2 = strchr(comma1,','); if (!comma2) { uredislog->command = uwsgi_redis_logger_build_command(comma1); goto done; } *comma2 = 0; uredislog->command = uwsgi_redis_logger_build_command(comma1); comma2++; if (*comma2 == 0) goto done; uredislog->prefix = comma2; } done: if (!uredislog->password) uredislog->password = NULL; if (!uredislog->id) uredislog->id = "0"; if (!uredislog->address) uredislog->address = uwsgi_str("127.0.0.1:6379"); if (!uredislog->command) uredislog->command = "*3\r\n$7\r\npublish\r\n$5\r\nuwsgi\r\n"; if (!uredislog->prefix) uredislog->prefix = ""; uredislog->fd = -1; uredislog->iovec[0].iov_base = uredislog->command; uredislog->iovec[0].iov_len = strlen(uredislog->command); uredislog->iovec[1].iov_base = "$"; uredislog->iovec[1].iov_len = 1; uredislog->iovec[2].iov_base = uredislog->msgsize; uredislog->iovec[3].iov_base = "\r\n"; uredislog->iovec[3].iov_len = 2; uredislog->iovec[4].iov_base = uredislog->prefix; uredislog->iovec[4].iov_len = strlen(uredislog->prefix); uredislog->iovec[6].iov_base = "\r\n"; uredislog->iovec[6].iov_len = 2; ul->configured = 1; } uredislog = (struct uwsgi_redislog_state *) ul->data; if (uredislog->fd == -1) { struct iovec setup_iov; char setup_buf[4096]; uredislog->fd = uwsgi_connect(uredislog->address, uwsgi.socket_timeout, 0); if (uredislog->password) { setup_iov.iov_len = snprintf( setup_buf, sizeof (setup_buf), "*2\r\n$4\r\nauth\r\n$%zu\r\n%*s\r\n", strlen(uredislog->password), (int)strlen(uredislog->password), uredislog->password); setup_iov.iov_base = setup_buf; ret = writev(uredislog->fd, &setup_iov, 1); if (ret <= 0) { close(uredislog->fd); uredislog->fd = -1; return -1; } uwsgi_redis_logger_discard_response(uredislog); } if (uredislog->id) { setup_iov.iov_len = snprintf( setup_buf, sizeof (setup_buf), "*2\r\n$6\r\nselect\r\n$%zu\r\n%*s\r\n", strlen(uredislog->id), (int)strlen(uredislog->id), uredislog->id); setup_iov.iov_base = setup_buf; ret = writev(uredislog->fd, &setup_iov, 1); if (ret <= 0) { close(uredislog->fd); uredislog->fd = -1; return -1; } uwsgi_redis_logger_discard_response(uredislog); } } if (uredislog->fd == -1) return -1; // drop newline if (message[len-1] == '\n') len--; uwsgi_num2str2(len + uredislog->iovec[4].iov_len, uredislog->msgsize); uredislog->iovec[2].iov_len = strlen(uredislog->msgsize); uredislog->iovec[5].iov_base = message; uredislog->iovec[5].iov_len = len; ret = writev(uredislog->fd, uredislog->iovec, 7); if (ret <= 0) { close(uredislog->fd); uredislog->fd = -1; return -1; } uwsgi_redis_logger_discard_response(uredislog); return ret; } void uwsgi_redislog_register() { uwsgi_register_logger("redislog", uwsgi_redis_logger); } struct uwsgi_plugin redislog_plugin = { .name = "redislog", .on_load = uwsgi_redislog_register, }; uwsgi-2.0.29/plugins/redislog/uwsgiplugin.py000066400000000000000000000001231477626554400212020ustar00rootroot00000000000000NAME='redislog' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['redislog_plugin'] uwsgi-2.0.29/plugins/ring/000077500000000000000000000000001477626554400154065ustar00rootroot00000000000000uwsgi-2.0.29/plugins/ring/ring_plugin.c000066400000000000000000000344211477626554400200730ustar00rootroot00000000000000#include /* Clojure/ring JVM handler to run a ring app you need to load the clojure jar, a clojure script and specify a namspace:handler app ./uwsgi --http :9090 --http-modifier1 8 --http-modifier2 1 --jvm-classpath clojuretest/lib/clojure-1.3.0.jar --ring-load clojuretest/src/clojuretest/core.clj --ring-app clojuretest.core:handler TODO app mountpoints check if loading compiled classes works */ #define UWSGI_JVM_REQUEST_HANDLER_RING 1 extern struct uwsgi_jvm ujvm; struct uwsgi_ring { struct uwsgi_string_list *scripts; char *app; jobject handler; jobject keyword; jobject into; // invoke with 1 arg jmethodID invoke1; // invoke with 2 args jmethodID invoke2; jclass Associative; jclass PersistentArrayMap; } uring; static struct uwsgi_option uwsgi_ring_options[] = { {"ring-load", required_argument, 0, "load the specified clojure script", uwsgi_opt_add_string_list, &uring.scripts, 0}, {"clojure-load", required_argument, 0, "load the specified clojure script", uwsgi_opt_add_string_list, &uring.scripts, 0}, {"ring-app", required_argument, 0, "map the specified ring application (syntax namespace:function)", uwsgi_opt_set_str, &uring.app, 0}, {0, 0, 0, 0}, }; static jobject uwsgi_ring_invoke1(jobject o, jobject arg1) { return uwsgi_jvm_call_object(o, uring.invoke1, arg1); } static jobject uwsgi_ring_invoke2(jobject o, jobject arg1, jobject arg2) { return uwsgi_jvm_call_object(o, uring.invoke2, arg1, arg2); } // here we create a PersistentArrayMap empty object (we use that for clojure "into") static jobject uwsgi_ring_associative() { // optimization static jmethodID mid = 0; if (!mid) { mid = uwsgi_jvm_get_method_id(uring.PersistentArrayMap, "", "()V"); if (!mid) return NULL; } jobject o = (*ujvm_env)->NewObject(ujvm_env, uring.PersistentArrayMap, mid); if (uwsgi_jvm_exception()) { return NULL; } return o; } // create a new clojure keyword static jobject uwsgi_ring_keyword(char *key, size_t len) { jobject j_key = uwsgi_jvm_str(key, len); if (!j_key) return NULL; jobject kw = uwsgi_ring_invoke1(uring.keyword, j_key); uwsgi_jvm_local_unref(j_key); return kw; } // add a string item to the ring request map static int uwsgi_ring_request_item_add(jobject hm, char *key, size_t keylen, char *value, size_t vallen) { jobject j_key = uwsgi_ring_keyword(key, keylen); if (!j_key) return -1; jobject j_value = uwsgi_jvm_str(value, vallen); if (!j_value) { uwsgi_jvm_local_unref(j_key); return -1; } int ret = uwsgi_jvm_hashmap_put(hm, j_key, j_value); uwsgi_jvm_local_unref(j_key); uwsgi_jvm_local_unref(j_value); return ret; } static int uwsgi_ring_request_item_add_body(jobject hm, char *key, size_t keylen) { jobject j_key = uwsgi_ring_keyword(key, keylen); if (!j_key) return -1; jobject j_value = uwsgi_jvm_request_body_input_stream(); if (!j_value) { uwsgi_jvm_local_unref(j_key); return -1; } int ret = uwsgi_jvm_hashmap_put(hm, j_key, j_value); uwsgi_jvm_local_unref(j_key); uwsgi_jvm_local_unref(j_value); return ret; } // add a keyword item to the ring request map static int uwsgi_ring_request_item_add_keyword(jobject hm, char *key, size_t keylen, char *value, size_t vallen) { jobject j_key = uwsgi_ring_keyword(key, keylen); if (!j_key) return -1; char *lc_value = uwsgi_malloc(vallen); char *ptr = lc_value; size_t i; for(i=0;imethod, wsgi_req->method_len)) goto end; if (uwsgi_ring_request_item_add(hm, "uri", 3, wsgi_req->path_info, wsgi_req->path_info_len)) goto end; if (uwsgi_ring_request_item_add(hm, "server-name", 11, wsgi_req->host, wsgi_req->host_len)) goto end; // server-port is required !!! uint16_t server_port_len = 0; char *server_port = uwsgi_get_var(wsgi_req, "SERVER_PORT", 11, &server_port_len); if (!server_port) goto end; if (uwsgi_ring_request_item_add_num(hm, "server-port", 11, uwsgi_str_num(server_port, server_port_len))) goto end; if (wsgi_req->scheme_len > 0) { if (uwsgi_ring_request_item_add_keyword(hm, "scheme", 6, wsgi_req->scheme, wsgi_req->scheme_len)) goto end; } else { if (uwsgi_ring_request_item_add_keyword(hm, "scheme", 6, "http", 4)) goto end; } if (uwsgi_ring_request_item_add(hm, "remote-addr", 11, wsgi_req->remote_addr, wsgi_req->remote_addr_len)) goto end; if (wsgi_req->query_string_len > 0) { if (uwsgi_ring_request_item_add(hm, "query-string", 12, wsgi_req->query_string, wsgi_req->query_string_len)) goto end; } if (wsgi_req->content_type_len) { if (uwsgi_ring_request_item_add(hm, "content-type", 12, wsgi_req->content_type, wsgi_req->content_type_len)) goto end; } if (wsgi_req->post_cl > 0) { if (uwsgi_ring_request_item_add_num(hm, "content-length", 14, wsgi_req->post_cl)) goto end; } // generate :headers jobject req_headers = uwsgi_jvm_hashmap(); if (!req_headers) goto end; int i; for(i=0;ivar_cnt;i++) { char *hk = wsgi_req->hvec[i].iov_base; uint16_t hk_l = wsgi_req->hvec[i].iov_len; char *hv = wsgi_req->hvec[i+1].iov_base; uint16_t hv_l = wsgi_req->hvec[i+1].iov_len; if (!uwsgi_starts_with(hk, hk_l, "HTTP_", 5)) { if (uwsgi_ring_request_header_add(req_headers,hk+5,hk_l-5, hv, hv_l)) goto hend; } else if (!uwsgi_strncmp(hk, hk_l, "CONTENT_TYPE", 12)) { if (uwsgi_ring_request_header_add(req_headers,hk,hk_l, hv, hv_l)) goto hend; } else if (!uwsgi_strncmp(hk, hk_l, "CONTENT_LENGTH", 14)) { if (uwsgi_ring_request_header_add(req_headers, hk,hk_l, hv, hv_l)) goto hend; } i++; } jobject h_empty_request = uwsgi_ring_associative(); if (!h_empty_request) goto hend; // convert the req_headers HashMap to Associative jobject clj_req_headers = uwsgi_ring_invoke2(uring.into, h_empty_request, req_headers); if (!clj_req_headers) { uwsgi_jvm_local_unref(h_empty_request); goto hend; } uwsgi_jvm_local_unref(h_empty_request); // add :headers if (uwsgi_ring_request_item_add_obj(hm, "headers", 7, clj_req_headers)) { uwsgi_jvm_local_unref(clj_req_headers); hend: uwsgi_jvm_local_unref(req_headers); goto end; } uwsgi_jvm_local_unref(clj_req_headers); uwsgi_jvm_local_unref(req_headers); // add :body input stream if (uwsgi_ring_request_item_add_body(hm, "body", 4)) goto end; // *** END OF REQUEST GENERATION *** // convert the HashMap to Associative request = uwsgi_ring_invoke2(uring.into, empty_request, hm); if (!request) goto end; response = uwsgi_ring_invoke1(uring.handler, request); if (!response) goto end; if (!uwsgi_jvm_object_is_instance(response, uring.Associative)) { uwsgi_log("invalid ring response type, need to implement: clojure.lang.Associative\n"); goto end; } r_status = uwsgi_ring_response_get(response, "status", 6); if (!r_status) goto end; if (!uwsgi_jvm_object_is_instance(r_status, ujvm.long_class) && !uwsgi_jvm_object_is_instance(r_status, ujvm.int_class)) { uwsgi_log("invalid ring response status type, must be: java.lang.Long\n"); goto end; } long n_status = uwsgi_jvm_number2c(r_status); if (n_status == -1) goto end; if (uwsgi_num2str2(n_status, status_str) != 3) { goto end; } if (uwsgi_response_prepare_headers(wsgi_req, status_str, 3)) goto end; r_headers = uwsgi_ring_response_get(response, "headers", 7); if (!r_headers) goto end; if (!uwsgi_jvm_object_is_instance(r_headers, uring.Associative)) { uwsgi_log("invalid ring response headers type, need to implement: clojure.lang.Associative\n"); goto end; } entries = uwsgi_ring_Associative_iterator(r_headers); if (!entries) goto end; if (uwsgi_jvm_iterator_to_response_headers(wsgi_req, entries)) { goto end; } r_body = uwsgi_ring_response_get(response, "body", 4); if (!r_body) goto end; if (uwsgi_jvm_object_to_response_body(wsgi_req, r_body)) { uwsgi_log("unsupported clojure/ring body type\n"); } end: // destroy the request map and the response uwsgi_jvm_local_unref(hm); uwsgi_jvm_local_unref(empty_request); if (request) { uwsgi_jvm_local_unref(request); } if (entries) { uwsgi_jvm_local_unref(entries); } if (r_status) { uwsgi_jvm_local_unref(r_status); } if (r_headers) { uwsgi_jvm_local_unref(r_headers); } if (r_body) { uwsgi_jvm_local_unref(r_body); } if (response) { uwsgi_jvm_local_unref(response); } return UWSGI_OK; } static int uwsgi_ring_setup() { uwsgi_log("loading clojure environment...\n"); jclass clojure = uwsgi_jvm_class("clojure/lang/RT"); if (!clojure) { exit(1); } jclass clojure_var_class = uwsgi_jvm_class("clojure/lang/Var"); if (!clojure_var_class) { exit(1); } uring.Associative = uwsgi_jvm_class("clojure/lang/Associative"); if (!uring.Associative) { exit(1); } // we use that for allocating the empty associative passed to "into" uring.PersistentArrayMap = uwsgi_jvm_class("clojure/lang/PersistentArrayMap"); if (!uring.PersistentArrayMap) { exit(1); } jmethodID clojure_loadresourcescript = uwsgi_jvm_get_static_method_id(clojure, "loadResourceScript", "(Ljava/lang/String;)V"); if (!clojure_loadresourcescript) { exit(1); } struct uwsgi_string_list *usl = uring.scripts; while(usl) { if (uwsgi_jvm_call_static(clojure, clojure_loadresourcescript, uwsgi_jvm_str(usl->value, 0))) { exit(1); } usl = usl->next; } jmethodID clojure_var = uwsgi_jvm_get_static_method_id(clojure, "var", "(Ljava/lang/String;Ljava/lang/String;)Lclojure/lang/Var;"); if (!clojure_var) { exit(1); } uring.keyword = uwsgi_jvm_call_object_static(clojure, clojure_var, uwsgi_jvm_str("clojure.core", 0), uwsgi_jvm_str("keyword", 0)); if (!uring.keyword) { exit(1); } uring.into = uwsgi_jvm_call_object_static(clojure, clojure_var, uwsgi_jvm_str("clojure.core", 0), uwsgi_jvm_str("into", 0)); if (!uring.into) { exit(1); } char *namespace = uwsgi_str(uring.app); char *colon = strchr(namespace, '/'); if (!colon) { colon = strchr(namespace, ':'); if (!colon) { uwsgi_log("invalid ring application namespace/handler\n"); exit(1); } } *colon = 0; uring.handler = uwsgi_jvm_call_object_static(clojure, clojure_var, uwsgi_jvm_str(namespace, 0), uwsgi_jvm_str(colon+1, 0)); if (!uring.handler) { exit(1); } uring.invoke1 = uwsgi_jvm_get_method_id(clojure_var_class, "invoke", "(Ljava/lang/Object;)Ljava/lang/Object;"); if (!uring.invoke1) { exit(1); } uring.invoke2 = uwsgi_jvm_get_method_id(clojure_var_class, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); if (!uring.invoke2) { exit(1); } uwsgi_log("clojure/ring app loaded\n"); return 0; } static int uwsgi_ring_init() { if (!uring.app) return 0; if (uwsgi_jvm_register_request_handler(UWSGI_JVM_REQUEST_HANDLER_RING, uwsgi_ring_setup, uwsgi_ring_request)) { exit(1); } return 0; } struct uwsgi_plugin ring_plugin = { .name = "ring", .options = uwsgi_ring_options, .init = uwsgi_ring_init, }; uwsgi-2.0.29/plugins/ring/uwsgiplugin.py000066400000000000000000000012021477626554400203300ustar00rootroot00000000000000import os import shutil jvm_path = 'plugins/jvm' up = {} try: execfile('%s/uwsgiplugin.py' % jvm_path, up) except: f = open('%s/uwsgiplugin.py' % jvm_path) exec(f.read(), up) f.close() NAME='ring' CFLAGS = up['CFLAGS'] CFLAGS.append('-I%s' % jvm_path) LDFLAGS = [] LIBS = [] GCC_LIST = ['ring_plugin'] def post_build(config): env = os.environ.get('VIRTUAL_ENV') if env: plugin = "%s/ring_plugin.so" % os.getcwd() if os.path.exists(plugin): tgt = "%s/bin/ring_plugin.so" % env shutil.copyfile(plugin, tgt) print("*** ring_plugin.so had been copied to %s" % tgt) uwsgi-2.0.29/plugins/router_access/000077500000000000000000000000001477626554400173105ustar00rootroot00000000000000uwsgi-2.0.29/plugins/router_access/router_access.c000066400000000000000000000040751477626554400223230ustar00rootroot00000000000000#include "../../uwsgi.h" #include /* by Colin Ligertwood syntax: route = /^foobar access:action=hosts,daemon=uwsgi route = /^foobar access:action=allow,daemon=uwsgi,addr=127.0.0.1 route = /^foobar access:action=deny,daemon=uwsgi2,addr=192.168.* route = /^foobar access:action=deny,daemon=uwsgi3,addr=192.168.0.0/24 TODO only the 'hosts' action is supported */ struct uwsgi_router_access_conf { char *action; char *daemon; char *addr; }; static int uwsgi_routing_func_access(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ int pass = 0; struct uwsgi_router_access_conf *urac = (struct uwsgi_router_access_conf *) ur->data2; if (!urac) { urac = uwsgi_calloc(sizeof(struct uwsgi_router_access_conf)); if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=', "action", &urac->action, "daemon", &urac->daemon, "addr", &urac->addr, NULL)) { free(urac); goto forbidden; } if (!urac->action) urac->action = "hosts"; if (!urac->daemon) urac->action = "uwsgi"; ur->data2 = urac; } char *addr = uwsgi_concat2n(wsgi_req->remote_addr, wsgi_req->remote_addr_len, "", 0); if (!strcmp(urac->action, "hosts")){ pass = hosts_ctl(urac->daemon, STRING_UNKNOWN, addr, STRING_UNKNOWN); } else if (!strcmp(urac->action, "allow") && urac->addr){ // unimplemented } else if (!strcmp(urac->action, "deny") && urac->addr){ // unimplemented } free(addr); if (pass) return UWSGI_ROUTE_NEXT; forbidden: if (uwsgi_response_prepare_headers(wsgi_req, "403 Forbidden", 13)) goto end; if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) goto end; uwsgi_response_write_body_do(wsgi_req, "Forbidden", 9); end: return UWSGI_ROUTE_BREAK; } static int uwsgi_router_access(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_access; ur->data = args; ur->data_len = strlen(args); return 0; } static void router_access_register() { uwsgi_register_router("access", uwsgi_router_access); } struct uwsgi_plugin router_access_plugin = { .name = "router_access", .on_load = router_access_register, }; uwsgi-2.0.29/plugins/router_access/uwsgiplugin.py000066400000000000000000000001571477626554400222420ustar00rootroot00000000000000NAME='router_access' CFLAGS = [] LDFLAGS = [] LIBS = ['-lwrap'] REQUIRES = [''] GCC_LIST = ['router_access'] uwsgi-2.0.29/plugins/router_basicauth/000077500000000000000000000000001477626554400200125ustar00rootroot00000000000000uwsgi-2.0.29/plugins/router_basicauth/router_basicauth.c000066400000000000000000000124241477626554400235240ustar00rootroot00000000000000#include #ifdef UWSGI_ROUTING // TODO: Add more crypt_r supported platfroms here #if defined(__linux__) && defined(__GLIBC__) #include #elif defined(__CYGWIN__) #include pthread_mutex_t ur_basicauth_crypt_mutex; #else pthread_mutex_t ur_basicauth_crypt_mutex; #endif extern struct uwsgi_server uwsgi; static char *htpasswd_check_sha1(char *pwd) { #ifdef UWSGI_SSL char sha1[20]; uwsgi_sha1(pwd, strlen(pwd), sha1); size_t len = 0; char *b64 = uwsgi_base64_encode(sha1, 20, &len); if (!b64) return NULL; // we add a new line for being fgets-friendly char *crypted = uwsgi_concat3n("{SHA}", 5, b64, len, "\n", 1); free(b64); return crypted; #else uwsgi_log("*** WARNING, rebuild uWSGI with SSL support for htpasswd sha1 feature ***\n"); return NULL; #endif } static uint16_t htpasswd_check(char *filename, char *auth) { char line[1024]; char *colon = strchr(auth, ':'); if (!colon) return 0; FILE *htpasswd = fopen(filename, "r"); if (!htpasswd) { return 0; } while(fgets(line, 1024, htpasswd)) { char *crypted = NULL; int need_free = 0; char *colon2 = strchr(line, ':'); if (!colon2) break; char *cpwd = colon2+1; size_t clen = strlen(cpwd); // now we check which algo to use // {SHA} ? if (!uwsgi_starts_with(cpwd, clen, "{SHA}", 5)) { crypted = htpasswd_check_sha1(colon+1); if (crypted) need_free = 1; goto check; } if (clen < 13) break; if (clen > 13) cpwd[13] = 0; #if defined(__linux__) && defined(__GLIBC__) struct crypt_data cd; memset(&cd, 0, sizeof(struct crypt_data)); /* work around glibc-2.2.5 bug, * has been fixed at some time in glibc-2.3.X */ #if (__GLIBC__ == 2) && \ (defined(__GLIBC_MINOR__) && __GLIBC_MINOR__ >= 2 && __GLIBC_MINOR__ < 4) // we do as nginx here cd.current_salt[0] = ~cpwd[0]; #endif crypted = crypt_r( colon+1, cpwd, &cd); #else if (uwsgi.threads > 1) pthread_mutex_lock(&ur_basicauth_crypt_mutex); crypted = crypt( colon+1, cpwd); if (uwsgi.threads > 1) pthread_mutex_unlock(&ur_basicauth_crypt_mutex); #endif check: if (!crypted) continue; if (!strcmp( crypted, cpwd )) { if (!uwsgi_strncmp(auth, colon-auth, line, colon2-line)) { fclose(htpasswd); if (need_free) free(crypted); return colon-auth; } } if (need_free) free(crypted); } fclose(htpasswd); return 0; } static int uwsgi_routing_func_basicauth(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { // skip if already authenticated if (wsgi_req->remote_user_len > 0) { return UWSGI_ROUTE_NEXT; } if (wsgi_req->authorization_len > 7 && ur->data2_len > 0) { if (strncmp(wsgi_req->authorization, "Basic ", 6)) goto forbidden; size_t auth_len = 0; char *auth = uwsgi_base64_decode(wsgi_req->authorization+6, wsgi_req->authorization_len-6, &auth_len); if (auth) { if (!ur->custom) { // check htpasswd-like file uint16_t ulen = htpasswd_check(ur->data2, auth); if (ulen > 0) { wsgi_req->remote_user = uwsgi_req_append(wsgi_req, "REMOTE_USER", 11, auth, ulen); if (!wsgi_req->remote_user) { free(auth); goto forbidden; } wsgi_req->remote_user_len = ulen; } else if (ur->data3_len == 0) { free(auth); goto forbidden; } } else { if (!uwsgi_strncmp(auth, auth_len, ur->data2, ur->data2_len)) { wsgi_req->remote_user = uwsgi_req_append(wsgi_req, "REMOTE_USER", 11, auth, ur->custom); if (!wsgi_req->remote_user) { free(auth); goto forbidden; } wsgi_req->remote_user_len = ur->custom; } else if (ur->data3_len == 0) { free(auth); goto forbidden; } } free(auth); return UWSGI_ROUTE_NEXT; } } forbidden: if (uwsgi_response_prepare_headers(wsgi_req, "401 Authorization Required", 26)) goto end; char *realm = uwsgi_concat3n("Basic realm=\"", 13, ur->data, ur->data_len, "\"", 1); // no need to check for errors uwsgi_response_add_header(wsgi_req, "WWW-Authenticate", 16, realm, 13 + ur->data_len + 1); free(realm); uwsgi_response_write_body_do(wsgi_req, "Unauthorized", 12); end: return UWSGI_ROUTE_BREAK; } #ifndef __linux__ static void router_basicauth_init_lock() { pthread_mutex_init(&ur_basicauth_crypt_mutex, NULL); } #endif static int uwsgi_router_basicauth(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_basicauth; char *comma = strchr(args, ','); if (!comma) { uwsgi_log("invalid route syntax: %s\n", args); exit(1); } *comma = 0; char *colon = strchr(comma+1, ':'); // is an htpasswd-like file ? if (!colon) { ur->custom = 0; } else { ur->custom = colon-(comma+1); } ur->data = args; ur->data_len = strlen(args); ur->data2 = comma+1; ur->data2_len = strlen(ur->data2); return 0; } static int uwsgi_router_basicauth_next(struct uwsgi_route *ur, char *args) { ur->data3_len = 1; return uwsgi_router_basicauth(ur, args); } static void router_basicauth_register(void) { uwsgi_register_router("basicauth", uwsgi_router_basicauth); uwsgi_register_router("basicauth-next", uwsgi_router_basicauth_next); } struct uwsgi_plugin router_basicauth_plugin = { .name = "router_basicauth", .on_load = router_basicauth_register, #ifndef __linux__ .enable_threads = router_basicauth_init_lock, #endif }; #else struct uwsgi_plugin router_basicauth_plugin = { .name = "router_basicauth", }; #endif uwsgi-2.0.29/plugins/router_basicauth/uwsgiplugin.py000066400000000000000000000003311477626554400227360ustar00rootroot00000000000000import os NAME='router_basicauth' CFLAGS = [] LDFLAGS = [] LIBS = [] # osx and openbsd do not need libcrypt if os.uname()[0] not in ('Darwin', 'OpenBSD'): LIBS.append('-lcrypt') GCC_LIST = ['router_basicauth'] uwsgi-2.0.29/plugins/router_cache/000077500000000000000000000000001477626554400171125ustar00rootroot00000000000000uwsgi-2.0.29/plugins/router_cache/router_cache.c000066400000000000000000000471561477626554400217360ustar00rootroot00000000000000#include #ifdef UWSGI_ROUTING extern struct uwsgi_server uwsgi; /* by Unbit syntax: route = /^foobar1(.*)/ cache:key=foo$1poo,content_type=text/html,name=foobar */ struct uwsgi_router_cache_conf { // the name of the cache char *name; size_t name_len; char *key; size_t key_len; char *var; size_t var_len; char *value; size_t value_len; // use mime types ? char *mime; char *as_num; #ifdef UWSGI_ZLIB char *gzip; size_t gzip_len; #endif char *content_type; size_t content_type_len; char *content_encoding; size_t content_encoding_len; struct uwsgi_cache *cache; char *expires_str; uint64_t expires; int64_t default_num; uint64_t flags; char *status_str; int status; char *no_offload; char *no_cl; }; // this is allocated for each transformation struct uwsgi_transformation_cache_conf { struct uwsgi_buffer *cache_it; #ifdef UWSGI_ZLIB struct uwsgi_buffer *cache_it_gzip; #endif int status; struct uwsgi_buffer *value; struct uwsgi_buffer *cache_it_to; uint64_t cache_it_expires; }; static int transform_cache(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) { struct uwsgi_transformation_cache_conf *utcc = (struct uwsgi_transformation_cache_conf *) ut->data; struct uwsgi_buffer *ub = ut->chunk; // force value if (utcc->value) { ub = utcc->value; } // store only successfull response if (wsgi_req->write_errors == 0 && (wsgi_req->status == 200 || (utcc->status && wsgi_req->status == utcc->status)) && ub->pos > 0) { if (utcc->cache_it) { uwsgi_cache_magic_set(utcc->cache_it->buf, utcc->cache_it->pos, ub->buf, ub->pos, utcc->cache_it_expires, UWSGI_CACHE_FLAG_UPDATE, utcc->cache_it_to ? utcc->cache_it_to->buf : NULL); #ifdef UWSGI_ZLIB if (utcc->cache_it_gzip) { struct uwsgi_buffer *gzipped = uwsgi_gzip(ub->buf, ub->pos); if (gzipped) { uwsgi_cache_magic_set(utcc->cache_it_gzip->buf, utcc->cache_it_gzip->pos, gzipped->buf, gzipped->pos, utcc->cache_it_expires, UWSGI_CACHE_FLAG_UPDATE, utcc->cache_it_to ? utcc->cache_it_to->buf : NULL); uwsgi_buffer_destroy(gzipped); } } #endif } } // free resources if (utcc->cache_it) uwsgi_buffer_destroy(utcc->cache_it); #ifdef UWSGI_ZLIB if (utcc->cache_it_gzip) uwsgi_buffer_destroy(utcc->cache_it_gzip); #endif if (utcc->cache_it_to) uwsgi_buffer_destroy(utcc->cache_it_to); if (utcc->value) uwsgi_buffer_destroy(utcc->value); free(utcc); return 0; } // be tolerant on errors static int uwsgi_routing_func_cache_store(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2; struct uwsgi_transformation_cache_conf *utcc = uwsgi_calloc(sizeof(struct uwsgi_transformation_cache_conf)); // build key and name char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); utcc->cache_it = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len); if (!utcc->cache_it) goto error; if (urcc->name) { utcc->cache_it_to = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->name, urcc->name_len); if (!utcc->cache_it_to) goto error; } if (urcc->value) { utcc->value = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->value, urcc->value_len); if (!utcc->value) goto error; } utcc->status = urcc->status; #ifdef UWSGI_ZLIB if (urcc->gzip) { utcc->cache_it_gzip = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->gzip, urcc->gzip_len); if (!utcc->cache_it_gzip) goto error; } #endif utcc->cache_it_expires = urcc->expires; uwsgi_add_transformation(wsgi_req, transform_cache, utcc); return UWSGI_ROUTE_NEXT; error: if (utcc->cache_it) uwsgi_buffer_destroy(utcc->cache_it); #ifdef UWSGI_ZLIB if (utcc->cache_it_gzip) uwsgi_buffer_destroy(utcc->cache_it_gzip); #endif if (utcc->cache_it_to) uwsgi_buffer_destroy(utcc->cache_it_to); free(utcc); return UWSGI_ROUTE_NEXT; } static int uwsgi_routing_func_cache(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ char *mime_type = NULL; size_t mime_type_len = 0; struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len); if (!ub) return UWSGI_ROUTE_BREAK; uint64_t valsize = 0; uint64_t expires = 0; char *value = uwsgi_cache_magic_get(ub->buf, ub->pos, &valsize, &expires, urcc->name); if (urcc->mime && value) { mime_type = uwsgi_get_mime_type(ub->buf, ub->pos, &mime_type_len); } uwsgi_buffer_destroy(ub); if (value) { if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto error; if (mime_type) { uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len); } else { if (uwsgi_response_add_content_type(wsgi_req, urcc->content_type, urcc->content_type_len)) goto error; } if (urcc->content_encoding_len) { if (uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, urcc->content_encoding, urcc->content_encoding_len)) goto error; } if (expires) { if (uwsgi_response_add_expires(wsgi_req, expires)) goto error; } if (!urcc->no_cl) { if (uwsgi_response_add_content_length(wsgi_req, valsize)) goto error; } if (wsgi_req->socket->can_offload && !ur->custom && !urcc->no_offload) { if (!uwsgi_offload_request_memory_do(wsgi_req, value, valsize)) { wsgi_req->via = UWSGI_VIA_OFFLOAD; return UWSGI_ROUTE_BREAK; } } uwsgi_response_write_body_do(wsgi_req, value, valsize); free(value); if (ur->custom) return UWSGI_ROUTE_NEXT; return UWSGI_ROUTE_BREAK; } return UWSGI_ROUTE_NEXT; error: free(value); return UWSGI_ROUTE_BREAK; } // place a cache value in a request var static int uwsgi_routing_func_cachevar(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len); if (!ub) return UWSGI_ROUTE_BREAK; uint64_t valsize = 0; char *value = uwsgi_cache_magic_get(ub->buf, ub->pos, &valsize, NULL, urcc->name); uwsgi_buffer_destroy(ub); if (value) { if (urcc->as_num) { char *tmp = value; if (valsize == 8) { int64_t *num = (int64_t *) value; value = uwsgi_64bit2str(*num); } else { value = uwsgi_64bit2str(0); } free(tmp); } if (!uwsgi_req_append(wsgi_req, urcc->var, urcc->var_len, value, valsize)) { free(value); return UWSGI_ROUTE_BREAK; } free(value); } return UWSGI_ROUTE_NEXT; } // set a cache item static int uwsgi_routing_func_cacheset(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len); if (!ub) return UWSGI_ROUTE_BREAK; struct uwsgi_buffer *ub_val = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->value, urcc->value_len); if (!ub_val) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } if (uwsgi_cache_magic_set(ub->buf, ub->pos, ub_val->buf, ub_val->pos, urcc->expires, 0, urcc->name)) { uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub_val); return UWSGI_ROUTE_BREAK; } uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub_val); return UWSGI_ROUTE_NEXT; } // cacheinc/cachedec/cachemul/cachediv static int uwsgi_routing_func_cachemath(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len); if (!ub) return UWSGI_ROUTE_BREAK; int64_t num = urcc->default_num; if (urcc->value) { struct uwsgi_buffer *ub_val = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->value, urcc->value_len); if (!ub_val) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } num = strtol(ub_val->buf, NULL, 10); uwsgi_buffer_destroy(ub_val); } if (uwsgi_cache_magic_set(ub->buf, ub->pos, (char *) &num, 8, urcc->expires, urcc->flags, urcc->name)) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_cache_store(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_cache_store; ur->data = args; ur->data_len = strlen(args); struct uwsgi_router_cache_conf *urcc = uwsgi_calloc(sizeof(struct uwsgi_router_cache_conf)); if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=', "key", &urcc->key, #ifdef UWSGI_ZLIB "gzip", &urcc->gzip, #endif "name", &urcc->name, "value", &urcc->value, "status", &urcc->status_str, "code", &urcc->status_str, "expires", &urcc->expires_str, NULL)) { uwsgi_log("invalid cachestore route syntax: %s\n", args); goto error; } if (urcc->key) { urcc->key_len = strlen(urcc->key); } #ifdef UWSGI_ZLIB if (urcc->gzip) { urcc->gzip_len = strlen(urcc->gzip); } #endif if (urcc->name) { urcc->name_len = strlen(urcc->name); } if (!urcc->key) { uwsgi_log("invalid cachestore route syntax: you need to specify a cache key\n"); goto error; } if (urcc->expires_str) { urcc->expires = strtoul(urcc->expires_str, NULL, 10); } if (urcc->value) { urcc->value_len = strlen(urcc->value); } if (urcc->status_str) { urcc->status = atoi(urcc->status_str); } ur->data2 = urcc; return 0; error: if (urcc->key) free(urcc->key); if (urcc->name) free(urcc->name); if (urcc->expires_str) free(urcc->expires_str); free(urcc); return -1; } static int uwsgi_router_cache(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_cache; ur->data = args; ur->data_len = strlen(args); struct uwsgi_router_cache_conf *urcc = uwsgi_calloc(sizeof(struct uwsgi_router_cache_conf)); if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=', "key", &urcc->key, "content_type", &urcc->content_type, "content_encoding", &urcc->content_encoding, "mime", &urcc->mime, "name", &urcc->name, "no_offload", &urcc->no_offload, "no_content_length", &urcc->no_cl, "no_cl", &urcc->no_cl, "nocl", &urcc->no_cl, NULL)) { uwsgi_log("invalid route syntax: %s\n", args); exit(1); } if (urcc->key) { urcc->key_len = strlen(urcc->key); } if (!urcc->key) { uwsgi_log("invalid route syntax: you need to specify a cache key\n"); exit(1); } if (!urcc->content_type) urcc->content_type = "text/html"; urcc->content_type_len = strlen(urcc->content_type); if (urcc->content_encoding) { urcc->content_encoding_len = strlen(urcc->content_encoding); } ur->data2 = urcc; return 0; } static int uwsgi_router_cache_continue(struct uwsgi_route *ur, char *args) { uwsgi_router_cache(ur, args); ur->custom = 1; return 0; } static struct uwsgi_router_cache_conf *uwsgi_router_cachemath(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_cachemath; ur->data = args; ur->data_len = strlen(args); struct uwsgi_router_cache_conf *urcc = uwsgi_calloc(sizeof(struct uwsgi_router_cache_conf)); if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=', "key", &urcc->key, "value", &urcc->value, "name", &urcc->name, "expires", &urcc->expires_str, NULL)) { uwsgi_log("invalid cachemath route syntax: %s\n", args); goto error; } if (urcc->key) { urcc->key_len = strlen(urcc->key); } if (urcc->value) { urcc->value_len = strlen(urcc->value); } if (urcc->name) { urcc->name_len = strlen(urcc->name); } if (!urcc->key) { uwsgi_log("invalid cachemath route syntax: you need to specify a cache key\n"); goto error; } if (urcc->expires_str) { urcc->expires = strtoul(urcc->expires_str, NULL, 10); } urcc->flags = UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE; ur->data2 = urcc; return urcc; error: if (urcc->key) free(urcc->key); if (urcc->name) free(urcc->name); if (urcc->value) free(urcc->value); if (urcc->expires_str) free(urcc->expires_str); free(urcc); return NULL; } static int uwsgi_router_cacheinc(struct uwsgi_route *ur, char *args) { struct uwsgi_router_cache_conf *urcc = uwsgi_router_cachemath(ur, args); if (!urcc) return -1; urcc->default_num = 1; urcc->flags |= UWSGI_CACHE_FLAG_INC; return 0; } static int uwsgi_router_cachedec(struct uwsgi_route *ur, char *args) { struct uwsgi_router_cache_conf *urcc = uwsgi_router_cachemath(ur, args); if (!urcc) return -1; urcc->default_num = 1; urcc->flags |= UWSGI_CACHE_FLAG_DEC; return 0; } static int uwsgi_router_cachemul(struct uwsgi_route *ur, char *args) { struct uwsgi_router_cache_conf *urcc = uwsgi_router_cachemath(ur, args); if (!urcc) return -1; urcc->default_num = 2; urcc->flags |= UWSGI_CACHE_FLAG_MUL; return 0; } static int uwsgi_router_cachediv(struct uwsgi_route *ur, char *args) { struct uwsgi_router_cache_conf *urcc = uwsgi_router_cachemath(ur, args); if (!urcc) return -1; urcc->default_num = 2; urcc->flags |= UWSGI_CACHE_FLAG_DIV; return 0; } static int uwsgi_router_cacheset(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_cacheset; ur->data = args; ur->data_len = strlen(args); struct uwsgi_router_cache_conf *urcc = uwsgi_calloc(sizeof(struct uwsgi_router_cache_conf)); if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=', "key", &urcc->key, "value", &urcc->value, "name", &urcc->name, "expires", &urcc->expires_str, NULL)) { uwsgi_log("invalid cacheset route syntax: %s\n", args); goto error; } if (urcc->key) { urcc->key_len = strlen(urcc->key); } if (urcc->value) { urcc->value_len = strlen(urcc->value); } if (urcc->name) { urcc->name_len = strlen(urcc->name); } if (!urcc->key || !urcc->value) { uwsgi_log("invalid cacheset route syntax: you need to specify a cache key and a value\n"); goto error; } if (urcc->expires_str) { urcc->expires = strtoul(urcc->expires_str, NULL, 10); } ur->data2 = urcc; return 0; error: if (urcc->key) free(urcc->key); if (urcc->name) free(urcc->name); if (urcc->value) free(urcc->value); if (urcc->expires_str) free(urcc->expires_str); free(urcc); return -1; } static int uwsgi_router_cachevar(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_cachevar; ur->data = args; ur->data_len = strlen(args); struct uwsgi_router_cache_conf *urcc = uwsgi_calloc(sizeof(struct uwsgi_router_cache_conf)); if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=', "key", &urcc->key, "var", &urcc->var, "name", &urcc->name, "num", &urcc->as_num, "as_num", &urcc->as_num, NULL)) { uwsgi_log("invalid route syntax: %s\n", args); exit(1); } if (urcc->key) { urcc->key_len = strlen(urcc->key); } if (urcc->var) { urcc->var_len = strlen(urcc->var); } if (!urcc->key || !urcc->var) { uwsgi_log("invalid route syntax: you need to specify a cache key and a request var\n"); exit(1); } ur->data2 = urcc; return 0; } static int uwsgi_route_condition_incache(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { int ret = 0; char *key = NULL; size_t key_len = 0; char *name = NULL; if (uwsgi_kvlist_parse(ur->subject_str, ur->subject_str_len, ',', '=', "key", &key, "name", &name, NULL)) { return 0; } if (!key) goto end; key_len = strlen(key); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, NULL, 0, key, key_len); if (!ub) goto end; ret = uwsgi_cache_magic_exists(ub->buf, ub->pos, name); uwsgi_buffer_destroy(ub); end: if (key) free(key); if (name) free(name); return ret; } static void router_cache_register() { uwsgi_register_router("cache", uwsgi_router_cache); uwsgi_register_router("cache-continue", uwsgi_router_cache_continue); uwsgi_register_router("cachevar", uwsgi_router_cachevar); uwsgi_register_router("cacheset", uwsgi_router_cacheset); uwsgi_register_router("cachestore", uwsgi_router_cache_store); uwsgi_register_router("cache-store", uwsgi_router_cache_store); uwsgi_register_route_condition("incache", uwsgi_route_condition_incache); uwsgi_register_router("cacheinc", uwsgi_router_cacheinc); uwsgi_register_router("cachedec", uwsgi_router_cachedec); uwsgi_register_router("cachemul", uwsgi_router_cachemul); uwsgi_register_router("cachediv", uwsgi_router_cachediv); } struct uwsgi_plugin router_cache_plugin = { .name = "router_cache", .on_load = router_cache_register, }; #else struct uwsgi_plugin router_cache_plugin = { .name = "router_cache", }; #endif uwsgi-2.0.29/plugins/router_cache/uwsgiplugin.py000066400000000000000000000001241477626554400220360ustar00rootroot00000000000000NAME='router_cache' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['router_cache'] uwsgi-2.0.29/plugins/router_expires/000077500000000000000000000000001477626554400175265ustar00rootroot00000000000000uwsgi-2.0.29/plugins/router_expires/expires.c000066400000000000000000000063021477626554400213520ustar00rootroot00000000000000#include #ifdef UWSGI_ROUTING extern struct uwsgi_server uwsgi; /* by Unbit syntax: route = /^foobar1(.*)/ expires:filename=foo$1poo,value=30 route = /^foobar1(.*)/ expires:unix=${time[unix]},value=30 */ struct uwsgi_router_expires_conf { char *filename; size_t filename_len; char *unixt; size_t unixt_len; char *value; size_t value_len; }; static int uwsgi_routing_func_expires(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_router_expires_conf *urec = (struct uwsgi_router_expires_conf *) ur->data2; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); uint64_t expires = 0; if (urec->filename) { struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urec->filename, urec->filename_len); if (!ub) return UWSGI_ROUTE_BREAK; struct stat st; if (stat(ub->buf, &st)) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } expires = st.st_mtime; uwsgi_buffer_destroy(ub); } else if (urec->unixt) { struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urec->unixt, urec->unixt_len); if (!ub) return UWSGI_ROUTE_BREAK; expires = strtoul(ub->buf, NULL, 10); uwsgi_buffer_destroy(ub); } if (urec->value) { struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urec->value, urec->value_len); if (!ub) return UWSGI_ROUTE_BREAK; expires += atoi(ub->buf); uwsgi_buffer_destroy(ub); } char expires_str[7 + 2 + 31]; int len = uwsgi_http_date((time_t) expires, expires_str + 9); if (!len) return UWSGI_ROUTE_BREAK; memcpy(expires_str, "Expires: ", 9); uwsgi_additional_header_add(wsgi_req, expires_str, 9 + len); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_expires(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_expires; ur->data = args; ur->data_len = strlen(args); struct uwsgi_router_expires_conf *urec = uwsgi_calloc(sizeof(struct uwsgi_router_expires_conf)); if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=', "filename", &urec->filename, "file", &urec->filename, "unix", &urec->unixt, "value", &urec->value, NULL)) { uwsgi_log("invalid route syntax: %s\n", args); exit(1); } if (urec->filename) { urec->filename_len = strlen(urec->filename); } if (urec->unixt) { urec->unixt_len = strlen(urec->unixt); } if (urec->value) { urec->value_len = strlen(urec->value); } ur->data2 = urec; return 0; } static void router_expires_register() { uwsgi_register_router("expires", uwsgi_router_expires); } struct uwsgi_plugin router_expires_plugin = { .name = "router_expires", .on_load = router_expires_register, }; #else struct uwsgi_plugin router_expires_plugin = { .name = "router_expires", }; #endif uwsgi-2.0.29/plugins/router_expires/uwsgiplugin.py000066400000000000000000000001211477626554400224470ustar00rootroot00000000000000NAME='router_expires' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['expires'] uwsgi-2.0.29/plugins/router_hash/000077500000000000000000000000001477626554400167725ustar00rootroot00000000000000uwsgi-2.0.29/plugins/router_hash/router_hash.c000066400000000000000000000072571477626554400214740ustar00rootroot00000000000000#include #ifdef UWSGI_ROUTING extern struct uwsgi_server uwsgi; /* by Unbit syntax: route = /^foobar1(.*)/ hash:key=foo$1poo,algo=murmur2,var=MYHASH,items=node1;node2;node3 */ struct uwsgi_router_hash_conf { char *key; size_t key_len; char *var; size_t var_len; char *algo; char *items; size_t items_len; }; static int uwsgi_routing_func_hash(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_router_hash_conf *urhc = (struct uwsgi_router_hash_conf *) ur->data2; struct uwsgi_hash_algo *uha = uwsgi_hash_algo_get(urhc->algo); if (!uha) { uwsgi_log("[uwsgi-hash-router] unable to find hash algo \"%s\"\n", urhc->algo); return UWSGI_ROUTE_BREAK; } char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urhc->key, urhc->key_len); if (!ub) return UWSGI_ROUTE_BREAK; uint32_t h = uha->func(ub->buf, ub->pos); uwsgi_buffer_destroy(ub); // now count the number of items uint32_t items = 1; size_t i, ilen = urhc->items_len; for(i=0;iitems[i] == ';') items++; } // skip last semicolon if (urhc->items[ilen-1] == ';') items--; if (items < 1) return UWSGI_ROUTE_BREAK; uint32_t hashed_result = h % items; uint32_t found = 0; char *value = urhc->items; uint16_t vallen = 0; for(i=0;iitems + i; } if (urhc->items[i] == ';') { if (found == hashed_result) { vallen = (urhc->items+i) - value; break; } value = NULL; found++; } } if (vallen == 0) { // first item if (hashed_result == 0) { value = urhc->items; vallen = urhc->items_len; } // last item else if (value != NULL) { vallen = (urhc->items + urhc->items_len) - value; } } if (!vallen) { uwsgi_log("[uwsgi-hash-router] BUG !!! unable to hash items\n"); return UWSGI_ROUTE_BREAK; } if (!uwsgi_req_append(wsgi_req, urhc->var, urhc->var_len, value, vallen)) { uwsgi_log("[uwsgi-hash-router] unable to append hash var to the request\n"); return UWSGI_ROUTE_BREAK; } return UWSGI_ROUTE_NEXT; } static int uwsgi_router_hash(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_hash; ur->data = args; ur->data_len = strlen(args); struct uwsgi_router_hash_conf *urhc = uwsgi_calloc(sizeof(struct uwsgi_router_hash_conf)); if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=', "key", &urhc->key, "var", &urhc->var, "algo", &urhc->algo, "items", &urhc->items, NULL)) { uwsgi_log("invalid route syntax: %s\n", args); exit(1); } if (!urhc->key || !urhc->var || !urhc->items) { uwsgi_log("invalid route syntax: you need to specify a hash key, a var and a set of items\n"); exit(1); } urhc->key_len = strlen(urhc->key); urhc->var_len = strlen(urhc->var); urhc->items_len = strlen(urhc->items); if (!urhc->algo) urhc->algo = "djb33x"; ur->data2 = urhc; return 0; } static void router_hash_register() { uwsgi_register_router("hash", uwsgi_router_hash); } struct uwsgi_plugin router_hash_plugin = { .name = "router_hash", .on_load = router_hash_register, }; #else struct uwsgi_plugin router_hash_plugin = { .name = "router_hash", }; #endif uwsgi-2.0.29/plugins/router_hash/uwsgiplugin.py000066400000000000000000000001221477626554400217140ustar00rootroot00000000000000NAME='router_hash' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['router_hash'] uwsgi-2.0.29/plugins/router_http/000077500000000000000000000000001477626554400170265ustar00rootroot00000000000000uwsgi-2.0.29/plugins/router_http/router_http.c000066400000000000000000000115261477626554400215560ustar00rootroot00000000000000#include #ifdef UWSGI_ROUTING extern struct uwsgi_server uwsgi; static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_buffer *ub = NULL; // mark a route request wsgi_req->via = UWSGI_VIA_ROUTE; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub_addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub_addr) return UWSGI_ROUTE_BREAK; struct uwsgi_buffer *ub_url = NULL; if (ur->data3_len) { ub_url = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data3, ur->data3_len); if (!ub_url) { uwsgi_buffer_destroy(ub_addr); return UWSGI_ROUTE_BREAK; } } // convert the wsgi_request to an http proxy request if (ur->custom & 0x02) { ub = uwsgi_buffer_new(uwsgi.page_size); } else if (ur->custom & 0x04) { ub = uwsgi_to_http_dumb(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0); } else { ub = uwsgi_to_http(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0); } if (!ub) { if (ub_url) uwsgi_buffer_destroy(ub_url); uwsgi_log("unable to generate http request for %s\n", ub_addr->buf); uwsgi_buffer_destroy(ub_addr); return UWSGI_ROUTE_NEXT; } if (ub_url) uwsgi_buffer_destroy(ub_url); // amount of body to send size_t remains = wsgi_req->post_cl - wsgi_req->proto_parser_remains; // append remaining body... if (wsgi_req->proto_parser_remains > 0) { if (uwsgi_buffer_append(ub, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains)) { uwsgi_buffer_destroy(ub); uwsgi_log("unable to generate http request for %s\n", ub_addr->buf); uwsgi_buffer_destroy(ub_addr); return UWSGI_ROUTE_NEXT; } wsgi_req->post_pos += wsgi_req->proto_parser_remains; wsgi_req->proto_parser_remains = 0; } // ok now if have offload threads, directly use them if (!wsgi_req->post_file && !(ur->custom & 0x01) && wsgi_req->socket->can_offload) { // append buffered body if (uwsgi.post_buffering > 0 && wsgi_req->post_cl > 0) { if (uwsgi_buffer_append(ub, wsgi_req->post_buffering_buf, wsgi_req->post_cl)) { uwsgi_buffer_destroy(ub); uwsgi_log("unable to generate http request for %s\n", ub_addr->buf); uwsgi_buffer_destroy(ub_addr); return UWSGI_ROUTE_NEXT; } } // if we have a CONNECT request, let's confirm it to the client if (ur->custom & 0x02) { if (uwsgi_response_prepare_headers(wsgi_req, "200 Connection established", 26)) goto end; // no need to check for return value uwsgi_response_write_headers_do(wsgi_req); } if (!uwsgi_offload_request_net_do(wsgi_req, ub_addr->buf, ub)) { wsgi_req->via = UWSGI_VIA_OFFLOAD; wsgi_req->status = 202; uwsgi_buffer_destroy(ub_addr); return UWSGI_ROUTE_BREAK; } } if (uwsgi_proxy_nb(wsgi_req, ub_addr->buf, ub, remains, uwsgi.socket_timeout)) { uwsgi_log("error routing request to http server %s\n", ub_addr->buf); } end: uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub_addr); return UWSGI_ROUTE_BREAK; } static int uwsgi_router_http(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_http; ur->data = (void *) args; ur->data_len = strlen(args); char *comma = strchr(ur->data, ','); if (comma) { *comma = 0; ur->data_len = strlen(ur->data); ur->data2 = comma+1; comma = strchr(ur->data2, ','); if (comma) { *comma = 0; ur->data3 = comma+1; ur->data3_len = strlen(ur->data3); } ur->data2_len = strlen(ur->data2); } return 0; } static int uwsgi_router_proxyhttp(struct uwsgi_route *ur, char *args) { ur->custom = 0x1; return uwsgi_router_http(ur, args); } static int uwsgi_router_proxyhttp_connect(struct uwsgi_route *ur, char *args) { ur->custom = 0x1|0x02; return uwsgi_router_http(ur, args); } static int uwsgi_router_http_connect(struct uwsgi_route *ur, char *args) { ur->custom = 0x02; return uwsgi_router_http(ur, args); } static int uwsgi_router_httpdumb(struct uwsgi_route *ur, char *args) { ur->custom = 0x04; return uwsgi_router_http(ur, args); } static void router_http_register(void) { uwsgi_register_router("http", uwsgi_router_http); uwsgi_register_router("httpdumb", uwsgi_router_httpdumb); uwsgi_register_router("proxyhttp", uwsgi_router_proxyhttp); uwsgi_register_router("httpconnect", uwsgi_router_http_connect); uwsgi_register_router("proxyhttpconnect", uwsgi_router_proxyhttp_connect); } struct uwsgi_plugin router_http_plugin = { .name = "router_http", .on_load = router_http_register, }; #else struct uwsgi_plugin router_http_plugin = { .name = "router_http", }; #endif uwsgi-2.0.29/plugins/router_http/uwsgiplugin.py000066400000000000000000000001221477626554400217500ustar00rootroot00000000000000NAME='router_http' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['router_http'] uwsgi-2.0.29/plugins/router_memcached/000077500000000000000000000000001477626554400177555ustar00rootroot00000000000000uwsgi-2.0.29/plugins/router_memcached/router_memcached.c000066400000000000000000000257301477626554400234360ustar00rootroot00000000000000#include #ifdef UWSGI_ROUTING #define MEMCACHED_BUFSIZE 8192 extern struct uwsgi_server uwsgi; /* memcached internal router and transformation route = /^foobar1(.*)/ memcached:addr=127.0.0.1:11211,key=foo$1poo route = /^foobar1(.*)/ memcachedstore:addr=127.0.0.1:11211,key=foo$1poo */ struct uwsgi_router_memcached_conf { char *addr; size_t addr_len; char *key; size_t key_len; char *content_type; size_t content_type_len; char *no_offload; char *expires; }; // this is allocated for each transformation struct uwsgi_transformation_memcached_conf { struct uwsgi_buffer *addr; struct uwsgi_buffer *key; char *expires; }; static size_t memcached_firstline_parse(char *buf, size_t len) { // check for "VALUE x 0 0" if (len < 11) return 0; char *flags = memchr(buf + 6, ' ', len-6); if (!flags) return 0; size_t skip = (flags-buf)+1; if (skip+1 >= len) return 0; char *bytes = memchr(buf + skip + 1, ' ', len - (skip+1)); if (!bytes) return 0; skip = (bytes-buf)+1; if (skip+1 > len) return 0; char *bytes_end = memchr(buf + skip + 1, ' ', len - (skip+1)); if (bytes_end) { return uwsgi_str_num(bytes + 1, bytes_end - (bytes+1)); } else { return uwsgi_str_num(bytes + 1, len-skip); } } // store an item in memcached static void memcached_store(char *addr, struct uwsgi_buffer *key, struct uwsgi_buffer *value, char *expires) { int timeout = uwsgi.socket_timeout; int fd = uwsgi_connect(addr, 0, 1); if (fd < 0) return; // wait for connection int ret = uwsgi.wait_write_hook(fd, timeout); if (ret <= 0) goto end; // build the request struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); if (uwsgi_buffer_append(ub, "set ", 4)) goto end2; if (uwsgi_buffer_append(ub, key->buf, key->pos)) goto end2; if (uwsgi_buffer_append(ub, " 0 " , 3)) goto end2; if (uwsgi_buffer_append(ub, expires, strlen(expires))) goto end2; if (uwsgi_buffer_append(ub, " " , 1)) goto end2; if (uwsgi_buffer_num64(ub, value->pos)) goto end2; if (uwsgi_buffer_append(ub, "\r\n" , 2)) goto end2; if (uwsgi_write_true_nb(fd, ub->buf, ub->pos, timeout)) goto end2; if (uwsgi_write_true_nb(fd, value->buf, value->pos, timeout)) goto end2; if (uwsgi_write_true_nb(fd, "\r\n", 2, timeout)) goto end2; // we are not interested in command result... (ugly but it works) end2: uwsgi_buffer_destroy(ub); end: close(fd); } static int transform_memcached(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) { struct uwsgi_transformation_memcached_conf *utmc = (struct uwsgi_transformation_memcached_conf *) ut->data; struct uwsgi_buffer *ub = ut->chunk; // store only successfull response if (wsgi_req->write_errors == 0 && wsgi_req->status == 200 && ub->pos > 0) { memcached_store(utmc->addr->buf, utmc->key, ub, utmc->expires); } // free resources uwsgi_buffer_destroy(utmc->key); uwsgi_buffer_destroy(utmc->addr); free(utmc); return 0; } // be tolerant on errors static int uwsgi_routing_func_memcached_store(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_router_memcached_conf *urmc = (struct uwsgi_router_memcached_conf *) ur->data2; struct uwsgi_transformation_memcached_conf *utmc = uwsgi_calloc(sizeof(struct uwsgi_transformation_memcached_conf)); // build key and name char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); utmc->key = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->key, urmc->key_len); if (!utmc->key) goto error; utmc->addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->addr, urmc->addr_len); if (!utmc->addr) goto error; utmc->expires = urmc->expires; uwsgi_add_transformation(wsgi_req, transform_memcached, utmc); return UWSGI_ROUTE_NEXT; error: if (utmc->key) uwsgi_buffer_destroy(utmc->key); if (utmc->addr) uwsgi_buffer_destroy(utmc->addr); free(utmc); return UWSGI_ROUTE_NEXT; } static int uwsgi_routing_func_memcached(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ // this is the buffer for the memcached response char buf[MEMCACHED_BUFSIZE]; size_t i; char last_char = 0; struct uwsgi_router_memcached_conf *urmc = (struct uwsgi_router_memcached_conf *) ur->data2; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub_key = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->key, urmc->key_len); if (!ub_key) return UWSGI_ROUTE_BREAK; struct uwsgi_buffer *ub_addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->addr, urmc->addr_len); if (!ub_addr) { uwsgi_buffer_destroy(ub_key); return UWSGI_ROUTE_BREAK; } int fd = uwsgi_connect(ub_addr->buf, 0, 1); if (fd < 0) { uwsgi_buffer_destroy(ub_key); uwsgi_buffer_destroy(ub_addr); goto end; } // wait for connection; int ret = uwsgi.wait_write_hook(fd, uwsgi.socket_timeout); if (ret <= 0) { uwsgi_buffer_destroy(ub_key) ; uwsgi_buffer_destroy(ub_addr); close(fd); goto end; } // build the request and send it char *cmd = uwsgi_concat3n("get ", 4, ub_key->buf, ub_key->pos, "\r\n", 2); if (uwsgi_write_true_nb(fd, cmd, 6+ub_key->pos, uwsgi.socket_timeout)) { uwsgi_buffer_destroy(ub_key); uwsgi_buffer_destroy(ub_addr); free(cmd); close(fd); goto end; } uwsgi_buffer_destroy(ub_key); uwsgi_buffer_destroy(ub_addr); free(cmd); // ok, start reading the response... // first we need to get a full line; size_t found = 0; size_t pos = 0; for(;;) { ssize_t len = read(fd, buf + pos, MEMCACHED_BUFSIZE - pos); if (len > 0) { pos += len; goto read; } if (len < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) goto wait; } close(fd); goto end; wait: ret = uwsgi.wait_read_hook(fd, uwsgi.socket_timeout); // when we have a chunk try to read the first line if (ret > 0) { len = read(fd, buf + pos, MEMCACHED_BUFSIZE - pos); if (len > 0) { pos += len; goto read; } } close(fd); goto end; read: for(i=0;icontent_type, urmc->content_type_len)) goto error; if (uwsgi_response_add_content_length(wsgi_req, response_size)) goto error; // the first chunk could already contains part of the body size_t remains = pos-(found+2); if (remains >= response_size) { uwsgi_response_write_body_do(wsgi_req, buf+found+2, response_size); goto done; } // send what we have if (uwsgi_response_write_body_do(wsgi_req, buf+found+2, remains)) goto error; // and now start reading til the output is consumed response_size -= remains; // try to offload via the pipe engine if (wsgi_req->socket->can_offload && !ur->custom && !urmc->no_offload) { if (!uwsgi_offload_request_pipe_do(wsgi_req, fd, response_size)) { wsgi_req->via = UWSGI_VIA_OFFLOAD; return UWSGI_ROUTE_BREAK; } } while(response_size > 0) { ssize_t len = read(fd, buf, UMIN(MEMCACHED_BUFSIZE, response_size)); if (len > 0) goto write; if (len < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) goto wait2; } goto error; wait2: ret = uwsgi.wait_read_hook(fd, uwsgi.socket_timeout); if (ret > 0) { len = read(fd, buf, UMIN(MEMCACHED_BUFSIZE, response_size)); if (len > 0) goto write; } goto error; write: if (uwsgi_response_write_body_do(wsgi_req, buf, len)) goto error; response_size -= len; } done: close(fd); if (ur->custom) return UWSGI_ROUTE_NEXT; return UWSGI_ROUTE_BREAK; error: close(fd); return UWSGI_ROUTE_BREAK; end: return UWSGI_ROUTE_NEXT; } static int uwsgi_router_memcached(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_memcached; ur->data = args; ur->data_len = strlen(args); struct uwsgi_router_memcached_conf *urmc = uwsgi_calloc(sizeof(struct uwsgi_router_memcached_conf)); if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=', "addr", &urmc->addr, "key", &urmc->key, "content_type", &urmc->content_type, "no_offload", &urmc->no_offload, NULL)) { uwsgi_log("invalid route syntax: %s\n", args); exit(1); } if (!urmc->key || !urmc->addr) { uwsgi_log("invalid route syntax: you need to specify a memcached address and key pattern\n"); return -1; } urmc->key_len = strlen(urmc->key); urmc->addr_len = strlen(urmc->addr); if (!urmc->content_type) urmc->content_type = "text/html"; urmc->content_type_len = strlen(urmc->content_type); ur->data2 = urmc; return 0; } static int uwsgi_router_memcached_continue(struct uwsgi_route *ur, char *args) { uwsgi_router_memcached(ur, args); ur->custom = 1; return 0; } static int uwsgi_router_memcached_store(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_memcached_store; ur->data = args; ur->data_len = strlen(args); struct uwsgi_router_memcached_conf *urmc = uwsgi_calloc(sizeof(struct uwsgi_router_memcached_conf)); if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=', "addr", &urmc->addr, "key", &urmc->key, "expires", &urmc->expires, NULL)) { uwsgi_log("invalid memcachedstore route syntax: %s\n", args); return -1; } if (!urmc->key || !urmc->addr) { uwsgi_log("invalid memcachedstore route syntax: you need to specify an address and a key\n"); return -1; } urmc->key_len = strlen(urmc->key); urmc->addr_len = strlen(urmc->addr); if (!urmc->expires) urmc->expires = "0"; ur->data2 = urmc; return 0; } static void router_memcached_register() { uwsgi_register_router("memcached", uwsgi_router_memcached); uwsgi_register_router("memcached-continue", uwsgi_router_memcached_continue); uwsgi_register_router("memcachedstore", uwsgi_router_memcached_store); uwsgi_register_router("memcached-store", uwsgi_router_memcached_store); } #endif struct uwsgi_plugin router_memcached_plugin = { .name = "router_memcached", #ifdef UWSGI_ROUTING .on_load = router_memcached_register, #endif }; uwsgi-2.0.29/plugins/router_memcached/uwsgiplugin.py000066400000000000000000000001341477626554400227020ustar00rootroot00000000000000NAME='router_memcached' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['router_memcached'] uwsgi-2.0.29/plugins/router_metrics/000077500000000000000000000000001477626554400175155ustar00rootroot00000000000000uwsgi-2.0.29/plugins/router_metrics/plugin.c000066400000000000000000000100061477626554400211540ustar00rootroot00000000000000#include #ifdef UWSGI_ROUTING struct uwsgi_router_metric_conf { // the name of the metric char *name; size_t name_len; // the value for the metric char *value; size_t value_len; int (*func)(char *, char *, int64_t); }; // metricinc/metricdec/metricmul/metricdiv/metricset static int uwsgi_routing_func_metricmath(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_router_metric_conf *urmc = (struct uwsgi_router_metric_conf *) ur->data2; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->name, urmc->name_len); if (!ub) return UWSGI_ROUTE_BREAK; struct uwsgi_buffer *ub_val = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->value, urmc->value_len); if (!ub_val) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } int64_t num = strtol(ub_val->buf, NULL, 10); uwsgi_buffer_destroy(ub_val); if (urmc->func(ub->buf, NULL, num)) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; } static struct uwsgi_router_metric_conf *uwsgi_router_metricmath(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_metricmath; ur->data = args; ur->data_len = strlen(args); struct uwsgi_router_metric_conf *urmc = uwsgi_calloc(sizeof(struct uwsgi_router_metric_conf)); char *comma = strchr(args, ','); if (comma) { urmc->value = comma+1; urmc->value_len = strlen(urmc->value); *comma = 0; } else { urmc->value = "1"; urmc->value_len = 1; } urmc->name = args; urmc->name_len = strlen(args); if (comma) *comma = ','; ur->data2 = urmc; return urmc; } static int uwsgi_router_metricinc(struct uwsgi_route *ur, char *args) { struct uwsgi_router_metric_conf *urmc = uwsgi_router_metricmath(ur, args); if (!urmc) return -1; urmc->func = uwsgi_metric_inc; return 0; } static int uwsgi_router_metricdec(struct uwsgi_route *ur, char *args) { struct uwsgi_router_metric_conf *urmc = uwsgi_router_metricmath(ur, args); if (!urmc) return -1; urmc->func = uwsgi_metric_dec; return 0; } static int uwsgi_router_metricmul(struct uwsgi_route *ur, char *args) { struct uwsgi_router_metric_conf *urmc = uwsgi_router_metricmath(ur, args); if (!urmc) return -1; urmc->func = uwsgi_metric_mul; return 0; } static int uwsgi_router_metricdiv(struct uwsgi_route *ur, char *args) { struct uwsgi_router_metric_conf *urmc = uwsgi_router_metricmath(ur, args); if (!urmc) return -1; urmc->func = uwsgi_metric_div; return 0; } static int uwsgi_router_metricset(struct uwsgi_route *ur, char *args) { struct uwsgi_router_metric_conf *urmc = uwsgi_router_metricmath(ur, args); if (!urmc) return -1; urmc->func = uwsgi_metric_set; return 0; } static char *uwsgi_route_var_metric(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) { int64_t metric = uwsgi_metric_getn(key, keylen, NULL, 0); char *ret = uwsgi_64bit2str(metric); *vallen = strlen(ret); return ret; } static void router_metrics_register() { uwsgi_register_router("metricinc", uwsgi_router_metricinc); uwsgi_register_router("metricdec", uwsgi_router_metricdec); uwsgi_register_router("metricmul", uwsgi_router_metricmul); uwsgi_register_router("metricdiv", uwsgi_router_metricdiv); uwsgi_register_router("metricset", uwsgi_router_metricset); struct uwsgi_route_var *urv = uwsgi_register_route_var("metric", uwsgi_route_var_metric); urv->need_free = 1; } struct uwsgi_plugin router_metrics_plugin = { .name = "router_metrics", .on_load = router_metrics_register, }; #else struct uwsgi_plugin router_metrics_plugin = { .name = "router_metrics", }; #endif uwsgi-2.0.29/plugins/router_metrics/uwsgiplugin.py000066400000000000000000000001201477626554400224350ustar00rootroot00000000000000NAME='router_metrics' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['plugin'] uwsgi-2.0.29/plugins/router_radius/000077500000000000000000000000001477626554400173365ustar00rootroot00000000000000uwsgi-2.0.29/plugins/router_radius/radius.c000066400000000000000000000200071477626554400207700ustar00rootroot00000000000000#include extern struct uwsgi_server uwsgi; struct uwsgi_radius_conf { char *realm; uint16_t realm_len; char *server; char *secret; uint16_t secret_len; char *nas_port_str; uint32_t nas_port; char *nas_address_str; uint32_t nas_address; }; static uint16_t uwsgi_radius_auth(struct uwsgi_radius_conf *urc, char *auth, size_t auth_len) { static uint8_t packet_identifier = 0; char access_request[4096]; char hash[4096]; // md5 result char md5_hash[16]; size_t i; char *password = memchr(auth, ':', auth_len); if (!password) return 0; char *username = auth; uint16_t username_len = password - auth; password++; uint16_t password_len = auth_len - (username_len+1); int fd = uwsgi_connect_udp(urc->server); if (fd < 0) return 0; uwsgi_socket_nb(fd); // start generating authenticator char authenticator[16]; for(i=0;i<16;i++) authenticator[i] = rand(); // generate the User-Password attribute char *md5 = authenticator; // step 1 pad to 16 bytes boundary size_t pwd16_len = password_len + (16 - (password_len % 16)); if (pwd16_len > 128) return 0; // compute the whole packet size uint16_t access_request_len = 4 + 16 + 2 + username_len + 2 + pwd16_len + 6 + 6; memset(access_request, 0, access_request_len); if (access_request_len > 4096) return 0; char *pwd16_buf = access_request + (access_request_len - (pwd16_len + 6 + 6)); memcpy(pwd16_buf, password, password_len); // allocate a buffer for the hash if (urc->secret_len + 16 > 4096) return 0; memcpy(hash, urc->secret, urc->secret_len); for(i=0;isecret_len, md5, 16); // calculate its md5 if (!uwsgi_md5(hash, urc->secret_len + 16, md5_hash)) { goto end; } size_t j; // set md5 to the new result md5 = &pwd16_buf[i]; // xor the result (we use the authenticator as destination buffer) for(j=0;j<16;j++) { md5[j] = md5_hash[j] ^ md5[j]; } } // complete the packet packet_identifier++; access_request[0] = 1; access_request[1] = packet_identifier; access_request[2] = (uint8_t) ((access_request_len >> 8) & 0xff); access_request[3] = (uint8_t) (access_request_len & 0xff); memcpy(access_request + 4, authenticator, 16); access_request[4 + 16] = 1; access_request[4 + 16 + 1] = username_len + 2; memcpy(access_request + (4 + 16 + 2), username, username_len); access_request[4 + 16 + 2 + username_len] = 2; access_request[4 + 16 + 2 + username_len + 1] = pwd16_len + 2; // add nas port access_request[4 + 16 + 2 + username_len + 2 + pwd16_len] = 5; access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 1] = 6; access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 2] = (uint8_t) ((urc->nas_port >> 24) & 0xff); access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 3] = (uint8_t) ((urc->nas_port >> 16) & 0xff); access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 4] = (uint8_t) ((urc->nas_port >> 8) & 0xff); access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 5] = (uint8_t) (urc->nas_port & 0xff); // add nas address access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 6] = 4; access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 6 + 1] = 6; access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 6 + 2] = (uint8_t) ((urc->nas_address >> 24) & 0xff); access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 6 + 3] = (uint8_t) ((urc->nas_address >> 16) & 0xff); access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 6 + 4] = (uint8_t) ((urc->nas_address >> 8) & 0xff); access_request[4 + 16 + 2 + username_len + 2 + pwd16_len + 6 + 5] = (uint8_t) (urc->nas_address & 0xff); if (write(fd, access_request, access_request_len) != access_request_len) { goto end; } // now wait for the response int ret = uwsgi.wait_read_hook(fd, uwsgi.socket_timeout); if (ret <= 0) goto end; ssize_t rlen = read(fd, access_request, access_request_len); // we need at least 4 + 16 if (rlen >= 20) { char response_authenticator[16]; if (access_request[1] != packet_identifier) goto end; if (rlen + urc->secret_len > 4096) goto end; // get the authenticator memcpy(response_authenticator, access_request+4, 16); // append the secret memcpy(access_request+rlen, urc->secret, urc->secret_len); // change the authenticator memcpy(access_request+4, authenticator, 16); // compute the md5 if (!uwsgi_md5(access_request, rlen + urc->secret_len, md5_hash)) { goto end; } if (memcmp(md5_hash, response_authenticator, 16)) goto end; // Access-Accept if (access_request[0] == 2) { close(fd); return username_len; } } end: close(fd); return 0; } static int uwsgi_routing_func_radius(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_radius_conf *urc = (struct uwsgi_radius_conf *) ur->data2; // skip if already authenticated if (wsgi_req->remote_user_len > 0) { return UWSGI_ROUTE_NEXT; } if (wsgi_req->authorization_len > 7) { if (strncmp(wsgi_req->authorization, "Basic ", 6)) goto forbidden; size_t auth_len = 0; char *auth = uwsgi_base64_decode(wsgi_req->authorization+6, wsgi_req->authorization_len-6, &auth_len); if (auth) { uint16_t rlen = uwsgi_radius_auth(urc, auth, auth_len); if (rlen > 0) { wsgi_req->remote_user = uwsgi_req_append(wsgi_req, "REMOTE_USER", 11, auth, rlen); free(auth); if (!wsgi_req->remote_user) goto forbidden; wsgi_req->remote_user_len = rlen; return UWSGI_ROUTE_NEXT; } free(auth); if (ur->custom) return UWSGI_ROUTE_NEXT; } } forbidden: if (uwsgi_response_prepare_headers(wsgi_req, "401 Authorization Required", 26)) goto end; char *realm = uwsgi_concat3n("Basic realm=\"", 13, urc->realm, urc->realm_len, "\"", 1); // no need to check for errors uwsgi_response_add_header(wsgi_req, "WWW-Authenticate", 16, realm, 13 + urc->realm_len + 1); free(realm); uwsgi_response_write_body_do(wsgi_req, "Unauthorized", 12); end: return UWSGI_ROUTE_BREAK; } static int uwsgi_router_radius(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_radius; ur->data = args; ur->data_len = strlen(args); struct uwsgi_radius_conf *urc = uwsgi_calloc(sizeof(struct uwsgi_radius_conf)); if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=', "realm", &urc->realm, "server", &urc->server, "secret", &urc->secret, "nas_port", &urc->nas_port_str, "nas_address", &urc->nas_address_str, NULL)) { uwsgi_log("invalid route syntax: %s\n", args); exit(1); } if (!urc->realm || !urc->server || !urc->secret) { uwsgi_log("invalid radius route syntax: you need to specify a realm a server and a secret\n"); exit(1); } urc->realm_len = strlen(urc->realm); urc->secret_len = strlen(urc->secret); if (urc->nas_port_str) { urc->nas_port = strtoul(urc->nas_port_str, NULL, 10); } if (!urc->nas_address_str) { urc->nas_address_str = uwsgi.hostname; } struct hostent *he = gethostbyname(urc->nas_address_str); if (he) { if (he->h_addr_list[0]) { memcpy(&urc->nas_address, he->h_addr_list[0], 4); urc->nas_address = htonl(urc->nas_address); } } ur->data2 = urc; return 0; } static int uwsgi_router_radius_next(struct uwsgi_route *ur, char *args) { ur->custom = 1; return uwsgi_router_radius(ur, args); } static void router_radius_register(void) { uwsgi_register_router("radius", uwsgi_router_radius); uwsgi_register_router("radius-next", uwsgi_router_radius_next); } struct uwsgi_plugin router_radius_plugin = { .name = "router_radius", .on_load = router_radius_register, }; uwsgi-2.0.29/plugins/router_radius/uwsgiplugin.py000066400000000000000000000001171477626554400222640ustar00rootroot00000000000000NAME='router_radius' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['radius'] uwsgi-2.0.29/plugins/router_redirect/000077500000000000000000000000001477626554400176505ustar00rootroot00000000000000uwsgi-2.0.29/plugins/router_redirect/router_redirect.c000066400000000000000000000050241477626554400232160ustar00rootroot00000000000000#include #ifdef UWSGI_ROUTING extern struct uwsgi_server uwsgi; static int uwsgi_routing_func_redirect(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_buffer *ub = NULL; if (uwsgi_response_prepare_headers(wsgi_req, "302 Found", 9)) goto end; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; if (uwsgi_response_add_header(wsgi_req, "Location", 8, ub->buf, ub->pos)) goto end; // no need to check the ret value uwsgi_response_write_body_do(wsgi_req, "Moved", 5); end: if (ub) uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } static int uwsgi_routing_func_redirect_permanent(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_buffer *ub = NULL; if (uwsgi_response_prepare_headers(wsgi_req, "301 Moved Permanently", 21)) goto end; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; if (uwsgi_response_add_header(wsgi_req, "Location", 8, ub->buf, ub->pos)) goto end; // no need to check the ret value uwsgi_response_write_body_do(wsgi_req, "Moved Permanently", 17); end: if (ub) uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } static int uwsgi_router_redirect(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_redirect; ur->data = args; ur->data_len = strlen(args); return 0; } static int uwsgi_router_redirect_permanent(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_redirect_permanent; ur->data = args; ur->data_len = strlen(args); return 0; } static void router_redirect_register(void) { uwsgi_register_router("redirect", uwsgi_router_redirect); uwsgi_register_router("redirect-302", uwsgi_router_redirect); uwsgi_register_router("redirect-permanent", uwsgi_router_redirect_permanent); uwsgi_register_router("redirect-301", uwsgi_router_redirect_permanent); } struct uwsgi_plugin router_redirect_plugin = { .name = "router_redirect", .on_load = router_redirect_register, }; #else struct uwsgi_plugin router_redirect_plugin = { .name = "router_redirect", }; #endif uwsgi-2.0.29/plugins/router_redirect/uwsgiplugin.py000066400000000000000000000001321477626554400225730ustar00rootroot00000000000000NAME='router_redirect' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['router_redirect'] uwsgi-2.0.29/plugins/router_redis/000077500000000000000000000000001477626554400171555ustar00rootroot00000000000000uwsgi-2.0.29/plugins/router_redis/router_redis.c000066400000000000000000000257601477626554400220410ustar00rootroot00000000000000#include #ifdef UWSGI_ROUTING #define REDIS_BUFSIZE 8192 extern struct uwsgi_server uwsgi; /* redis internal router and transformation route = /^foobar1(.*)/ redis:addr=127.0.0.1:11211,key=foo$1poo route = /^foobar1(.*)/ redisstore:addr=127.0.0.1:11211,key=foo$1poo */ struct uwsgi_router_redis_conf { char *addr; size_t addr_len; char *key; size_t key_len; char *content_type; size_t content_type_len; char *no_offload; char *expires; }; // this is allocated for each transformation struct uwsgi_transformation_redis_conf { struct uwsgi_buffer *addr; struct uwsgi_buffer *key; char *expires; }; static size_t redis_firstline_parse(char *buf, size_t len) { // check for "$0" if (len < 2) return 0; if (buf[0] != '$') return 0; if (buf[1] == '-') return 0; return uwsgi_str_num(buf + 1, len - 1); } // store an item in redis static void redis_store(char *addr, struct uwsgi_buffer *key, struct uwsgi_buffer *value, char *expires) { int timeout = uwsgi.socket_timeout; int fd = uwsgi_connect(addr, 0, 1); if (fd < 0) return; // wait for connection int ret = uwsgi.wait_write_hook(fd, timeout); if (ret <= 0) goto end; // build the request struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); if (uwsgi_buffer_append(ub, "*3\r\n$3\r\nSET\r\n$", 14)) goto end2; if (uwsgi_buffer_num64(ub, key->pos)) goto end2; if (uwsgi_buffer_append(ub, "\r\n" , 2)) goto end2; if (uwsgi_buffer_append(ub, key->buf, key->pos)) goto end2; if (uwsgi_buffer_append(ub, "\r\n$" , 3)) goto end2; if (uwsgi_buffer_num64(ub, value->pos)) goto end2; if (uwsgi_buffer_append(ub, "\r\n" , 2)) goto end2; if (uwsgi_write_true_nb(fd, ub->buf, ub->pos, timeout)) goto end2; if (uwsgi_write_true_nb(fd, value->buf, value->pos, timeout)) goto end2; ub->pos = 0; if (strcmp(expires, "0")) { if (uwsgi_buffer_append(ub, "\r\n*3\r\n$6\r\nEXPIRE\r\n$" , 19)) goto end2; if (uwsgi_buffer_num64(ub, key->pos)) goto end2; if (uwsgi_buffer_append(ub, "\r\n" , 2)) goto end2; if (uwsgi_buffer_append(ub, key->buf, key->pos)) goto end2; if (uwsgi_buffer_append(ub, "\r\n$" , 3)) goto end2; if (uwsgi_buffer_num64(ub, strlen(expires))) goto end2; if (uwsgi_buffer_append(ub, "\r\n" , 2)) goto end2; if (uwsgi_buffer_append(ub, expires, strlen(expires))) goto end2; } if (uwsgi_buffer_append(ub, "\r\n" , 2)) goto end2; if (uwsgi_write_true_nb(fd, ub->buf, ub->pos, timeout)) goto end2; // we are not interested in command result... (ugly but it works) end2: uwsgi_buffer_destroy(ub); end: close(fd); } static int transform_redis(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) { struct uwsgi_transformation_redis_conf *utrc = (struct uwsgi_transformation_redis_conf *) ut->data; struct uwsgi_buffer *ub = ut->chunk; // store only successfull response if (wsgi_req->write_errors == 0 && wsgi_req->status == 200 && ub->pos > 0) { redis_store(utrc->addr->buf, utrc->key, ub, utrc->expires); } // free resources uwsgi_buffer_destroy(utrc->key); uwsgi_buffer_destroy(utrc->addr); free(utrc); return 0; } // be tolerant on errors static int uwsgi_routing_func_redis_store(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_router_redis_conf *urrc = (struct uwsgi_router_redis_conf *) ur->data2; struct uwsgi_transformation_redis_conf *utrc = uwsgi_calloc(sizeof(struct uwsgi_transformation_redis_conf)); // build key and name char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); utrc->key = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urrc->key, urrc->key_len); if (!utrc->key) goto error; utrc->addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urrc->addr, urrc->addr_len); if (!utrc->addr) goto error; utrc->expires = urrc->expires; uwsgi_add_transformation(wsgi_req, transform_redis, utrc); return UWSGI_ROUTE_NEXT; error: if (utrc->key) uwsgi_buffer_destroy(utrc->key); if (utrc->addr) uwsgi_buffer_destroy(utrc->addr); free(utrc); return UWSGI_ROUTE_NEXT; } static int uwsgi_routing_func_redis(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ // this is the buffer for the redis response char buf[REDIS_BUFSIZE]; size_t i; char last_char = 0; struct uwsgi_router_redis_conf *urrc = (struct uwsgi_router_redis_conf *) ur->data2; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub_key = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urrc->key, urrc->key_len); if (!ub_key) return UWSGI_ROUTE_BREAK; struct uwsgi_buffer *ub_addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urrc->addr, urrc->addr_len); if (!ub_addr) { uwsgi_buffer_destroy(ub_key); return UWSGI_ROUTE_BREAK; } int fd = uwsgi_connect(ub_addr->buf, 0, 1); if (fd < 0) { uwsgi_buffer_destroy(ub_key); uwsgi_buffer_destroy(ub_addr); goto end; } // wait for connection; int ret = uwsgi.wait_write_hook(fd, uwsgi.socket_timeout); if (ret <= 0) { uwsgi_buffer_destroy(ub_key) ; uwsgi_buffer_destroy(ub_addr); close(fd); goto end; } // build the request and send it char *cmd = uwsgi_concat3n("get ", 4, ub_key->buf, ub_key->pos, "\r\n", 2); if (uwsgi_write_true_nb(fd, cmd, 6+ub_key->pos, uwsgi.socket_timeout)) { uwsgi_buffer_destroy(ub_key); uwsgi_buffer_destroy(ub_addr); free(cmd); close(fd); goto end; } uwsgi_buffer_destroy(ub_key); uwsgi_buffer_destroy(ub_addr); free(cmd); // ok, start reading the response... // first we need to get a full line; size_t found = 0; size_t pos = 0; for(;;) { ssize_t len = read(fd, buf + pos, REDIS_BUFSIZE - pos); if (len > 0) { pos += len; goto read; } if (len < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) goto wait; } close(fd); goto end; wait: ret = uwsgi.wait_read_hook(fd, uwsgi.socket_timeout); // when we have a chunk try to read the first line if (ret > 0) { len = read(fd, buf + pos, REDIS_BUFSIZE - pos); if (len > 0) { pos += len; goto read; } } close(fd); goto end; read: for(i=0;icontent_type, urrc->content_type_len)) goto error; if (uwsgi_response_add_content_length(wsgi_req, response_size)) goto error; // the first chunk could already contains part of the body size_t remains = pos-(found+2); if (remains >= response_size) { uwsgi_response_write_body_do(wsgi_req, buf+found+2, response_size); goto done; } // send what we have if (uwsgi_response_write_body_do(wsgi_req, buf+found+2, remains)) goto error; // and now start reading til the output is consumed response_size -= remains; // try to offload via the pipe engine if (wsgi_req->socket->can_offload && !ur->custom && !urrc->no_offload) { if (!uwsgi_offload_request_pipe_do(wsgi_req, fd, response_size)) { wsgi_req->via = UWSGI_VIA_OFFLOAD; return UWSGI_ROUTE_BREAK; } } while(response_size > 0) { ssize_t len = read(fd, buf, UMIN(REDIS_BUFSIZE, response_size)); if (len > 0) goto write; if (len < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) goto wait2; } goto error; wait2: ret = uwsgi.wait_read_hook(fd, uwsgi.socket_timeout); if (ret > 0) { len = read(fd, buf, UMIN(REDIS_BUFSIZE, response_size)); if (len > 0) goto write; } goto error; write: if (uwsgi_response_write_body_do(wsgi_req, buf, len)) goto error; response_size -= len; } done: close(fd); if (ur->custom) return UWSGI_ROUTE_NEXT; return UWSGI_ROUTE_BREAK; error: close(fd); return UWSGI_ROUTE_BREAK; end: return UWSGI_ROUTE_NEXT; } static int uwsgi_router_redis(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_redis; ur->data = args; ur->data_len = strlen(args); struct uwsgi_router_redis_conf *urrc = uwsgi_calloc(sizeof(struct uwsgi_router_redis_conf)); if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=', "addr", &urrc->addr, "key", &urrc->key, "content_type", &urrc->content_type, "no_offload", &urrc->no_offload, NULL)) { uwsgi_log("invalid route syntax: %s\n", args); exit(1); } if (!urrc->key || !urrc->addr) { uwsgi_log("invalid route syntax: you need to specify a redis address and key pattern\n"); return -1; } urrc->key_len = strlen(urrc->key); urrc->addr_len = strlen(urrc->addr); if (!urrc->content_type) urrc->content_type = "text/html"; urrc->content_type_len = strlen(urrc->content_type); ur->data2 = urrc; return 0; } static int uwsgi_router_redis_continue(struct uwsgi_route *ur, char *args) { uwsgi_router_redis(ur, args); ur->custom = 1; return 0; } static int uwsgi_router_redis_store(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_redis_store; ur->data = args; ur->data_len = strlen(args); struct uwsgi_router_redis_conf *urrc = uwsgi_calloc(sizeof(struct uwsgi_router_redis_conf)); if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=', "addr", &urrc->addr, "key", &urrc->key, "expires", &urrc->expires, NULL)) { uwsgi_log("invalid redisstore route syntax: %s\n", args); return -1; } if (!urrc->key || !urrc->addr) { uwsgi_log("invalid redisstore route syntax: you need to specify an address and a key\n"); return -1; } urrc->key_len = strlen(urrc->key); urrc->addr_len = strlen(urrc->addr); if (!urrc->expires) urrc->expires = "0"; ur->data2 = urrc; return 0; } static void router_redis_register() { uwsgi_register_router("redis", uwsgi_router_redis); uwsgi_register_router("redis-continue", uwsgi_router_redis_continue); uwsgi_register_router("redisstore", uwsgi_router_redis_store); uwsgi_register_router("redis-store", uwsgi_router_redis_store); } #endif struct uwsgi_plugin router_redis_plugin = { .name = "router_redis", #ifdef UWSGI_ROUTING .on_load = router_redis_register, #endif }; uwsgi-2.0.29/plugins/router_redis/uwsgiplugin.py000066400000000000000000000001241477626554400221010ustar00rootroot00000000000000NAME='router_redis' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['router_redis'] uwsgi-2.0.29/plugins/router_rewrite/000077500000000000000000000000001477626554400175305ustar00rootroot00000000000000uwsgi-2.0.29/plugins/router_rewrite/router_rewrite.c000066400000000000000000000054541477626554400227650ustar00rootroot00000000000000#include #ifdef UWSGI_ROUTING extern struct uwsgi_server uwsgi; static int uwsgi_routing_func_rewrite(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char *tmp_qs = NULL; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; uint16_t path_info_len = ub->pos; uint16_t query_string_len = 0; char *query_string = memchr(ub->buf, '?', ub->pos); if (query_string) { path_info_len = query_string - ub->buf; query_string++; query_string_len = ub->pos - (path_info_len + 1); if (wsgi_req->query_string_len > 0) { tmp_qs = uwsgi_concat4n(query_string, query_string_len, "&", 1, wsgi_req->query_string, wsgi_req->query_string_len, "", 0); query_string = tmp_qs; query_string_len = strlen(query_string); } } // over engineering, could be required in the future... else { if (wsgi_req->query_string_len > 0) { query_string = wsgi_req->query_string; query_string_len = wsgi_req->query_string_len; } else { query_string = ""; } } char *path_info = uwsgi_malloc(path_info_len); http_url_decode(ub->buf, &path_info_len, path_info); char *ptr = uwsgi_req_append(wsgi_req, "PATH_INFO", 9, path_info, path_info_len); if (!ptr) goto clear; free(path_info); path_info = NULL; // set new path_info wsgi_req->path_info = ptr; wsgi_req->path_info_len = path_info_len; ptr = uwsgi_req_append(wsgi_req, "QUERY_STRING", 12, query_string, query_string_len); if (!ptr) goto clear; // set new query_string wsgi_req->query_string = ptr; wsgi_req->query_string_len = query_string_len; uwsgi_buffer_destroy(ub); if (tmp_qs) free(tmp_qs); if (ur->custom) return UWSGI_ROUTE_CONTINUE; return UWSGI_ROUTE_NEXT; clear: uwsgi_buffer_destroy(ub); if (tmp_qs) free(tmp_qs); if (path_info) free(path_info); return UWSGI_ROUTE_BREAK; } static int uwsgi_router_rewrite(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_rewrite; ur->data = args; ur->data_len = strlen(args); return 0; } static int uwsgi_router_rewrite_last(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_rewrite; ur->data = args; ur->data_len = strlen(args); ur->custom = 1; return 0; } static void router_rewrite_register(void) { uwsgi_register_router("rewrite", uwsgi_router_rewrite); uwsgi_register_router("rewrite-last", uwsgi_router_rewrite_last); } struct uwsgi_plugin router_rewrite_plugin = { .name = "router_rewrite", .on_load = router_rewrite_register, }; #else struct uwsgi_plugin router_rewrite_plugin = { .name = "router_rewrite", }; #endif uwsgi-2.0.29/plugins/router_rewrite/uwsgiplugin.py000066400000000000000000000001301477626554400224510ustar00rootroot00000000000000NAME='router_rewrite' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['router_rewrite'] uwsgi-2.0.29/plugins/router_spnego/000077500000000000000000000000001477626554400173425ustar00rootroot00000000000000uwsgi-2.0.29/plugins/router_spnego/router_spnego.c000066400000000000000000000173051477626554400224070ustar00rootroot00000000000000#include #include extern struct uwsgi_server uwsgi; /* At the first request (without authentication) uWSGI sends back a token The client resend-the request with its token Following requests could need a new token or are simply accepted */ // log errors... static void uwsgi_spnego_err(const char *func, OM_uint32 err_maj, OM_uint32 err_min) { OM_uint32 ret; OM_uint32 min_stat; OM_uint32 msg_ctx = 0; gss_buffer_desc status_string; ret = gss_display_status (&min_stat, err_maj, GSS_C_GSS_CODE, GSS_C_NO_OID, &msg_ctx, &status_string); if (GSS_ERROR(ret)) return; uwsgi_log("[uwsgi-spnego] %s() error (major): %.*s\n", func, status_string.length, status_string.value); gss_release_buffer(&min_stat, &status_string); ret = gss_display_status (&min_stat, err_min, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string); if (GSS_ERROR(ret)) return; if (status_string.length > 0) { uwsgi_log("[uwsgi-spnego] %s() error (minor): %.*s\n",func, status_string.length, status_string.value); } if (status_string.value) { gss_release_buffer(&min_stat, &status_string); } } static char *uwsgi_spnego_new_token(struct wsgi_request *wsgi_req, struct uwsgi_route *ur, char *token_buf, size_t token_buf_len, size_t *b64_len) { char *b64 = NULL; OM_uint32 ret; OM_uint32 min_ret; gss_buffer_desc service = GSS_C_EMPTY_BUFFER; struct uwsgi_buffer *ub = NULL; if (ur->data_len) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) goto end; service.value = ub->buf; service.length = ub->pos; } gss_name_t server_name = GSS_C_NO_NAME; gss_name_t client_name = GSS_C_NO_NAME; gss_ctx_id_t context = GSS_C_NO_CONTEXT; gss_cred_id_t cred = GSS_C_NO_CREDENTIAL; gss_buffer_desc token = GSS_C_EMPTY_BUFFER; token.value = token_buf; token.length = token_buf_len; if (service.length == 0) { service.value = "HTTP"; service.length = 4; } ret = gss_import_name(&min_ret, &service, GSS_C_NT_HOSTBASED_SERVICE, &server_name); if (GSS_ERROR(ret)) { uwsgi_spnego_err("gss_import_name", ret, min_ret); goto end; } ret = gss_acquire_cred(&min_ret, server_name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, GSS_C_ACCEPT, &cred, NULL, NULL); if (GSS_ERROR(ret)) { uwsgi_spnego_err("gss_acquire_cred", ret, min_ret); goto end; } gss_buffer_desc output = GSS_C_EMPTY_BUFFER; ret = gss_accept_sec_context(&min_ret, &context, cred, &token, GSS_C_NO_CHANNEL_BINDINGS, &client_name, NULL, &output, NULL, NULL, NULL); if (GSS_ERROR(ret)) { uwsgi_spnego_err("gss_accept_sec_context", ret, min_ret); if (output.value) { gss_release_buffer(&min_ret, &output); } goto end; } if (output.length) { b64 = uwsgi_base64_encode(output.value, output.length, b64_len); if (output.value) { gss_release_buffer(&min_ret, &output); } if (!b64) { goto end; } ret = gss_display_name(&min_ret, client_name, &output, NULL); if (GSS_ERROR(ret)) { uwsgi_spnego_err("gss_display_name", ret, min_ret); if (output.value) { gss_release_buffer(&min_ret, &output); } free(b64); b64 = NULL; goto end; } wsgi_req->remote_user = uwsgi_req_append(wsgi_req, "REMOTE_USER", 11, output.value, output.length); if (!wsgi_req->remote_user) { if (output.value) { gss_release_buffer(&min_ret, &output); } free(b64); b64 = NULL; goto end; } wsgi_req->remote_user_len = output.length; if (output.value) { gss_release_buffer(&min_ret, &output); } if (!wsgi_req->remote_user) { wsgi_req->remote_user_len = 0; free(b64); b64 = NULL; goto end; } } end: if (server_name != GSS_C_NO_NAME) { gss_release_name(&min_ret, &server_name); } if (client_name != GSS_C_NO_NAME) { gss_release_name(&min_ret, &client_name); } if (cred != GSS_C_NO_CREDENTIAL) { gss_release_cred(&min_ret, &cred); } if (context != GSS_C_NO_CONTEXT) { gss_delete_sec_context(&min_ret, &context, GSS_C_NO_BUFFER); } if (ub) { uwsgi_buffer_destroy(ub); } return b64; } static int uwsgi_routing_func_spnego(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char *negotiate = NULL; size_t negotiate_len = 0; size_t b64_len = 0; // check for "Negotiate " string at least if (wsgi_req->authorization_len > 10) { if (strncmp(wsgi_req->authorization, "Negotiate ", 10)) goto forbidden; char *token = uwsgi_base64_decode(wsgi_req->authorization+10, wsgi_req->authorization_len-10, &b64_len); if (token) { negotiate = uwsgi_spnego_new_token(wsgi_req, ur, token, b64_len, &negotiate_len); free(token); if (negotiate) { char *auth_header = uwsgi_concat2n("WWW-Authenticate: Negotiate ", 28, negotiate, negotiate_len); free(negotiate); uwsgi_additional_header_add(wsgi_req, auth_header, negotiate_len + 28); free(auth_header); return UWSGI_ROUTE_NEXT; } if (ur->custom) return UWSGI_ROUTE_NEXT; } } forbidden: if (uwsgi_response_prepare_headers(wsgi_req, "401 Authorization Required", 26)) goto end; if (uwsgi_response_add_connection_close(wsgi_req)) goto end; if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) goto end; if (negotiate && negotiate_len) { char *neg_token = uwsgi_concat2n("Negotiate ", 10, negotiate, negotiate_len); int ret = uwsgi_response_add_header(wsgi_req, "WWW-Authenticate", 16, neg_token, 10 + negotiate_len); free(neg_token); if (ret) goto end; } else { if (uwsgi_response_add_header(wsgi_req, "WWW-Authenticate", 16, "Negotiate", 9)) goto end; } uwsgi_response_write_body_do(wsgi_req, "Unauthorized", 12); end: if (ur->custom) return UWSGI_ROUTE_NEXT; return UWSGI_ROUTE_BREAK; } static int uwsgi_router_spnego(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_spnego; ur->data = args ; if (args) { ur->data_len = strlen(args); } return 0; } static int uwsgi_router_spnego_next(struct uwsgi_route *ur, char *args) { ur->custom = 1; return uwsgi_router_spnego(ur, args); } static void router_spnego_register(void) { uwsgi_register_router("spnego", uwsgi_router_spnego); uwsgi_register_router("spnego-next", uwsgi_router_spnego_next); } struct uwsgi_plugin router_spnego_plugin = { .name = "router_spnego", .on_load = router_spnego_register, }; uwsgi-2.0.29/plugins/router_spnego/uwsgiplugin.py000066400000000000000000000003311477626554400222660ustar00rootroot00000000000000import os NAME='router_spnego' CFLAGS = os.popen('krb5-config --cflags gssapi').read().rstrip().split() LDFLAGS = [] LIBS = os.popen('krb5-config --libs gssapi').read().rstrip().split() GCC_LIST = ['router_spnego'] uwsgi-2.0.29/plugins/router_static/000077500000000000000000000000001477626554400173365ustar00rootroot00000000000000uwsgi-2.0.29/plugins/router_static/router_static.c000066400000000000000000000260011477626554400223700ustar00rootroot00000000000000#include #ifdef UWSGI_ROUTING extern struct uwsgi_server uwsgi; struct uwsgi_router_file_conf { char *filename; size_t filename_len; char *status; size_t status_len; char *content_type; size_t content_type_len; char *mime; char *no_cl; char *no_headers; }; int uwsgi_routing_func_static(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; uwsgi_file_serve(wsgi_req, ub->buf, ub->pos, NULL, 0, 1); uwsgi_buffer_destroy(ub); if (ur->custom == 1) return UWSGI_ROUTE_NEXT; return UWSGI_ROUTE_BREAK; } int uwsgi_routing_func_file(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char buf[32768]; struct stat st; int ret = UWSGI_ROUTE_BREAK; size_t remains = 0; struct uwsgi_router_file_conf *urfc = (struct uwsgi_router_file_conf *) ur->data2; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->filename, urfc->filename_len); if (!ub) return UWSGI_ROUTE_BREAK; int fd = open(ub->buf, O_RDONLY); if (fd < 0) { if (ur->custom) ret = UWSGI_ROUTE_NEXT; goto end; } if (fstat(fd, &st)) { goto end2; } struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len); if (!ub_s) goto end2; // static file - don't update avg_rt after request wsgi_req->do_not_account_avg_rt = 1; if (urfc->no_headers) goto send; if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) { uwsgi_buffer_destroy(ub_s); goto end2; } uwsgi_buffer_destroy(ub_s); if (!urfc->no_cl) { if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end2; } if (urfc->mime) { size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(ub->buf, ub->pos, &mime_type_len); if (mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end2; } else { if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2; } } else { if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2; } send: remains = st.st_size; while(remains) { ssize_t rlen = read(fd, buf, UMIN(32768, remains)); if (rlen <= 0) goto end2; if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) goto end2; remains -= rlen; } end2: close(fd); end: uwsgi_buffer_destroy(ub); return ret; } int uwsgi_routing_func_sendfile(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct stat st; int ret = UWSGI_ROUTE_BREAK; struct uwsgi_router_file_conf *urfc = (struct uwsgi_router_file_conf *) ur->data2; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->filename, urfc->filename_len); if (!ub) return UWSGI_ROUTE_BREAK; int fd = open(ub->buf, O_RDONLY); if (fd < 0) { if (ur->custom) ret = UWSGI_ROUTE_NEXT; goto end; } if (fstat(fd, &st)) { goto end2; } struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len); if (!ub_s) goto end2; // static file - don't update avg_rt after request wsgi_req->do_not_account_avg_rt = 1; if (urfc->no_headers) goto send; if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) { uwsgi_buffer_destroy(ub_s); goto end2; } uwsgi_buffer_destroy(ub_s); if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end2; if (urfc->mime) { size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(ub->buf, ub->pos, &mime_type_len); if (mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end2; } else { if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2; } } else { if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2; } send: if (!wsgi_req->headers_sent) { if (uwsgi_response_write_headers_do(wsgi_req)) goto end2; } if (!uwsgi_simple_sendfile(wsgi_req, fd, 0, st.st_size)) { wsgi_req->via = UWSGI_VIA_SENDFILE; wsgi_req->response_size += st.st_size; } end2: close(fd); end: uwsgi_buffer_destroy(ub); return ret; } int uwsgi_routing_func_fastfile(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct stat st; int ret = UWSGI_ROUTE_BREAK; struct uwsgi_router_file_conf *urfc = (struct uwsgi_router_file_conf *) ur->data2; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->filename, urfc->filename_len); if (!ub) return UWSGI_ROUTE_BREAK; int fd = open(ub->buf, O_RDONLY); if (fd < 0) { if (ur->custom) ret = UWSGI_ROUTE_NEXT; goto end; } if (fstat(fd, &st)) { goto end2; } struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len); if (!ub_s) goto end2; // static file - don't update avg_rt after request wsgi_req->do_not_account_avg_rt = 1; if (urfc->no_headers) goto send; if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) { uwsgi_buffer_destroy(ub_s); goto end2; } uwsgi_buffer_destroy(ub_s); if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end2; if (urfc->mime) { size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(ub->buf, ub->pos, &mime_type_len); if (mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end2; } else { if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2; } } else { if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2; } send: if (!wsgi_req->headers_sent) { if (uwsgi_response_write_headers_do(wsgi_req)) goto end2; } if (wsgi_req->socket->can_offload) { if (!uwsgi_offload_request_sendfile_do(wsgi_req, fd, 0, st.st_size)) { wsgi_req->via = UWSGI_VIA_OFFLOAD; wsgi_req->response_size += st.st_size; // the fd will be closed by the offload engine goto end; } } if (!uwsgi_simple_sendfile(wsgi_req, fd, 0, st.st_size)) { wsgi_req->via = UWSGI_VIA_SENDFILE; wsgi_req->response_size += st.st_size; } end2: close(fd); end: uwsgi_buffer_destroy(ub); return ret; } static int uwsgi_router_static(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_static; ur->data = args; ur->data_len = strlen(args); return 0; } static int uwsgi_router_static_next(struct uwsgi_route *ur, char *args) { ur->custom = 1; return uwsgi_router_static(ur, args); } static int uwsgi_router_file(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_file; ur->data = args; ur->data_len = strlen(args); struct uwsgi_router_file_conf *urfc = uwsgi_calloc(sizeof(struct uwsgi_router_file_conf)); if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=', "filename", &urfc->filename, "status", &urfc->status, "content_type", &urfc->content_type, "nocl", &urfc->no_cl, "no_cl", &urfc->no_cl, "no_content_length", &urfc->no_cl, "mime", &urfc->mime, "no_headers", &urfc->no_headers, NULL)) { uwsgi_log("invalid file route syntax: %s\n", args); return -1; } if (!urfc->filename) { uwsgi_log("you have to specifify a filename for the \"file\" router\n"); return -1; } urfc->filename_len = strlen(urfc->filename); if (!urfc->content_type) { urfc->content_type = "text/html"; } urfc->content_type_len = strlen(urfc->content_type); if (!urfc->status) { urfc->status = "200 OK"; } urfc->status_len = strlen(urfc->status); ur->data2 = urfc; return 0; } static int uwsgi_router_file_next(struct uwsgi_route *ur, char *args) { ur->custom = 1; return uwsgi_router_file(ur, args); } static int uwsgi_router_sendfile(struct uwsgi_route *ur, char *args) { int ret = uwsgi_router_file(ur, args); ur->func = uwsgi_routing_func_sendfile; return ret; } static int uwsgi_router_sendfile_next(struct uwsgi_route *ur, char *args) { ur->custom = 1; int ret = uwsgi_router_file(ur, args); ur->func = uwsgi_routing_func_sendfile; return ret; } static int uwsgi_router_fastfile(struct uwsgi_route *ur, char *args) { int ret = uwsgi_router_file(ur, args); ur->func = uwsgi_routing_func_fastfile; return ret; } static int uwsgi_router_fastfile_next(struct uwsgi_route *ur, char *args) { ur->custom = 1; int ret = uwsgi_router_file(ur, args); ur->func = uwsgi_routing_func_fastfile; return ret; } static void router_static_register(void) { uwsgi_register_router("static", uwsgi_router_static); uwsgi_register_router("static-next", uwsgi_router_static_next); uwsgi_register_router("file", uwsgi_router_file); uwsgi_register_router("file-next", uwsgi_router_file_next); uwsgi_register_router("sendfile", uwsgi_router_sendfile); uwsgi_register_router("sendfile-next", uwsgi_router_sendfile_next); uwsgi_register_router("fastfile", uwsgi_router_fastfile); uwsgi_register_router("fastfile-next", uwsgi_router_fastfile_next); } struct uwsgi_plugin router_static_plugin = { .name = "router_static", .on_load = router_static_register, }; #else struct uwsgi_plugin router_static_plugin = { .name = "router_static", }; #endif uwsgi-2.0.29/plugins/router_static/uwsgiplugin.py000066400000000000000000000001261477626554400222640ustar00rootroot00000000000000NAME='router_static' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['router_static'] uwsgi-2.0.29/plugins/router_uwsgi/000077500000000000000000000000001477626554400172055ustar00rootroot00000000000000uwsgi-2.0.29/plugins/router_uwsgi/router_uwsgi.c000066400000000000000000000120331477626554400221060ustar00rootroot00000000000000#include #ifdef UWSGI_ROUTING extern struct uwsgi_server uwsgi; static int uwsgi_routing_func_uwsgi_simple(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_header *uh = (struct uwsgi_header *) ur->data; wsgi_req->uh->modifier1 = uh->modifier1; wsgi_req->uh->modifier2 = uh->modifier2; // set appid if (ur->data2_len > 0) { wsgi_req->appid = ur->data2; wsgi_req->appid_len = ur->data2_len; char *ptr = uwsgi_req_append(wsgi_req, "UWSGI_APPID", 11, ur->data2, ur->data2_len); if (ptr) { // fill iovec if (wsgi_req->var_cnt + 2 < uwsgi.vec_size - (4 + 1)) { wsgi_req->hvec[wsgi_req->var_cnt].iov_base = ptr - (2 + 11); wsgi_req->hvec[wsgi_req->var_cnt].iov_len = 11; wsgi_req->var_cnt++; wsgi_req->hvec[wsgi_req->var_cnt].iov_base = ptr; wsgi_req->hvec[wsgi_req->var_cnt].iov_len = ur->data2_len; wsgi_req->var_cnt++; } } } return UWSGI_ROUTE_CONTINUE; } static int uwsgi_routing_func_uwsgi_remote(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_header *uh = (struct uwsgi_header *) ur->data; char *addr = ur->data + sizeof(struct uwsgi_header); char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub_addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, addr, strlen(addr)); if (!ub_addr) return UWSGI_ROUTE_BREAK; // mark a route request wsgi_req->via = UWSGI_VIA_ROUTE; // append appid if (ur->data2_len > 0) { uwsgi_req_append(wsgi_req, "UWSGI_APPID", 11, ur->data2, ur->data2_len); } size_t remains = wsgi_req->post_cl - wsgi_req->proto_parser_remains; struct uwsgi_buffer *ub = uwsgi_buffer_new(4 + wsgi_req->uh->pktsize + wsgi_req->proto_parser_remains); uh->pktsize = wsgi_req->uh->pktsize; if (uwsgi_buffer_append(ub, (char *) uh, 4)) goto end; if (uwsgi_buffer_append(ub, wsgi_req->buffer, wsgi_req->uh->pktsize)) goto end; if (wsgi_req->proto_parser_remains > 0) { if (uwsgi_buffer_append(ub, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains)) { goto end; } wsgi_req->post_pos += wsgi_req->proto_parser_remains; wsgi_req->proto_parser_remains = 0; } // ok now if have offload threads, directly use them if (!wsgi_req->post_file && !ur->custom && wsgi_req->socket->can_offload) { // append buffered body if (uwsgi.post_buffering > 0 && wsgi_req->post_cl > 0) { if (uwsgi_buffer_append(ub, wsgi_req->post_buffering_buf, wsgi_req->post_cl)) { goto end; } } if (!uwsgi_offload_request_net_do(wsgi_req, ub_addr->buf, ub)) { wsgi_req->via = UWSGI_VIA_OFFLOAD; wsgi_req->status = 202; uwsgi_buffer_destroy(ub_addr); return UWSGI_ROUTE_BREAK; } } if (uwsgi_proxy_nb(wsgi_req, ub_addr->buf, ub, remains, uwsgi.socket_timeout)) { uwsgi_log("error routing request to uwsgi server %s\n", ub_addr->buf); } end: uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub_addr); return UWSGI_ROUTE_BREAK; } static void uwsgi_router_uwsgi_free(struct uwsgi_route *ur) { free(ur->data); } static int uwsgi_router_uwsgi(struct uwsgi_route *ur, char *args) { // check for commas char *comma1 = strchr(args, ','); if (!comma1) { uwsgi_log("invalid route syntax: %s\n", args); return -1; } char *comma2 = strchr(comma1+1, ','); if (!comma2) { uwsgi_log("invalid route syntax: %s\n", args); return -1; } char *comma3 = strchr(comma2+1, ','); if (comma3) { *comma3 = 0; } *comma1 = 0; *comma2 = 0; // simple modifier remapper if (*args == 0) { struct uwsgi_header *uh = uwsgi_calloc(sizeof(struct uwsgi_header)); ur->func = uwsgi_routing_func_uwsgi_simple; ur->data = (void *) uh; ur->free = uwsgi_router_uwsgi_free; uh->modifier1 = atoi(comma1+1); uh->modifier2 = atoi(comma2+1); if (comma3) { ur->data2 = comma3+1; ur->data2_len = strlen(ur->data2); } return 0; } else { struct uwsgi_header *uh = uwsgi_calloc(sizeof(struct uwsgi_header) + strlen(args) + 1); ur->func = uwsgi_routing_func_uwsgi_remote; ur->data = (void *) uh; ur->free = uwsgi_router_uwsgi_free; uh->modifier1 = atoi(comma1+1); uh->modifier2 = atoi(comma2+1); if (comma3) { ur->data2 = comma3+1; ur->data2_len = strlen(ur->data2); } void *ptr = (void *) uh; strcpy(ptr+sizeof(struct uwsgi_header), args); return 0; } return -1; } static int uwsgi_router_proxyuwsgi(struct uwsgi_route *ur, char *args) { ur->custom = 1; return uwsgi_router_uwsgi(ur, args); } static void router_uwsgi_register(void) { uwsgi_register_router("uwsgi", uwsgi_router_uwsgi); uwsgi_register_router("proxyuwsgi", uwsgi_router_proxyuwsgi); } struct uwsgi_plugin router_uwsgi_plugin = { .name = "router_uwsgi", .on_load = router_uwsgi_register, }; #else struct uwsgi_plugin router_uwsgi_plugin = { .name = "router_uwsgi", }; #endif uwsgi-2.0.29/plugins/router_uwsgi/uwsgiplugin.py000066400000000000000000000001241477626554400221310ustar00rootroot00000000000000NAME='router_uwsgi' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['router_uwsgi'] uwsgi-2.0.29/plugins/router_xmldir/000077500000000000000000000000001477626554400173465ustar00rootroot00000000000000uwsgi-2.0.29/plugins/router_xmldir/router_xmldir.c000066400000000000000000000141151477626554400224130ustar00rootroot00000000000000/* * Copyright (C) 2013 Unbit S.a.s. * Copyright (C) 2013 Guido Berhoerster * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #ifndef UWSGI_XML_LIBXML2 #error you need a libxml2-enabled build of uWSGI to use the router_xmldir plugin #endif #include static struct router_xmldir_conf { char *codeset; } conf; void *xrealloc(void *ptr, size_t size) { void *tmp; tmp = realloc(ptr, size); if (tmp == NULL) { uwsgi_error("realloc()"); exit(1); } return (tmp); } char *to_utf8(char *codeset, char *in) { size_t buf_size; size_t buf_offset; size_t in_remaining; size_t buf_remaining; size_t ret; char *buf = NULL; char *buf_ptr; char *in_ptr = in; static iconv_t cd = (iconv_t)-1; /* UTF-8 encoded Unicode replacement char (U+FFFD) */ const char repl[] = "\xef\xbf\xbd"; if (cd == (iconv_t)-1) { if ((cd = iconv_open("UTF-8", codeset)) == (iconv_t)-1) { uwsgi_error("iconv_open"); return (NULL); } } in_remaining = strlen(in) + 1; buf_size = buf_remaining = in_remaining; buf = buf_ptr = uwsgi_malloc(buf_size); while (in_remaining > (size_t)0) { ret = iconv(cd, &in_ptr, &in_remaining, &buf_ptr, &buf_remaining); if (ret == (size_t)-1) { switch (errno) { case EINVAL: /* truncate */ in_remaining = 0; *buf_ptr = '\0'; break; case EILSEQ: /* * insert a replacement character for each * illegal sequence */ in_ptr++; in_remaining--; if (buf_remaining < sizeof (repl)) { buf_size += in_remaining + sizeof (repl) - 1; buf_remaining += in_remaining + sizeof (repl) - 1; buf_offset = buf_ptr - buf; buf = xrealloc(buf, buf_size); buf_ptr = buf + buf_offset; } strcat(buf_ptr, repl); buf_ptr += sizeof (repl) - 1; buf_remaining -= sizeof (repl) - 1; break; case E2BIG: buf_size += in_remaining; buf_remaining += in_remaining; buf_offset = buf_ptr - buf; buf = xrealloc(buf, buf_size); buf_ptr = buf + buf_offset; break; default: uwsgi_error("iconv"); free(buf); return (NULL); } } } buf = xrealloc(buf, strlen(buf) + 1); return (buf); } static int uwsgi_routing_func_xmldir(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ char **subject; uint16_t *subject_len; char *dirname; struct uwsgi_buffer *ub; char *name = NULL; char *path = NULL; int i; int n; struct dirent **tasklist; xmlDoc *rdoc; xmlNode *rtree; xmlNodePtr entrynode; char *path_info = NULL; struct stat sb; size_t sizebuf_len; char *sizebuf; char timebuf[20]; int xlen = 0; subject = (char **) (((char *)(wsgi_req))+ur->subject); subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) { uwsgi_500(wsgi_req); return UWSGI_ROUTE_BREAK; } dirname = ub->buf; path_info = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "", 1); n = scandir(dirname, &tasklist, 0, alphasort); if (n < 0) { uwsgi_404(wsgi_req); goto out; } rdoc = xmlNewDoc(BAD_CAST "1.0"); rtree = xmlNewNode(NULL, BAD_CAST "index"); xmlNewProp(rtree, BAD_CAST "path", BAD_CAST path_info); xmlDocSetRootElement(rdoc, rtree); for(i = 0; i < n; i++) { if ((strcmp(tasklist[i]->d_name, ".") == 0) || (strcmp(tasklist[i]->d_name, "..") == 0)) { goto next_entry; } path = uwsgi_concat3(dirname, "/", tasklist[i]->d_name); if (lstat(path, &sb) == -1) { goto next_entry; } name = to_utf8(conf.codeset, tasklist[i]->d_name); if (name == NULL) { goto next_entry; } if (S_ISDIR(sb.st_mode)) { entrynode = xmlNewTextChild(rtree, NULL, BAD_CAST "directory", BAD_CAST name); } else if (S_ISREG(sb.st_mode)) { entrynode = xmlNewTextChild(rtree, NULL, BAD_CAST "file", BAD_CAST name); } else { /* skip everything but directories and regular files */ goto next_entry; } sizebuf_len = snprintf(NULL, 0, "%jd", (intmax_t) sb.st_size); sizebuf = uwsgi_malloc(sizebuf_len + 1); snprintf(sizebuf, sizebuf_len + 1, "%jd", (intmax_t) sb.st_size); xmlNewProp(entrynode, BAD_CAST "size", BAD_CAST sizebuf); free(sizebuf); strftime(timebuf, sizeof (timebuf), "%Y-%m-%dT%H:%M:%S", localtime(&sb.st_mtime)); xmlNewProp(entrynode, BAD_CAST "mtime", BAD_CAST timebuf); next_entry: free(path); path = NULL; free(tasklist[i]); free(name); name = NULL; } free(tasklist); xmlChar *xmlbuf; xmlDocDumpFormatMemory(rdoc, &xmlbuf, &xlen, 1); uwsgi_response_prepare_headers(wsgi_req,"200 OK", 6); uwsgi_response_write_body_do(wsgi_req, (char *) xmlbuf, xlen); xmlFreeDoc(rdoc); xmlFree(xmlbuf); out: uwsgi_buffer_destroy(ub); free(path_info); return UWSGI_ROUTE_BREAK; } static int uwsgi_router_xmldir(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_xmldir; ur->data = args; ur->data_len = strlen(args); return 0; } static void router_xmldir_register(void) { char *codeset; uwsgi_register_router("xmldir", uwsgi_router_xmldir); setlocale(LC_ALL, ""); codeset = nl_langinfo(CODESET); if (*codeset == '\0') { codeset = "ASCII"; } conf.codeset = uwsgi_str(codeset); if (conf.codeset == NULL) { uwsgi_error("strdup()"); exit(1); } } struct uwsgi_plugin router_xmldir_plugin = { .name = "router_xmldir", .on_load = router_xmldir_register, }; uwsgi-2.0.29/plugins/router_xmldir/uwsgiplugin.py000066400000000000000000000001251477626554400222730ustar00rootroot00000000000000NAME='router_xmldir' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['router_xmldir'] uwsgi-2.0.29/plugins/rpc/000077500000000000000000000000001477626554400152335ustar00rootroot00000000000000uwsgi-2.0.29/plugins/rpc/rpc_plugin.c000066400000000000000000000507411477626554400175500ustar00rootroot00000000000000#include #ifdef UWSGI_XML_LIBXML2 #include #include #endif extern struct uwsgi_server uwsgi; /* rpc-HTTP interface. modifier2 changes the parser behaviours: 0 -> return uwsgi header + rpc response 1 -> return raw rpc response 2 -> split PATH_INFO to get func name and args and return as HTTP response with content_type as application/binary or Accept request header (if different from *) 3 -> set xmlrpc wrapper (requires libxml2) 4 -> set jsonrpc wrapper (requires libjansson) 5 -> used in uwsgi response to signal the response is a uwsgi dictionary followed by the body (the dictionary must contains a CONTENT_LENGTH key) */ #ifdef UWSGI_XML_LIBXML2 // raise error on non-string args static int uwsgi_rpc_xmlrpc_string(xmlNode *element, char **argv, uint16_t *argvs, uint8_t *argc) { xmlNode *node; for (node = element->children; node; node = node->next) { if (node->type == XML_ELEMENT_NODE) { if (strcmp((char *) node->name, "string")) { return -1; } if (!node->children) return -1; if (!node->children->content) return -1; *argc+=1; argv[*argc] = (char *) node->children->content; argvs[*argc] = strlen(argv[*argc]); } } return 0; } static int uwsgi_rpc_xmlrpc_value(xmlNode *element, char **argv, uint16_t *argvs, uint8_t *argc) { xmlNode *node; for (node = element->children; node; node = node->next) { if (node->type == XML_ELEMENT_NODE) { if (!strcmp((char *) node->name, "value")) { if (uwsgi_rpc_xmlrpc_string(node, argv, argvs, argc)) { return -1; } } } } return 0; } static int uwsgi_rpc_xmlrpc_args(xmlNode *element, char **argv, uint16_t *argvs, uint8_t *argc) { xmlNode *node; for (node = element->children; node; node = node->next) { if (node->type == XML_ELEMENT_NODE) { if (!strcmp((char *) node->name, "param")) { if (uwsgi_rpc_xmlrpc_value(node, argv, argvs, argc)) { return -1; } } } } return 0; } static int uwsgi_rpc_xmlrpc(struct wsgi_request *wsgi_req, xmlDoc *doc, char **argv, uint16_t *argvs, uint8_t *argc, char **response_buf) { char *method = NULL; xmlNode *element = xmlDocGetRootElement(doc); if (!element) return -1; if (strcmp((char *) element->name, "methodCall")) return -1; *argc = 0; xmlNode *node; for (node = element->children; node; node = node->next) { if (node->type == XML_ELEMENT_NODE) { if (!strcmp((char *) node->name, "methodName") && node->children) { method = (char *) node->children->content; } else if (!strcmp((char *) node->name, "params")) { if (uwsgi_rpc_xmlrpc_args(node, argv, argvs, argc)) return -1; } } } if (!method) return -1; uint64_t content_len = uwsgi_rpc(method, *argc, argv+1, argvs+1, response_buf); if (!*response_buf) return -1; // add final NULL byte char *tmp_buf = realloc(*response_buf, content_len + 1); if (!tmp_buf) return -1; *response_buf = tmp_buf; *response_buf[content_len] = 0; xmlDoc *rdoc = xmlNewDoc(BAD_CAST "1.0"); xmlNode *m_response = xmlNewNode(NULL, BAD_CAST "methodResponse"); xmlDocSetRootElement(rdoc, m_response); xmlNode *x_params = xmlNewChild(m_response, NULL, BAD_CAST "params", NULL); xmlNode *x_param = xmlNewChild(x_params, NULL, BAD_CAST "param", NULL); xmlNode *x_value = xmlNewChild(x_param, NULL, BAD_CAST "value", NULL); xmlNewTextChild(x_value, NULL, BAD_CAST "string", BAD_CAST response_buf); xmlChar *xmlbuf; int xlen = 0; xmlDocDumpFormatMemory(rdoc, &xmlbuf, &xlen, 1); if (uwsgi_response_prepare_headers(wsgi_req,"200 OK", 6)) { xmlFreeDoc(rdoc); xmlFree(xmlbuf); return -1; } uwsgi_response_add_content_length(wsgi_req, xlen); uwsgi_response_add_content_type(wsgi_req, "application/xml", 15); uwsgi_response_write_body_do(wsgi_req, (char *) xmlbuf, xlen); xmlFreeDoc(rdoc); xmlFree(xmlbuf); return 0; } #endif static int uwsgi_rpc_request(struct wsgi_request *wsgi_req) { // this is the list of args char *argv[UMAX8]; // this is the size of each argument uint16_t argvs[UMAX8]; // maximum number of supported arguments uint8_t argc = 0xff; // response output char *response_buf = NULL; // response size size_t content_len = 0; /* Standard RPC request */ if (!wsgi_req->uh->pktsize) { uwsgi_log("Empty RPC request. skip.\n"); return -1; } if (wsgi_req->uh->modifier2 == 2) { if (uwsgi_parse_vars(wsgi_req)) { uwsgi_log("Invalid RPC request. skip.\n"); return -1; } if (wsgi_req->path_info_len == 0) { uwsgi_500(wsgi_req); return UWSGI_OK; } char *args = NULL; if (wsgi_req->path_info[0] == '/') { args = uwsgi_concat2n(wsgi_req->path_info+1, wsgi_req->path_info_len-1, "", 0); } else { args = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "", 0); } argc = 0; char *ctx = NULL; argv[0] = strtok_r(args, "/", &ctx); if (!argv[0]) { free(args); uwsgi_500(wsgi_req); return UWSGI_OK; } char *p = strtok_r(NULL, "/", &ctx); while(p) { argc++; argv[argc] = p; argvs[argc] = strlen(p); p = strtok_r(NULL, "/", &ctx); } content_len = uwsgi_rpc(argv[0], argc, argv+1, argvs+1, &response_buf); free(args); if (!content_len) { if (response_buf) free(response_buf); uwsgi_404(wsgi_req); return UWSGI_OK; } if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) {if (response_buf) free(response_buf); return -1;} if (uwsgi_response_add_content_length(wsgi_req, content_len)) {if (response_buf) free(response_buf); return -1;} uint16_t ctype_len = 0; char *ctype = uwsgi_get_var(wsgi_req, "HTTP_ACCEPT", 11, &ctype_len); if (!ctype || !uwsgi_strncmp(ctype, ctype_len, "*/*" ,3) || !uwsgi_strncmp(ctype, ctype_len, "*", 1)) { if (uwsgi_response_add_content_type(wsgi_req, "application/binary", 18)) {if (response_buf) free(response_buf); return -1;} } else { if (uwsgi_response_add_content_type(wsgi_req, ctype, ctype_len)) {if (response_buf) free(response_buf); return -1;} } goto sendbody; } #ifdef UWSGI_XML_LIBXML2 if (wsgi_req->uh->modifier2 == 3) { if (wsgi_req->post_cl == 0) { uwsgi_500(wsgi_req); return UWSGI_OK; } ssize_t body_len = 0; char *body = uwsgi_request_body_read(wsgi_req, wsgi_req->post_cl, &body_len); xmlDoc *doc = xmlReadMemory(body, body_len, NULL, NULL, 0); if (!doc) { uwsgi_500(wsgi_req); return UWSGI_OK; } int ret = uwsgi_rpc_xmlrpc(wsgi_req, doc, argv, argvs, &argc, &response_buf); xmlFreeDoc(doc); if (ret) { uwsgi_500(wsgi_req); } if (response_buf) free(response_buf); return UWSGI_OK; } #endif if (uwsgi_parse_array(wsgi_req->buffer, wsgi_req->uh->pktsize, argv, argvs, &argc)) { uwsgi_log("Invalid RPC request. skip.\n"); return -1; } // call the function (output will be in wsgi_req->buffer) content_len = uwsgi_rpc(argv[0], argc-1, argv+1, argvs+1, &response_buf); if (!response_buf) return -1; // using modifier2 we may want a raw output if (wsgi_req->uh->modifier2 == 0) { if (content_len > 0xffff) { // signal dictionary wsgi_req->uh->modifier2 = 5; struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); if (uwsgi_buffer_append_keynum(ub, "CONTENT_LENGTH", 14 , content_len)) { uwsgi_buffer_destroy(ub); free(response_buf); return -1; } // fix uwsgi header wsgi_req->uh->pktsize = ub->pos; if (uwsgi_response_write_body_do(wsgi_req, (char *) wsgi_req->uh, 4)) { uwsgi_buffer_destroy(ub); free(response_buf); return -1; } if (uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos)) { uwsgi_buffer_destroy(ub); free(response_buf); return -1; } uwsgi_buffer_destroy(ub); } else { wsgi_req->uh->pktsize = content_len; if (uwsgi_response_write_body_do(wsgi_req, (char *) wsgi_req->uh, 4)) { free(response_buf); return -1; } } } sendbody: // write the response uwsgi_response_write_body_do(wsgi_req, response_buf, content_len); free(response_buf); return UWSGI_OK; } #ifdef UWSGI_ROUTING static int uwsgi_routing_func_rpc(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { int ret = -1; // this is the list of args char *argv[UMAX8]; // this is the size of each argument uint16_t argvs[UMAX8]; // this is a placeholder for tmp uwsgi_buffers struct uwsgi_buffer *ubs[UMAX8]; char **r_argv = (char **) ur->data2; uint16_t *r_argvs = (uint16_t *) ur->data3; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); uint64_t i, last_translated = 0; for(i=0;icustom;i++) { ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]); if (!ubs[i]) goto end; argv[i] = ubs[i]->buf; argvs[i] = ubs[i]->pos; last_translated = i; } // ok we now need to check it it is a local call or a remote one char *func = uwsgi_str(ur->data); char *remote = NULL; char *at = strchr(func, '@'); if (at) { *at = 0; remote = at+1; } uint64_t size; char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size); free(func); if (!response) goto end; ret = UWSGI_ROUTE_BREAK; if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) {free(response) ; goto end;} if (uwsgi_response_add_content_length(wsgi_req, size)) {free(response) ; goto end;} uwsgi_response_write_body_do(wsgi_req, response, size); free(response); end: for(i=0;idata2; uint16_t *r_argvs = (uint16_t *) ur->data3; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); uint64_t i, last_translated = 0; for(i=0;icustom;i++) { ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]); if (!ubs[i]) goto end; argv[i] = ubs[i]->buf; argvs[i] = ubs[i]->pos; last_translated = i; } // ok we now need to check it it is a local call or a remote one char *func = uwsgi_str(ur->data); char *remote = NULL; char *at = strchr(func, '@'); if (at) { *at = 0; remote = at+1; } uint64_t size; char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size); free(func); if (!response) goto end; ret = UWSGI_ROUTE_NEXT; // optimization if (!wsgi_req->headers_sent) { if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) {free(response) ; goto end;} if (uwsgi_response_add_connection_close(wsgi_req)) {free(response) ; goto end;} } uwsgi_response_write_body_do(wsgi_req, response, size); free(response); end: for(i=0;idata2; uint16_t *r_argvs = (uint16_t *) ur->data3; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); uint64_t i, last_translated = 0; for(i=0;icustom;i++) { ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]); if (!ubs[i]) goto end; argv[i] = ubs[i]->buf; argvs[i] = ubs[i]->pos; last_translated = i; } // ok we now need to check it it is a local call or a remote one char *func = uwsgi_str(ur->data); char *remote = NULL; char *at = strchr(func, '@'); if (at) { *at = 0; remote = at+1; } uint64_t size; response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size); free(func); if (!response) goto end; ret = UWSGI_ROUTE_NEXT; if (size == 0) goto end; ret = uwsgi_blob_to_response(wsgi_req, response, size); if (ret == 0) { ret = UWSGI_ROUTE_BREAK; } end: free(response); for(i=0;idata2; uint16_t *r_argvs = (uint16_t *) ur->data3; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); uint64_t i, last_translated = 0; for(i=0;icustom;i++) { ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]); if (!ubs[i]) goto end; argv[i] = ubs[i]->buf; argvs[i] = ubs[i]->pos; last_translated = i; } // ok we now need to check it it is a local call or a remote one char *func = uwsgi_str(ur->data); char *remote = NULL; char *at = strchr(func, '@'); if (at) { *at = 0; remote = at+1; } uint64_t size; response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size); free(func); ret = UWSGI_ROUTE_BREAK; if (!uwsgi_req_append(wsgi_req, ur->data4, ur->data4_len, response, size)) { goto end; } ret = UWSGI_ROUTE_NEXT; end: if (response) free(response); for(i=0;idata2; uint16_t *r_argvs = (uint16_t *) ur->data3; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); uint64_t i, last_translated = 0; for(i=0;icustom;i++) { ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]); if (!ubs[i]) goto end; argv[i] = ubs[i]->buf; argvs[i] = ubs[i]->pos; last_translated = i; } // ok we now need to check it it is a local call or a remote one char *func = uwsgi_str(ur->data); char *remote = NULL; char *at = strchr(func, '@'); if (at) { *at = 0; remote = at+1; } uint64_t size; char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size); free(func); if (!response) goto end; ret = UWSGI_ROUTE_CONTINUE; if (!uwsgi_strncmp(response, size, "next", 4 )) { ret = UWSGI_ROUTE_NEXT; } else if (!uwsgi_strncmp(response, size, "continue", 8 )) { ret = UWSGI_ROUTE_CONTINUE; } else if (!uwsgi_starts_with(response, size, "break", 5 )) { ret = UWSGI_ROUTE_BREAK; if (size > 6) { if (uwsgi_response_prepare_headers(wsgi_req, response+6, size-6)) goto end0; if (uwsgi_response_add_connection_close(wsgi_req)) goto end0; if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) goto end0; // no need to check for return value uwsgi_response_write_headers_do(wsgi_req); } } else if (!uwsgi_starts_with(response, size, "goto ", 5)) { ret = UWSGI_ROUTE_BREAK; if (size > 5) { // find the label struct uwsgi_route *routes = uwsgi.routes; while(routes) { if (!routes->label) goto next; if (!uwsgi_strncmp(routes->label, routes->label_len, response+5, size-5)) { ret = UWSGI_ROUTE_NEXT; wsgi_req->route_goto = routes->pos; goto found; } next: routes = routes->next; } goto end0; found: if (wsgi_req->route_goto <= wsgi_req->route_pc) { wsgi_req->route_goto = 0; uwsgi_log("[uwsgi-route] ERROR \"goto\" instruction can only jump forward (check your label !!!)\n"); ret = UWSGI_ROUTE_BREAK; } } } end0: free(response); end: for(i=0;idata = the func name ur->custom = the number of arguments ur->data2 = the pointer to the args ur->data3 = the pointer to the args sizes ur->data4 = func specific */ static int uwsgi_router_rpc_base(struct uwsgi_route *ur, char *args) { ur->custom = 0; ur->data2 = uwsgi_calloc(sizeof(char *) * UMAX8); ur->data3 = uwsgi_calloc(sizeof(uint16_t) * UMAX8); char *p, *ctx = NULL; uwsgi_foreach_token(args, " ", p, ctx) { if (!ur->data) { ur->data = p; } else { if (ur->custom >= UMAX8) { uwsgi_log("unable to register route: maximum number of rpc args reached\n"); free(ur->data2); free(ur->data3); return -1; } char **argv = (char **) ur->data2; uint16_t *argvs = (uint16_t *) ur->data3; argv[ur->custom] = p; argvs[ur->custom] = strlen(p); ur->custom++; } } if (!ur->data) { uwsgi_log("unable to register route: you need to specify an rpc function\n"); free(ur->data2); free(ur->data3); return -1; } return 0; } static int uwsgi_router_rpc(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_rpc; return uwsgi_router_rpc_base(ur, args); } static int uwsgi_router_rpc_ret(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_rpc_ret; return uwsgi_router_rpc_base(ur, args); } static int uwsgi_router_rpc_blob(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_rpc_blob; return uwsgi_router_rpc_base(ur, args); } static int uwsgi_router_rpc_raw(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_rpc_raw; return uwsgi_router_rpc_base(ur, args); } static int uwsgi_router_rpc_var(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_rpc_var; char *space = strchr(args, ' '); if (!space) return -1; ur->data4 = args; ur->data4_len = space - args; return uwsgi_router_rpc_base(ur, space+1); } static void router_rpc_register() { uwsgi_register_router("call", uwsgi_router_rpc); uwsgi_register_router("rpc", uwsgi_router_rpc); uwsgi_register_router("rpcret", uwsgi_router_rpc_ret); uwsgi_register_router("rpcblob", uwsgi_router_rpc_blob); uwsgi_register_router("rpcnext", uwsgi_router_rpc_blob); uwsgi_register_router("rpcraw", uwsgi_router_rpc_raw); uwsgi_register_router("rpcvar", uwsgi_router_rpc_var); } #endif struct uwsgi_plugin rpc_plugin = { .name = "rpc", .modifier1 = 173, .request = uwsgi_rpc_request, #ifdef UWSGI_ROUTING .on_load = router_rpc_register, #endif }; uwsgi-2.0.29/plugins/rpc/uwsgiplugin.py000066400000000000000000000001111477626554400201530ustar00rootroot00000000000000NAME='rpc' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['rpc_plugin'] uwsgi-2.0.29/plugins/rrdtool/000077500000000000000000000000001477626554400161345ustar00rootroot00000000000000uwsgi-2.0.29/plugins/rrdtool/rrdtool.c000066400000000000000000000113331477626554400177660ustar00rootroot00000000000000#include extern struct uwsgi_server uwsgi; static struct uwsgi_rrdtool { void *lib; char *lib_name; int (*create)(int, char **); int (*update)(int, char **); int freq; char *update_area; struct uwsgi_string_list *directory; struct uwsgi_stats_pusher *pusher; } u_rrd; static struct uwsgi_option rrdtool_options[] = { {"rrdtool", required_argument, 0, "store rrd files in the specified directory", uwsgi_opt_add_string_list, &u_rrd.directory, UWSGI_OPT_MASTER|UWSGI_OPT_METRICS}, {"rrdtool-freq", required_argument, 0, "set collect frequency", uwsgi_opt_set_int, &u_rrd.freq, 0}, {"rrdtool-lib", required_argument, 0, "set the name of rrd library (default: librrd.so)", uwsgi_opt_set_str, &u_rrd.lib_name, 0}, {0, 0, 0, 0, 0, 0, 0}, }; static int rrdtool_init() { if (!u_rrd.lib_name) { u_rrd.lib_name = "librrd.so"; } u_rrd.lib = dlopen(u_rrd.lib_name, RTLD_LAZY); if (!u_rrd.lib) return -1; u_rrd.create = dlsym(u_rrd.lib, "rrd_create"); if (!u_rrd.create) { dlclose(u_rrd.lib); return -1; } u_rrd.update = dlsym(u_rrd.lib, "rrd_update"); if (!u_rrd.update) { dlclose(u_rrd.lib); return -1; } uwsgi_log_initial("*** RRDtool library available at %p ***\n", u_rrd.lib); return 0; } /* create .rrd files if needed */ static void rrdtool_post_init() { if (!u_rrd.create) return; // do not waste time if no --rrdtool option is defined if (!u_rrd.directory) return; if (!u_rrd.freq) u_rrd.freq = 300; char *argv[7]; argv[0] = "create"; // create RRA argv[3] = "RRA:AVERAGE:0.5:1:288" ; argv[4] = "RRA:AVERAGE:0.5:12:168" ; argv[5] = "RRA:AVERAGE:0.5:288:31" ; argv[6] = "RRA:AVERAGE:0.5:2016:52"; struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, u_rrd.directory) { char *dir = uwsgi_expand_path(usl->value, strlen(usl->value), NULL); if (!dir) { uwsgi_error("rrdtool_post_init()/uwsgi_expand_path()"); exit(1); } struct uwsgi_metric *um = uwsgi.metrics; // here locking is useless, but maybe in the future we could move this part // somewhere else int created = 0; uwsgi_rlock(uwsgi.metrics_lock); while(um) { char *filename = uwsgi_concat4(dir, "/", um->name, ".rrd"); if (!uwsgi_file_exists(filename)) { argv[1] = filename; if (um->type == UWSGI_METRIC_GAUGE) { argv[2] = "DS:metric:GAUGE:600:0:U"; } else { argv[2] = "DS:metric:DERIVE:600:0:U"; } if (u_rrd.create(7, argv)) { uwsgi_log("unable to create rrd file for metric \"%s\"\n", um->name); uwsgi_error("rrd_create()"); exit(1); } created++; } free(filename); um = um->next; } uwsgi_rwunlock(uwsgi.metrics_lock); uwsgi_log("created %d new rrd files in %s\n", created, dir); struct uwsgi_stats_pusher_instance *uspi = uwsgi_stats_pusher_add(u_rrd.pusher, NULL); uspi->freq = u_rrd.freq; uspi->data = dir; // no need to generate the json uspi->raw=1; } } static void rrdtool_push(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) { if (!u_rrd.update) return ; // standard stats pusher if (!uspi->data) { if (!uspi->arg) { uwsgi_log("invalid rrdtool stats pusher syntax\n"); exit(1); } uspi->data = uwsgi_expand_path(uspi->arg, strlen(uspi->arg), NULL); if (!uspi->data) { uwsgi_error("rrdtool_push()/uwsgi_expand_path()"); exit(1); } if (!u_rrd.freq) u_rrd.freq = 300; uspi->freq = u_rrd.freq; } // 1k will be more than enough char buf[1024]; char *argv[3]; argv[0] = "update"; struct uwsgi_metric *um = uwsgi.metrics; while(um) { uwsgi_rlock(uwsgi.metrics_lock); int ret = snprintf(buf, 1024, "N:%lld", (long long) (*um->value)); uwsgi_rwunlock(uwsgi.metrics_lock); if (um->reset_after_push){ uwsgi_wlock(uwsgi.metrics_lock); *um->value = um->initial_value; uwsgi_rwunlock(uwsgi.metrics_lock); } if (ret < 3 || ret >= 1024) { uwsgi_log("unable to update rrdtool metric for %s\n", um->name); goto next; } char *filename = uwsgi_concat4(uspi->data, "/", um->name, ".rrd"); argv[1] = filename; argv[2] = buf; if (u_rrd.update(3, argv)) { uwsgi_log_verbose("ERROR: rrd_update(\"%s\", \"%s\")\n", argv[1], argv[2]); } free(filename); next: um = um->next; } } static void rrdtool_register() { u_rrd.pusher = uwsgi_register_stats_pusher("rrdtool", rrdtool_push); u_rrd.pusher->raw = 1; } struct uwsgi_plugin rrdtool_plugin = { .name = "rrdtool", .options = rrdtool_options, .on_load = rrdtool_register, // this is the best phase to create rrd files (if needed) .preinit_apps = rrdtool_post_init, // here we get pointers to rrdtool functions .init = rrdtool_init, }; uwsgi-2.0.29/plugins/rrdtool/uwsgiplugin.py000066400000000000000000000001131477626554400210560ustar00rootroot00000000000000 NAME='rrdtool' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['rrdtool'] uwsgi-2.0.29/plugins/rsyslog/000077500000000000000000000000001477626554400161515ustar00rootroot00000000000000uwsgi-2.0.29/plugins/rsyslog/rsyslog_plugin.c000066400000000000000000000061201477626554400213740ustar00rootroot00000000000000#include "../../uwsgi.h" extern struct uwsgi_server uwsgi; struct uwsgi_rsyslog { int packet_size; int msg_size; int split_msg; } u_rsyslog; struct uwsgi_option rsyslog_options[] = { {"rsyslog-packet-size", required_argument, 0, "set maximum packet size for syslog messages (default 1024) WARNING! using packets > 1024 breaks RFC 3164 (#4.1)", uwsgi_opt_set_int, &u_rsyslog.packet_size, 0}, {"rsyslog-split-messages", no_argument, 0, "split big messages into multiple chunks if they are bigger than allowed packet size (default is false)", uwsgi_opt_true, &u_rsyslog.split_msg, 0}, {0, 0, 0, 0, 0, 0, 0}, }; ssize_t uwsgi_rsyslog_logger(struct uwsgi_logger *ul, char *message, size_t len) { char ctime_storage[26]; time_t current_time; int portn = 514; int rlen; if (!ul->configured) { if (!ul->arg) { uwsgi_log_safe("invalid rsyslog syntax\n"); exit(1); } if (ul->arg[0] == '/') { ul->fd = socket(AF_UNIX, SOCK_DGRAM, 0); } else { ul->fd = socket(AF_INET, SOCK_DGRAM, 0); } if (ul->fd < 0) { uwsgi_error_safe("socket()"); exit(1); } uwsgi_socket_nb(ul->fd); ul->count = 29; char *comma = strchr(ul->arg, ','); if (comma) { ul->data = comma+1; *comma = 0; char *prisev = strchr(ul->data, ','); if (prisev) { *prisev = 0; ul->count = atoi(prisev+1); } } else { ul->data = uwsgi_concat2(uwsgi.hostname," uwsgi"); } char *port = strchr(ul->arg, ':'); if (port) { portn = atoi(port+1); *port = 0; } if (ul->arg[0] == '/') { ul->addr_len = socket_to_un_addr(ul->arg, &ul->addr.sa_un); } else { ul->addr_len = socket_to_in_addr(ul->arg, NULL, portn, &ul->addr.sa_in); } if (port) *port = ':'; if (comma) *comma = ','; if (!u_rsyslog.packet_size) u_rsyslog.packet_size = 1024; if (!u_rsyslog.msg_size) u_rsyslog.msg_size = u_rsyslog.packet_size - 30; ul->buf = uwsgi_malloc(uwsgi.log_master_bufsize); ul->configured = 1; } current_time = uwsgi_now(); // drop newline if (message[len-1] == '\n') len--; #if defined(__sun__) && !defined(__clang__) ctime_r(¤t_time, ctime_storage, 26); #else ctime_r(¤t_time, ctime_storage); #endif int pos, msg_len, ret; for (pos=0 ; pos < (int) len ;) { if (pos > 0 && !u_rsyslog.split_msg) return pos; msg_len = ( ((int)len)-pos > u_rsyslog.msg_size ? u_rsyslog.msg_size : ((int)len)-pos); rlen = snprintf(ul->buf, u_rsyslog.packet_size, "<%d>%.*s %s: %.*s", ul->count, 15, ctime_storage+4, (char *) ul->data, msg_len, &message[pos]); if (rlen > 0 && rlen < u_rsyslog.packet_size) { ret = sendto(ul->fd, ul->buf, rlen, 0, (const struct sockaddr *) &ul->addr, ul->addr_len); if (ret <= 0) return ret; pos += msg_len; } else { return -1; } } return pos; } void uwsgi_rsyslog_register() { uwsgi_register_logger("rsyslog", uwsgi_rsyslog_logger); } struct uwsgi_plugin rsyslog_plugin = { .name = "rsyslog", .on_load = uwsgi_rsyslog_register, .options = rsyslog_options, }; uwsgi-2.0.29/plugins/rsyslog/uwsgiplugin.py000066400000000000000000000001211477626554400210720ustar00rootroot00000000000000NAME='rsyslog' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['rsyslog_plugin'] uwsgi-2.0.29/plugins/ruby19/000077500000000000000000000000001477626554400156025ustar00rootroot00000000000000uwsgi-2.0.29/plugins/ruby19/uwsgiplugin.py000066400000000000000000000036301477626554400205330ustar00rootroot00000000000000import os,sys NAME='ruby19' try: RUBYPATH = os.environ['UWSGICONFIG_RUBYPATH'] except: RUBYPATH = 'ruby' rbconfig = 'Config' version = os.popen(RUBYPATH + " -e \"print RUBY_VERSION\"").read().rstrip() v = version.split('.') GCC_LIST = ['../rack/rack_plugin', '../rack/rack_api'] if (v[0] == '1' and v[1] == '9') or v[0] >= '2': CFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print RbConfig::CONFIG['CFLAGS']\"").read().rstrip().split() CFLAGS.append('-DRUBY19') if version >= '2.7': CFLAGS.append('-DRUBY27') CFLAGS.append('-Wno-unused-parameter') rbconfig = 'RbConfig' else: CFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['CFLAGS']\"" % rbconfig).read().rstrip().split() includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['rubyhdrdir']\"" % rbconfig).read().rstrip() if includedir == 'nil': includedir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['archdir']\"" % rbconfig).read().rstrip() CFLAGS.append('-I' + includedir) else: CFLAGS.append('-I' + includedir) archdir = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['archdir']\"" % rbconfig).read().rstrip() arch = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['arch']\"" % rbconfig).read().rstrip() CFLAGS.append('-I' + archdir) CFLAGS.append('-I' + archdir + '/' + arch) CFLAGS.append('-I' + includedir + '/' + arch) CFLAGS.append('-Drack_plugin=ruby19_plugin') LDFLAGS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['LDFLAGS']\"" % rbconfig).read().rstrip().split() libpath = os.popen(RUBYPATH + " -e \"require 'rbconfig';print %s::CONFIG['libdir']\"" % rbconfig).read().rstrip() LDFLAGS.append('-L' + libpath ) os.environ['LD_RUN_PATH'] = libpath LIBS = os.popen(RUBYPATH + " -e \"require 'rbconfig';print '-l' + %s::CONFIG['RUBY_SO_NAME']\"" % rbconfig).read().rstrip().split() uwsgi-2.0.29/plugins/servlet/000077500000000000000000000000001477626554400161335ustar00rootroot00000000000000uwsgi-2.0.29/plugins/servlet/servlet_plugin.c000066400000000000000000000050211477626554400213370ustar00rootroot00000000000000#include /* Servlet 2.5 JVM handler */ #define UWSGI_JVM_REQUEST_HANDLER_SERVLET 2 extern struct uwsgi_jvm ujvm; struct uwsgi_servlet { } uservlet; static struct uwsgi_option uwsgi_servlet_options[] = { {0, 0, 0, 0}, }; // the request handler static int uwsgi_servlet_request(struct wsgi_request *wsgi_req) { return UWSGI_OK; } static int uwsgi_servlet_setup() { uwsgi_log("loading servlet environment...\n"); jclass servlet = uwsgi_jvm_class("org/apache/jasper/servlet/JspServlet"); uwsgi_log("jclass = %p\n", servlet); jmethodID mid = uwsgi_jvm_get_method_id(servlet, "", "()V"); if (uwsgi_jvm_exception() || !mid) exit(1); jobject instance = (*ujvm_env)->NewObject(ujvm_env, servlet, mid); if (uwsgi_jvm_exception() || !instance) exit(1); uwsgi_log("done\n"); jclass uwsgi_servlet_config = uwsgi_jvm_class("uWSGIServletConfig"); mid = uwsgi_jvm_get_method_id(uwsgi_servlet_config, "", "()V"); jobject config = (*ujvm_env)->NewObject(ujvm_env, uwsgi_servlet_config, mid); mid = uwsgi_jvm_get_method_id(servlet, "init", "(Ljavax/servlet/ServletConfig;)V"); uwsgi_jvm_call_object(instance, mid, config ); uwsgi_log("SERVLET initialized\n"); jclass uwsgi_request = uwsgi_jvm_class("uWSGIServletRequest"); jclass uwsgi_response = uwsgi_jvm_class("uWSGIServletResponse"); uwsgi_log("%p %p\n", uwsgi_request, uwsgi_response); mid = uwsgi_jvm_get_method_id(uwsgi_request , "", "()V"); if (uwsgi_jvm_exception() || !mid) exit(1); jobject request = (*ujvm_env)->NewObject(ujvm_env, uwsgi_request, mid); mid = uwsgi_jvm_get_method_id(uwsgi_response , "", "()V"); if (uwsgi_jvm_exception() || !mid) exit(1); jobject response = (*ujvm_env)->NewObject(ujvm_env, uwsgi_response, mid); uwsgi_log("%p %p\n", request, response); mid = uwsgi_jvm_get_method_id(servlet, "service", "(Ljavax/servlet/ServletRequest;Ljavax/servlet/ServletResponse;)V"); if (uwsgi_jvm_exception() || !mid) exit(1); uwsgi_jvm_call_object(instance, mid, request, response); uwsgi_log("done\n"); mid = uwsgi_jvm_get_method_id(uwsgi_response, "flushBuffer", "()V"); if (uwsgi_jvm_exception() || !mid) exit(1); uwsgi_jvm_call_object(response, mid); uwsgi_log("servlet loaded\n"); return 0; } static int uwsgi_servlet_init() { if (uwsgi_jvm_register_request_handler(UWSGI_JVM_REQUEST_HANDLER_SERVLET, uwsgi_servlet_setup, uwsgi_servlet_request)) { exit(1); } return 0; } struct uwsgi_plugin servlet_plugin = { .name = "servlet", .options = uwsgi_servlet_options, .init = uwsgi_servlet_init, }; uwsgi-2.0.29/plugins/servlet/uwsgi_servlet.java000066400000000000000000000277661477626554400217220ustar00rootroot00000000000000import javax.servlet.*; import javax.servlet.http.*; import java.util.*; import java.io.*; import java.net.*; /* uWSGI Servlet 2.5 Container implementation */ class uWSGIServletContext implements ServletContext { public Object getAttribute(String name) { System.out.println("uWSGIServletContext getAttribute " + name); return null; } public ServletContext getContext(String uripath) { return this; } public String getContextPath() { System.out.println("uWSGIServletContext getContextPath"); return "/root/uwsgi"; } public int getMajorVersion() { return 2; } public int getMinorVersion() { return 5; } public String getMimeType(java.lang.String file) { System.out.println("uWSGIServletContext getMimeType " + file); return "text/plain"; } public java.util.Set getResourcePaths(java.lang.String path) { System.out.println("uWSGIServletContext getResourcePaths " + path); return null; } public java.net.URL getResource(java.lang.String path) { System.out.println("uWSGIServletContext getResource " + path); try { File myFile; if (path.equals("/WEB-INF/web.xml")) { myFile = new File("/root/uwsgi/WEB-INF/web.xml"); } else { myFile = new File("/root/uwsgi/foo.jsp"); } return myFile.toURI().toURL(); } catch(MalformedURLException e) { System.out.println("uWSGIServletContext ERROR !!!"); return null; } } public RequestDispatcher getNamedDispatcher(java.lang.String name) { System.out.println("uWSGIServletContext getNamedDispatcher " + name); return null; } public java.io.InputStream getResourceAsStream(java.lang.String path) { System.out.println("uWSGIServletContext getResourceAsStream " + path); try { FileInputStream fis = new FileInputStream(path); return fis; } catch(FileNotFoundException e) { return null; } } public RequestDispatcher getRequestDispatcher(java.lang.String path) { System.out.println("uWSGIServletContext getRequestDispatcher " + path); return null; } public Servlet getServlet(java.lang.String name) { System.out.println("uWSGIServletContext getServlet"); return null; } public java.util.Enumeration getServletNames() { return null; } public java.util.Enumeration getServlets() { return null; } public void log(java.lang.String message, java.lang.Throwable throwable) { System.out.println("LOG " + message); } public void log(java.lang.Exception exception, java.lang.String msg) { System.out.println("LOG " + msg); } public void log(java.lang.String msg) { System.out.println("LOG " + msg); } public String getRealPath(java.lang.String path) { System.out.println("uWSGIServletContext getRealPath " + path); return path; } public String getServerInfo() { return "uWSGI"; } public String getInitParameter(java.lang.String name) { return null; } public Enumeration getInitParameterNames() { System.out.println("uWSGIServletContext getInitParameterNames()"); return null; } public java.util.Enumeration getAttributeNames() { System.out.println("uWSGIServletContext getAttributeNames"); return null; } public String getServletContextName() { System.out.println("uWSGIServletContext getServletContextName"); return "/jsp"; } public void removeAttribute(java.lang.String name) { } public void setAttribute(java.lang.String name, java.lang.Object object) { System.out.println("uWSGIServletContext setAttribute " + name); } } class uWSGIServletConfig implements ServletConfig { uWSGIServletContext context; public uWSGIServletConfig() { super(); System.out.println("uWSGIServletConfig allocation"); this.context = new uWSGIServletContext(); } public String getInitParameter(String name) { System.out.println("ServletConfig getInitParameter " + name); return null; } public Enumeration getInitParameterNames() { System.out.println("ServletConfig getInitParameterNames"); Vector pNames = new Vector(); return pNames.elements(); } public ServletContext getServletContext() { System.out.println("ServletConfig getServletContext"); return this.context; } public String getServletName() { return "/jsp"; } } class uWSGIServletOutputStream extends ServletOutputStream { // append a byte to the writing buffer public void write(int n) { System.out.print((char)n); } // send them to the client public void flush() { System.out.println("FLUSHING"); } } class uWSGIServletSession implements HttpSession { HashMap hm; public uWSGIServletSession() { this.hm = new HashMap(); } public String getId() { return "uwsgi"; } public int getMaxInactiveInterval() { return 3600; } public long getLastAccessedTime() { return 1373874485; } public long getCreationTime() { return 1373874485; } public void setMaxInactiveInterval(int interval) { System.out.println("SESSION INTERVAL " + interval ); } public HttpSessionContext getSessionContext() { return null; } public ServletContext getServletContext() { return null; } public String[] getValueNames() { return (String[]) this.hm.keySet().toArray(); } public void invalidate() { } public void removeAttribute(String name) { this.hm.remove(name); } public void removeValue(String name) { this.hm.remove(name); } public void putValue(String name, Object value) { this.hm.put(name, value); } public void setAttribute(String name, Object value) { this.hm.put(name, value); } public Enumeration getAttributeNames() { return Collections.enumeration(this.hm.keySet()); } public boolean isNew() { return false; } public Object getAttribute(String name) { return this.hm.get(name); } public Object getValue(String name) { return this.hm.get(name); } } class uWSGIServletRequest implements HttpServletRequest { uWSGIServletSession session = null; public Object getAttribute(String name) { System.out.println("getAttribute " + name); return null; } public Enumeration getAttributeNames() { return null; } public String getCharacterEncoding() { return "utf-8"; } public void setCharacterEncoding(String env) { } public String getParameter(String name) { System.out.println("getParameter " + name); return null; } public Enumeration getParameterNames() { return null; } public String[] getParameterValues(String name) { return null; } public int getContentLength() { return 0; } public String getContentType() { return "text/plain"; } public ServletInputStream getInputStream() { return null; } public Map getParameterMap() { return null; } public String getProtocol() { return "HTTP/1.0"; } public String getScheme() { System.out.println("getScheme"); return "http"; } public String getServerName() { return "quantal64.local"; } public int getServerPort() { return 80; } public BufferedReader getReader() { return null; } public String getRemoteAddr() { return "127.0.0.1"; } public String getRemoteHost() { return "localhost"; } public void setAttribute(String name, Object o) { } public void removeAttribute(String name) { } public Locale getLocale() { return null; } public Enumeration getLocales() { return null; } public boolean isSecure() { return false; } public RequestDispatcher getRequestDispatcher(String path) { System.out.println("RequestDispatcher getRequestDispatcher " + path); return null; } public String getRealPath(String path) { System.out.println("getRealPath " + path); return "/tmp"; } public int getRemotePort() { return 1717; } public String getLocalName() { return "localhost"; } public String getLocalAddr() { return "127.0.0.1"; } public int getLocalPort() { return 80; } public String getAuthType() { return null; } public Cookie[] getCookies() { return null; } public long getDateHeader(String name) { return -1; } public String getHeader(String name) { System.out.println("getHeader " + name); return null; } public Enumeration getHeaders(String name) { System.out.println("getHeaders " + name); return null; } public Enumeration getHeaderNames() { return null; } public int getIntHeader(String name) { return -1; } public String getMethod() { System.out.println("getMethod"); return "GET"; } public String getPathInfo() { System.out.println("getPathInfo"); return ""; } public String getPathTranslated() { System.out.println("getPathTranslated"); return null; } public String getContextPath() { System.out.println("getContextPath"); return ""; } public String getQueryString() { return "r=17"; } public String getRemoteUser() { return "kratos"; } public boolean isUserInRole(String role) { return false; } public java.security.Principal getUserPrincipal() { return null; } public String getRequestedSessionId() { System.out.println("getRequestedSessionId !!!"); return null; } public String getRequestURI() { System.out.println("getRequestURI"); return "/foo.jsp"; } public StringBuffer getRequestURL() { System.out.println("getRequestURL"); //return "http://quantal64.local/roberta?r=17"; return null; } public String getServletPath() { System.out.println("getServletPath"); return "/root/uwsgi/foo.jsp"; } public HttpSession getSession(boolean create) { System.out.println(" getSession !!!"); return null; } public HttpSession getSession() { System.out.println("!!! getSession !!!"); if (this.session == null) { this.session = new uWSGIServletSession(); } return this.session; } public boolean isRequestedSessionIdFromURL() { return false; } public boolean isRequestedSessionIdFromUrl() { return false; } public boolean isRequestedSessionIdFromCookie() { return false; } public boolean isRequestedSessionIdValid() { return false; } } class uWSGIServletResponse implements HttpServletResponse { PrintWriter pw; public uWSGIServletResponse() { this.pw = new PrintWriter(new uWSGIServletOutputStream()); } public void addCookie(Cookie cookie) { } public boolean containsHeader(String name) { return false; } public String encodeURL(String url) { System.out.println("URL = " + url); return url; } public String encodeRedirectURL(String url) { return url; } public String encodeUrl(String url) { return url; } public String encodeRedirectUrl(String url) { return url; } public void sendError(int sc, String msg) { } public void sendError(int sc) { } public void sendRedirect(String location) { } public void setDateHeader(String name, long date) { } public void addDateHeader(String name, long date) { } public void setHeader(String name, String value) { System.out.println("SET_HEADER " + name + " = " + value); } public void addHeader(String name, String value) { System.out.println("ADD_HEADER " + name + " = " + value); } public void setIntHeader(String name, int value) { } public void addIntHeader(String name, int value) { } public void setStatus(int sc) { System.out.println("STATUS " + sc); } public void setStatus(int sc, String sm) { System.out.println("STATUS " + sc + " " + sm); } public void flushBuffer() { System.out.println("flushBuffer"); this.pw.flush(); } public void resetBuffer() { System.out.println("resetBuffer"); } public boolean isCommitted() { return true; } public void reset() { } public void setLocale(Locale loc) { } public Locale getLocale() { return null; } public int getBufferSize() { return 4096; } public void setBufferSize(int size) { } public void setContentType(String type) { System.out.println("setContentType " + type); } public void setContentLength(int len) { } public void setCharacterEncoding(String charset) { } public PrintWriter getWriter() { System.out.println("getWriter()"); return this.pw; } public ServletOutputStream getOutputStream() { System.out.println("getOutputStream()"); return null; } public String getContentType() { return "text/plain"; } public String getCharacterEncoding() { return "utf-8"; } } uwsgi-2.0.29/plugins/servlet/uwsgiplugin.py000066400000000000000000000005071477626554400210640ustar00rootroot00000000000000import os import shutil jvm_path = 'plugins/jvm' up = {} try: execfile('%s/uwsgiplugin.py' % jvm_path, up) except: f = open('%s/uwsgiplugin.py' % jvm_path) exec(f.read(), up) f.close() NAME='servlet' CFLAGS = up['CFLAGS'] CFLAGS.append('-I%s' % jvm_path) LDFLAGS = [] LIBS = [] GCC_LIST = ['servlet_plugin'] uwsgi-2.0.29/plugins/signal/000077500000000000000000000000001477626554400157245ustar00rootroot00000000000000uwsgi-2.0.29/plugins/signal/signal_plugin.c000066400000000000000000000011771477626554400207310ustar00rootroot00000000000000#include extern struct uwsgi_server uwsgi; /* request 110 */ int uwsgi_request_signal(struct wsgi_request *wsgi_req) { uint8_t ret_status = 1; struct uwsgi_header uh; if (uwsgi_signal_send(uwsgi.signal_socket, wsgi_req->uh->modifier2) < 0) { ret_status = 0; } uh.modifier1 = 255; uh.pktsize = 0; uh.modifier2 = ret_status; if (uwsgi_response_write_body_do(wsgi_req, (char *) &uh, 4)) { return -1; } return UWSGI_OK; } struct uwsgi_plugin signal_plugin = { .name = "signal", .modifier1 = 110, .request = uwsgi_request_signal, }; uwsgi-2.0.29/plugins/signal/uwsgiplugin.py000066400000000000000000000001201477626554400206440ustar00rootroot00000000000000 NAME='signal' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['signal_plugin'] uwsgi-2.0.29/plugins/spooler/000077500000000000000000000000001477626554400161325ustar00rootroot00000000000000uwsgi-2.0.29/plugins/spooler/spooler_plugin.c000066400000000000000000000031261477626554400213410ustar00rootroot00000000000000#include /* this plugin, allows remote spooling of jobs */ extern struct uwsgi_server uwsgi; int uwsgi_request_spooler(struct wsgi_request *wsgi_req) { struct uwsgi_header uh; // TODO get the spooler from the modifier2 if (uwsgi.spoolers == NULL) { uwsgi_log("the spooler is inactive !!!...skip\n"); uh.modifier1 = 255; uh.pktsize = 0; uh.modifier2 = 0; uwsgi_response_write_body_do(wsgi_req, (char *) &uh, 4); return -1; } char *filename = uwsgi_spool_request(NULL, wsgi_req->buffer, wsgi_req->uh->pktsize, NULL, 0); uh.modifier1 = 255; uh.pktsize = 0; if (filename) { uh.modifier2 = 1; if (uwsgi_response_write_body_do(wsgi_req, (char *) &uh, 4)) { uwsgi_log("disconnected client, remove spool file.\n"); /* client disconnect, remove spool file */ if (unlink(filename)) { uwsgi_error("uwsgi_request_spooler()/unlink()"); uwsgi_log("something horrible happened !!! check your spooler ASAP !!!\n"); exit(1); } } free(filename); return 0; } else { /* announce a failed spool request */ uh.modifier2 = 0; uwsgi_response_write_body_do(wsgi_req, (char *) &uh, 4); } return -1; } struct uwsgi_plugin spooler_plugin = { .name = "spooler", .modifier1 = 17, .request = uwsgi_request_spooler, }; uwsgi-2.0.29/plugins/spooler/uwsgiplugin.py000066400000000000000000000001211477626554400210530ustar00rootroot00000000000000NAME='spooler' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['spooler_plugin'] uwsgi-2.0.29/plugins/sqlite3/000077500000000000000000000000001477626554400160335ustar00rootroot00000000000000uwsgi-2.0.29/plugins/sqlite3/plugin.c000066400000000000000000000042551477626554400175030ustar00rootroot00000000000000#include #include extern struct uwsgi_server uwsgi; static void uwsgi_sqlite3_config(char *, char *[]); static void uwsgi_opt_load_sqlite3(char *opt, char *filename, void *none) { config_magic_table_fill(filename, uwsgi.magic_table); uwsgi_sqlite3_config(filename, uwsgi.magic_table); } static struct uwsgi_option uwsgi_sqlite3_options[] = { {"sqlite3", required_argument, 0, "load config from sqlite3 db", uwsgi_opt_load_sqlite3, NULL, UWSGI_OPT_IMMEDIATE}, {"sqlite", required_argument, 0, "load config from sqlite3 db", uwsgi_opt_load_sqlite3, NULL, UWSGI_OPT_IMMEDIATE}, {0, 0, 0, 0, 0, 0, 0}, }; static int uwsgi_sqlite3_config_callback(void *magic_table, int field_count, char **fields, char **col) { // make a copy of the string if (field_count >= 2) { size_t value_len = strlen(fields[1]) + 1; char *value = magic_sub(fields[1], value_len, &value_len, (char **) magic_table); add_exported_option(uwsgi_strncopy(fields[0], strlen(fields[0])), value, 0); } return 0; } static void uwsgi_sqlite3_config(char *file, char *magic_table[]) { sqlite3 *db; char *err = NULL; char *query = "SELECT * FROM uwsgi"; char *colon = uwsgi_get_last_char(file, ':'); if (colon) { colon[0] = 0; if (colon[1] != 0) { query = colon + 1; } } uwsgi_log("[uWSGI] getting sqlite3 configuration from %s\n", file); #ifdef sqlite3_open_v2 if (sqlite3_open_v2(file, &db, SQLITE_OPEN_READONLY, NULL)) { #else if (sqlite3_open(file, &db)) { #endif uwsgi_log("unable to open sqlite3 db: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); exit(1); } if (sqlite3_exec(db, query, uwsgi_sqlite3_config_callback, (void *) magic_table, &err)) { uwsgi_log("sqlite3 error: %s\n", err); sqlite3_close(db); exit(1); } sqlite3_close(db); } struct uwsgi_plugin sqlite3_plugin = { .name = "sqlite3", .options = uwsgi_sqlite3_options, }; uwsgi-2.0.29/plugins/sqlite3/uwsgiplugin.py000066400000000000000000000001251477626554400207600ustar00rootroot00000000000000 NAME='sqlite3' CFLAGS = [] LDFLAGS = [] LIBS = ['-lsqlite3'] GCC_LIST = ['plugin'] uwsgi-2.0.29/plugins/ssi/000077500000000000000000000000001477626554400152455ustar00rootroot00000000000000uwsgi-2.0.29/plugins/ssi/ssi.c000066400000000000000000000311141477626554400162070ustar00rootroot00000000000000#include extern struct uwsgi_server uwsgi; #define UWSGI_SSI_MAX_ARGS 8 /* uWSGI server side includes implementation */ struct uwsgi_ssi_arg { char *key; size_t key_len; char *value; size_t val_len; }; struct uwsgi_ssi_cmd { char *name; size_t name_len; struct uwsgi_buffer *(*func)(struct wsgi_request *, struct uwsgi_ssi_arg *, int); struct uwsgi_ssi_cmd *next; }; struct uwsgi_ssi_cmd *uwsgi_ssi_commands = NULL; static struct uwsgi_ssi_cmd* uwsgi_ssi_get_cmd(char *name, size_t name_len) { struct uwsgi_ssi_cmd *usc = uwsgi_ssi_commands; while(usc) { if (!uwsgi_strncmp(usc->name, usc->name_len, name, name_len)) { return usc; } usc = usc->next; } return NULL; } static struct uwsgi_ssi_cmd *uwsgi_register_ssi_command(char *name, struct uwsgi_buffer *(*func)(struct wsgi_request *, struct uwsgi_ssi_arg *, int)) { struct uwsgi_ssi_cmd *old_usc = NULL,*usc = uwsgi_ssi_commands; while(usc) { if (!strcmp(usc->name, name)) { return usc; } old_usc = usc; usc = usc->next; } usc = uwsgi_calloc(sizeof(struct uwsgi_ssi_cmd)); usc->name = name; usc->name_len = strlen(name); usc->func = func; if (old_usc) { old_usc->next = usc; } else { uwsgi_ssi_commands = usc; } return usc; } static int uwsgi_ssi_parse_args(struct wsgi_request *wsgi_req, char *buf, size_t len, struct uwsgi_ssi_arg *argv, int *argc) { // status [0]null/= [1]" [2]" [3]\s size_t i; uint8_t status = 0; char *key = buf; size_t key_len = 0; char *value = NULL; size_t val_len = 0; for(i=0;i= UWSGI_SSI_MAX_ARGS) { return -1; } key = NULL; key_len = 0; value = NULL; val_len = 0; } else { if (!value) { value = buf + i; } val_len++; } break; case 3: if (!isspace((int)buf[i])) { key = buf + i; key_len = 1; status = 0; } break; default: return -1; } } return 0; } static struct uwsgi_buffer *uwsgi_ssi_parse_command(struct wsgi_request *wsgi_req, char *buf, size_t len) { // storage for arguments struct uwsgi_ssi_arg argv[UWSGI_SSI_MAX_ARGS]; int argc = 0; // first remove white spaces from the begin and the end char *cmd = buf; size_t cmd_len = len; size_t i; for(i=0;i0;i--) { if (isspace((int)buf[i])) { cmd_len--; } else { break; } } // now get the command char *ssi_cmd = cmd; size_t ssi_cmd_len = 0; int found = 0; for(i=0;ifunc(wsgi_req, argv, argc); } static struct uwsgi_buffer *uwsgi_ssi_parse(struct wsgi_request *wsgi_req, char *buf, size_t len) { size_t i; uint8_t status = 0; char *cmd = NULL; size_t cmd_len = 0; struct uwsgi_buffer *ub = uwsgi_buffer_new(len); // parsing status 0[null] 1[<] 2[!] 3[-] 4[-] 5[#/-] 6[-] 7[>] // on status 6-7-8 the reset action come back to 5 instead of 0 for(i=0;i') { status = 0; struct uwsgi_buffer *ub_cmd = uwsgi_ssi_parse_command(wsgi_req, cmd, cmd_len); if (ub_cmd) { if (uwsgi_buffer_append(ub, ub_cmd->buf, ub_cmd->pos)) { uwsgi_buffer_destroy(ub_cmd); goto error; } uwsgi_buffer_destroy(ub_cmd); } cmd = NULL; cmd_len = 0; } else { cmd_len+=3; } break; default: goto error; } } return ub; error: uwsgi_buffer_destroy(ub); return NULL; } static int uwsgi_ssi_request(struct wsgi_request *wsgi_req) { struct uwsgi_buffer *ub = NULL; if (uwsgi_parse_vars(wsgi_req)) { return -1; } if (!wsgi_req->document_root_len || !wsgi_req->path_info_len) { uwsgi_log("[uwsgi-ssi] DOCUMENT_ROOT and PATH_INFO must be defined !!!\n"); uwsgi_500(wsgi_req); return UWSGI_OK; } char *filename = uwsgi_concat3n(wsgi_req->document_root, wsgi_req->document_root_len, "/", 1, wsgi_req->path_info, wsgi_req->path_info_len); size_t filename_len = wsgi_req->document_root_len + 1 + wsgi_req->path_info_len; // we expand the path for future security implementations char *real_filename = uwsgi_expand_path(filename, filename_len, NULL); free(filename); if (!real_filename) { uwsgi_404(wsgi_req); return UWSGI_OK; } struct uwsgi_buffer *ub_ssi = uwsgi_buffer_from_file(real_filename); free(real_filename); if (!ub_ssi) { uwsgi_500(wsgi_req); return UWSGI_OK; } ub = uwsgi_ssi_parse(wsgi_req, ub_ssi->buf, ub_ssi->pos); uwsgi_buffer_destroy(ub_ssi); if (!ub) { uwsgi_500(wsgi_req); return UWSGI_OK; } // prepare headers if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) { uwsgi_500(wsgi_req); goto end; } // content_length if (uwsgi_response_add_content_length(wsgi_req, ub->pos)) { uwsgi_500(wsgi_req); goto end; } // content_type if (uwsgi_response_add_content_type(wsgi_req, "text/html", 9)) { uwsgi_500(wsgi_req); goto end; } uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); end: if (ub) { uwsgi_buffer_destroy(ub); } return UWSGI_OK; } static char *uwsgi_ssi_get_arg(struct uwsgi_ssi_arg *argv, int argc, char *key, size_t key_len, size_t *val_len) { int i; for(i=0;ikey, arg->key_len, key, key_len)) { *val_len = arg->val_len; return arg->value; } } return NULL; } // echo command static struct uwsgi_buffer *ssi_cmd_echo(struct wsgi_request *wsgi_req, struct uwsgi_ssi_arg *argv, int argc) { size_t var_len = 0; char *var = uwsgi_ssi_get_arg(argv, argc, "var", 3, &var_len); if (!var || var_len == 0) return NULL; uint16_t rlen = 0; char *value = uwsgi_get_var(wsgi_req, var, var_len, &rlen); if (!value) return NULL; if (rlen == 0) return NULL; struct uwsgi_buffer *ub = uwsgi_buffer_new(rlen); if (uwsgi_buffer_append(ub, value, rlen)) { uwsgi_buffer_destroy(ub); return NULL; } return ub; }; // printenv command static struct uwsgi_buffer *ssi_cmd_printenv(struct wsgi_request *wsgi_req, struct uwsgi_ssi_arg *argv, int argc) { struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); int i; for (i = 0; i < wsgi_req->var_cnt; i += 2) { if (uwsgi_buffer_append(ub, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len)) goto error; if (uwsgi_buffer_append(ub, "=", 1)) goto error; if (uwsgi_buffer_append(ub, wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len)) goto error; if (uwsgi_buffer_append(ub, "\n", 1)) goto error; } return ub; error: uwsgi_buffer_destroy(ub); return NULL; }; // include command static struct uwsgi_buffer *ssi_cmd_include(struct wsgi_request *wsgi_req, struct uwsgi_ssi_arg *argv, int argc) { size_t var_len = 0; char *var = uwsgi_ssi_get_arg(argv, argc, "file", 4, &var_len); if (!var || var_len == 0) return NULL; char *filename = uwsgi_concat2n(var, var_len, "", 0); struct uwsgi_buffer *ub = uwsgi_buffer_from_file(filename); free(filename); return ub; } // cache command (uWSGI specific) static struct uwsgi_buffer *ssi_cmd_cache(struct wsgi_request *wsgi_req, struct uwsgi_ssi_arg *argv, int argc) { size_t var_len = 0; char *var = uwsgi_ssi_get_arg(argv, argc, "key", 3, &var_len); if (!var || var_len == 0) return NULL; size_t cache_len = 0; char *cache = uwsgi_ssi_get_arg(argv, argc, "name", 4, &cache_len); char *cache_name = NULL; if (cache && cache_len) { cache_name = uwsgi_concat2n(cache, cache_len, "", 0); } uint64_t rlen = 0; char *value = uwsgi_cache_magic_get(var, var_len, &rlen, NULL, cache_name); if (cache_name) free(cache_name); struct uwsgi_buffer *ub = NULL; if (value) { ub = uwsgi_buffer_new(rlen); if (uwsgi_buffer_append(ub, value, rlen)) { free(value); uwsgi_buffer_destroy(ub); return NULL; } free(value); } return ub; } static int uwsgi_routing_func_ssi(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_buffer *ub = NULL; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub_filename = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub_filename) goto end; struct uwsgi_buffer *ub_ssi = uwsgi_buffer_from_file(ub_filename->buf); uwsgi_buffer_destroy(ub_filename); if (!ub_ssi) goto end; ub = uwsgi_ssi_parse(wsgi_req, ub_ssi->buf, ub_ssi->pos); uwsgi_buffer_destroy(ub_ssi); if (!ub) goto end; if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end; if (uwsgi_response_add_content_length(wsgi_req, ub->pos)) goto end; if (uwsgi_response_add_content_type(wsgi_req, "text/html", 9)) goto end; uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); end: if (ub) uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } static int uwsgi_router_ssi(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_ssi; ur->data = args; ur->data_len = strlen(args); return 0; } static int uwsgi_ssi_init() { uwsgi_register_ssi_command("echo", ssi_cmd_echo); uwsgi_register_ssi_command("printenv", ssi_cmd_printenv); uwsgi_register_ssi_command("include", ssi_cmd_include); uwsgi_register_ssi_command("cache", ssi_cmd_cache); return 0; } static void uwsgi_ssi_register_router() { uwsgi_register_router("ssi", uwsgi_router_ssi); } static void uwsgi_ssi_log(struct wsgi_request *wsgi_req) { log_request(wsgi_req); } struct uwsgi_plugin ssi_plugin = { .name = "ssi", .modifier1 = 19, .init = uwsgi_ssi_init, .request = uwsgi_ssi_request, .after_request = uwsgi_ssi_log, .on_load = uwsgi_ssi_register_router, }; uwsgi-2.0.29/plugins/ssi/uwsgiplugin.py000066400000000000000000000001021477626554400201650ustar00rootroot00000000000000NAME='ssi' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['ssi'] uwsgi-2.0.29/plugins/sslrouter/000077500000000000000000000000001477626554400165115ustar00rootroot00000000000000uwsgi-2.0.29/plugins/sslrouter/sslrouter.c000066400000000000000000000341121477626554400207200ustar00rootroot00000000000000#include #ifdef UWSGI_SSL /* uWSGI sslrouter */ #include "../corerouter/cr.h" extern struct uwsgi_server uwsgi; static struct uwsgi_sslrouter { struct uwsgi_corerouter cr; char *ssl_session_context; #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME int sni; #endif } usr; struct sslrouter_session { struct corerouter_session session; SSL *ssl; }; static void uwsgi_opt_sslrouter(char *opt, char *value, void *cr) { struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) cr; char *client_ca = NULL; // build socket, certificate and key file char *sock = uwsgi_str(value); char *crt = strchr(sock, ','); if (!crt) { uwsgi_log("invalid sslrouter syntax must be socket,crt,key\n"); exit(1); } *crt = '\0'; crt++; char *key = strchr(crt, ','); if (!key) { uwsgi_log("invalid sslrouter syntax must be socket,crt,key\n"); exit(1); } *key = '\0'; key++; char *ciphers = strchr(key, ','); if (ciphers) { *ciphers = '\0'; ciphers++; client_ca = strchr(ciphers, ','); if (client_ca) { *client_ca = '\0'; client_ca++; } } struct uwsgi_gateway_socket *ugs = uwsgi_new_gateway_socket(sock, ucr->name); // ok we have the socket, initialize ssl if required if (!uwsgi.ssl_initialized) { uwsgi_ssl_init(); } // initialize ssl context char *name = usr.ssl_session_context; if (!name) { name = uwsgi_concat3(ucr->short_name, "-", ugs->name); } ugs->ctx = uwsgi_ssl_new_server_context(name, crt, key, ciphers, client_ca); if (!ugs->ctx) { exit(1); } ucr->has_sockets++; } static void uwsgi_opt_sslrouter2(char *opt, char *value, void *cr) { struct uwsgi_corerouter *ucr = (struct uwsgi_corerouter *) cr; char *s2_addr = NULL; char *s2_cert = NULL; char *s2_key = NULL; char *s2_ciphers = NULL; char *s2_clientca = NULL; if (uwsgi_kvlist_parse(value, strlen(value), ',', '=', "addr", &s2_addr, "cert", &s2_cert, "crt", &s2_cert, "key", &s2_key, "ciphers", &s2_ciphers, "clientca", &s2_clientca, "client_ca", &s2_clientca, NULL)) { uwsgi_log("error parsing --sslrouter option\n"); exit(1); } if (!s2_addr || !s2_cert || !s2_key) { uwsgi_log("--sslrouter option needs addr, cert and key items\n"); exit(1); } struct uwsgi_gateway_socket *ugs = uwsgi_new_gateway_socket(s2_addr, ucr->name); // ok we have the socket, initialize ssl if required if (!uwsgi.ssl_initialized) { uwsgi_ssl_init(); } // initialize ssl context char *name = usr.ssl_session_context; if (!name) { name = uwsgi_concat3(ucr->short_name, "-", ugs->name); } ugs->ctx = uwsgi_ssl_new_server_context(name, s2_cert, s2_key, s2_ciphers, s2_clientca); if (!ugs->ctx) { exit(1); } ucr->has_sockets++; } static struct uwsgi_option sslrouter_options[] = { {"sslrouter", required_argument, 0, "run the sslrouter on the specified port", uwsgi_opt_sslrouter, &usr, 0}, {"sslrouter2", required_argument, 0, "run the sslrouter on the specified port (key-value based)", uwsgi_opt_sslrouter2, &usr, 0}, {"sslrouter-session-context", required_argument, 0, "set the session id context to the specified value", uwsgi_opt_set_str, &usr.ssl_session_context, 0}, {"sslrouter-processes", required_argument, 0, "prefork the specified number of sslrouter processes", uwsgi_opt_set_int, &usr.cr.processes, 0}, {"sslrouter-workers", required_argument, 0, "prefork the specified number of sslrouter processes", uwsgi_opt_set_int, &usr.cr.processes, 0}, {"sslrouter-zerg", required_argument, 0, "attach the sslrouter to a zerg server", uwsgi_opt_corerouter_zerg, &usr, 0}, {"sslrouter-use-cache", optional_argument, 0, "use uWSGI cache as hostname->server mapper for the sslrouter", uwsgi_opt_set_str, &usr.cr.use_cache, 0}, {"sslrouter-use-pattern", required_argument, 0, "use a pattern for sslrouter hostname->server mapping", uwsgi_opt_corerouter_use_pattern, &usr, 0}, {"sslrouter-use-base", required_argument, 0, "use a base dir for sslrouter hostname->server mapping", uwsgi_opt_corerouter_use_base, &usr, 0}, {"sslrouter-fallback", required_argument, 0, "fallback to the specified node in case of error", uwsgi_opt_add_string_list, &usr.cr.fallback, 0}, {"sslrouter-use-code-string", required_argument, 0, "use code string as hostname->server mapper for the sslrouter", uwsgi_opt_corerouter_cs, &usr, 0}, {"sslrouter-use-socket", optional_argument, 0, "forward request to the specified uwsgi socket", uwsgi_opt_corerouter_use_socket, &usr, 0}, {"sslrouter-to", required_argument, 0, "forward requests to the specified uwsgi server (you can specify it multiple times for load balancing)", uwsgi_opt_add_string_list, &usr.cr.static_nodes, 0}, {"sslrouter-gracetime", required_argument, 0, "retry connections to dead static nodes after the specified amount of seconds", uwsgi_opt_set_int, &usr.cr.static_node_gracetime, 0}, {"sslrouter-events", required_argument, 0, "set the maximum number of concurrent events", uwsgi_opt_set_int, &usr.cr.nevents, 0}, {"sslrouter-max-retries", required_argument, 0, "set the maximum number of retries/fallbacks to other nodes", uwsgi_opt_set_int, &usr.cr.max_retries, 0}, {"sslrouter-quiet", required_argument, 0, "do not report failed connections to instances", uwsgi_opt_true, &usr.cr.quiet, 0}, {"sslrouter-cheap", no_argument, 0, "run the sslrouter in cheap mode", uwsgi_opt_true, &usr.cr.cheap, 0}, {"sslrouter-subscription-server", required_argument, 0, "run the sslrouter subscription server on the spcified address", uwsgi_opt_corerouter_ss, &usr, 0}, {"sslrouter-timeout", required_argument, 0, "set sslrouter timeout", uwsgi_opt_set_int, &usr.cr.socket_timeout, 0}, {"sslrouter-stats", required_argument, 0, "run the sslrouter stats server", uwsgi_opt_set_str, &usr.cr.stats_server, 0}, {"sslrouter-stats-server", required_argument, 0, "run the sslrouter stats server", uwsgi_opt_set_str, &usr.cr.stats_server, 0}, {"sslrouter-ss", required_argument, 0, "run the sslrouter stats server", uwsgi_opt_set_str, &usr.cr.stats_server, 0}, {"sslrouter-harakiri", required_argument, 0, "enable sslrouter harakiri", uwsgi_opt_set_int, &usr.cr.harakiri, 0}, #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME {"sslrouter-sni", no_argument, 0, "use SNI to route requests", uwsgi_opt_true, &usr.sni, 0}, #endif {"sslrouter-buffer-size", required_argument, 0, "set internal buffer size (default: page size)", uwsgi_opt_set_64bit, &usr.cr.buffer_size, 0}, {0, 0, 0, 0, 0, 0, 0}, }; static ssize_t sr_write(struct corerouter_peer *); // write to backend static ssize_t sr_instance_write(struct corerouter_peer *peer) { ssize_t len = cr_write(peer, "sr_instance_write()"); // end on empty write if (!len) return 0; // the chunk has been sent, start (again) reading from client and instances if (cr_write_complete(peer)) { // reset the buffer peer->out->pos = 0; cr_reset_hooks(peer); } return len; } // read from backend static ssize_t sr_instance_read(struct corerouter_peer *peer) { ssize_t len = cr_read(peer, "sr_instance_read()"); if (!len) return 0; // set the input buffer as the main output one peer->session->main_peer->out = peer->in; peer->session->main_peer->out_pos = 0; cr_write_to_main(peer, sr_write); return len; } // the instance is connected now we cannot retry connections static ssize_t sr_instance_connected(struct corerouter_peer *peer) { cr_peer_connected(peer, "sr_instance_connected()"); peer->can_retry = 0; // set the output buffer as the main_peer output one peer->out = peer->session->main_peer->in; peer->out_pos = 0; return sr_instance_write(peer); } // retry the connection static int sr_retry(struct corerouter_peer *peer) { struct corerouter_session *cs = peer->session; struct uwsgi_corerouter *ucr = cs->corerouter; if (peer->instance_address_len > 0) goto retry; if (ucr->mapper(ucr, peer)) { return -1; } if (peer->instance_address_len == 0) { return -1; } retry: // start async connect (again) cr_connect(peer, sr_instance_connected); return 0; } static ssize_t sr_write(struct corerouter_peer *main_peer) { struct corerouter_session *cs = main_peer->session; struct sslrouter_session *sr = (struct sslrouter_session *) cs; int ret = SSL_write(sr->ssl, main_peer->out->buf + main_peer->out_pos, main_peer->out->pos - main_peer->out_pos); if (ret > 0) { main_peer->out_pos += ret; if (main_peer->out->pos == main_peer->out_pos) { main_peer->out->pos = 0; cr_reset_hooks(main_peer); } return ret; } if (ret == 0) return 0; int err = SSL_get_error(sr->ssl, ret); if (err == SSL_ERROR_WANT_READ) { cr_reset_hooks_and_read(main_peer, sr_write); return 1; } else if (err == SSL_ERROR_WANT_WRITE) { cr_write_to_main(main_peer, sr_write); return 1; } else if (err == SSL_ERROR_SYSCALL) { if (errno != 0) uwsgi_cr_error(main_peer, "sr_write()"); } else if (err == SSL_ERROR_SSL && uwsgi.ssl_verbose) { ERR_print_errors_fp(stderr); } return -1; } static ssize_t sr_read(struct corerouter_peer *main_peer) { struct corerouter_session *cs = main_peer->session; struct sslrouter_session *sr = (struct sslrouter_session *) cs; int ret = SSL_read(sr->ssl, main_peer->in->buf + main_peer->in->pos, main_peer->in->len - main_peer->in->pos); if (ret > 0) { // fix the buffer main_peer->in->pos += ret; // check for pending data int ret2 = SSL_pending(sr->ssl); if (ret2 > 0) { if (uwsgi_buffer_fix(main_peer->in, main_peer->in->len + ret2 )) { uwsgi_cr_log(main_peer, "cannot fix the buffer to %d\n", main_peer->in->len + ret2); return -1; } if (SSL_read(sr->ssl, main_peer->in->buf + main_peer->in->pos, ret2) != ret2) { uwsgi_cr_log(main_peer, "SSL_read() on %d bytes of pending data failed\n", ret2); return -1; } // fix the buffer main_peer->in->pos += ret2; } if (!main_peer->session->peers) { // add a new peer struct corerouter_peer *peer = uwsgi_cr_peer_add(cs); // set default peer hook peer->last_hook_read = sr_instance_read; // use the address as hostname memcpy(peer->key, cs->ugs->name, cs->ugs->name_len); peer->key_len = cs->ugs->name_len; #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME if (usr.sni) { const char *servername = SSL_get_servername(sr->ssl, TLSEXT_NAMETYPE_host_name); if (servername && strlen(servername) <= 0xff) { peer->key_len = strlen(servername); memcpy(peer->key, servername, peer->key_len); } } #endif // the mapper hook if (cs->corerouter->mapper(cs->corerouter, peer)) { return -1; } if (peer->instance_address_len == 0) { return -1; } peer->can_retry = 1; cr_connect(peer, sr_instance_connected); return 1; } main_peer->session->peers->out = main_peer->in; main_peer->session->peers->out_pos = 0; cr_write_to_backend(main_peer, sr_instance_write); return ret; } if (ret == 0) return 0; int err = SSL_get_error(sr->ssl, ret); if (err == SSL_ERROR_WANT_READ) { cr_reset_hooks_and_read(main_peer, sr_read); return 1; } else if (err == SSL_ERROR_WANT_WRITE) { cr_write_to_main(main_peer, sr_read); return 1; } else if (err == SSL_ERROR_SYSCALL) { if (errno != 0) uwsgi_cr_error(main_peer, "sr_ssl_read()"); } else if (err == SSL_ERROR_SSL && uwsgi.ssl_verbose) { ERR_print_errors_fp(stderr); } return -1; } static void sr_session_close(struct corerouter_session *cs) { struct sslrouter_session *sr = (struct sslrouter_session *) cs; // clear the errors (otherwise they could be propagated) ERR_clear_error(); SSL_free(sr->ssl); } // allocate a new session static int sslrouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket *ugs, struct corerouter_session *cs, struct sockaddr *sa, socklen_t s_len) { // set close hook cs->close = sr_session_close; // set retry hook cs->retry = sr_retry; struct sslrouter_session *sr = (struct sslrouter_session *) cs; sr->ssl = SSL_new(ugs->ctx); SSL_set_fd(sr->ssl, cs->main_peer->fd); SSL_set_accept_state(sr->ssl); if (uwsgi_cr_set_hooks(cs->main_peer, sr_read, NULL)) return -1; return 0; } static int sslrouter_init() { usr.cr.session_size = sizeof(struct sslrouter_session); usr.cr.alloc_session = sslrouter_alloc_session; uwsgi_corerouter_init((struct uwsgi_corerouter *) &usr); return 0; } static void sslrouter_setup() { usr.cr.name = uwsgi_str("uWSGI sslrouter"); usr.cr.short_name = uwsgi_str("sslrouter"); } struct uwsgi_plugin sslrouter_plugin = { .name = "sslrouter", .options = sslrouter_options, .init = sslrouter_init, .on_load = sslrouter_setup }; #else struct uwsgi_plugin sslrouter_plugin = { .name = "sslrouter", }; #endif uwsgi-2.0.29/plugins/sslrouter/uwsgiplugin.py000066400000000000000000000001521477626554400214360ustar00rootroot00000000000000 NAME='sslrouter' CFLAGS = [] LDFLAGS = [] LIBS = [] REQUIRES = ['corerouter'] GCC_LIST = ['sslrouter'] uwsgi-2.0.29/plugins/stackless/000077500000000000000000000000001477626554400164435ustar00rootroot00000000000000uwsgi-2.0.29/plugins/stackless/stackless.c000066400000000000000000000055451477626554400206140ustar00rootroot00000000000000#include "../python/uwsgi_python.h" #include extern struct uwsgi_server uwsgi; extern struct uwsgi_python up; struct ustackless { int enabled; PyObject *callable; PyTaskletObject **sl; } usl; static void gil_stackless_get() { pthread_setspecific(up.upt_gil_key, (void *) PyGILState_Ensure()); } static void gil_stackless_release() { PyGILState_Release((PyGILState_STATE) pthread_getspecific(up.upt_gil_key)); } static struct uwsgi_option stackless_options[] = { {"stackless", no_argument, 0, "use stackless as suspend engine", uwsgi_opt_true, &usl.enabled, 0}, { 0, 0, 0, 0, 0, 0, 0 } }; static PyObject *py_uwsgi_stackless_request(PyObject * self, PyObject *args) { async_schedule_to_req_green(); Py_DECREF(usl.sl[uwsgi.wsgi_req->async_id]); Py_INCREF(Py_None); return Py_None; } PyMethodDef uwsgi_stackless_request_method[] = {{"uwsgi_stackless_request", py_uwsgi_stackless_request, METH_VARARGS, ""}}; static void stackless_schedule_to_req() { int id = uwsgi.wsgi_req->async_id; uint8_t modifier1 = uwsgi.wsgi_req->uh->modifier1; // ensure gil UWSGI_GET_GIL if (!uwsgi.wsgi_req->suspended) { usl.sl[id] = PyTasklet_New(NULL, usl.callable); PyObject *args = PyTuple_New(0); PyTasklet_Setup(usl.sl[id], args, NULL); Py_DECREF(args); uwsgi.wsgi_req->suspended = 1; } // call it in the main core if (uwsgi.p[modifier1]->suspend) { uwsgi.p[modifier1]->suspend(NULL); } PyTasklet_Run(usl.sl[id]); // call it in the main core if (uwsgi.p[modifier1]->resume) { uwsgi.p[modifier1]->resume(NULL); } } static void stackless_schedule_to_main(struct wsgi_request *wsgi_req) { // ensure gil UWSGI_GET_GIL if (uwsgi.p[wsgi_req->uh->modifier1]->suspend) { uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req); } PyStackless_Schedule(Py_None, 1); if (uwsgi.p[wsgi_req->uh->modifier1]->resume) { uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req); } uwsgi.wsgi_req = wsgi_req; } static void stackless_init_apps(void) { if (!usl.enabled) return; if (uwsgi.async <= 1) { uwsgi_log("the stackless suspend engine requires async mode\n"); exit(1); } if (uwsgi.has_threads) { up.gil_get = gil_stackless_get; up.gil_release = gil_stackless_release; } // blindly call it as the stackless gil engine is already set UWSGI_GET_GIL usl.sl = uwsgi_malloc( sizeof(PyTaskletObject *) * uwsgi.async ); usl.callable = PyCFunction_New(uwsgi_stackless_request_method, NULL); Py_INCREF(usl.callable); uwsgi_log("enabled stackless engine\n"); uwsgi.schedule_to_main = stackless_schedule_to_main; uwsgi.schedule_to_req = stackless_schedule_to_req; } struct uwsgi_plugin stackless_plugin = { .name = "stackless", .init_apps = stackless_init_apps, .options = stackless_options, }; uwsgi-2.0.29/plugins/stackless/uwsgiplugin.py000066400000000000000000000006251477626554400213750ustar00rootroot00000000000000try: from distutils import sysconfig paths = [ sysconfig.get_python_inc(), sysconfig.get_python_inc(plat_specific=True), ] except ImportError: import sysconfig paths = [ sysconfig.get_path('include'), sysconfig.get_path('platinclude'), ] NAME = 'stackless' CFLAGS = ['-I' + path for path in paths] LDFLAGS = [] LIBS = [] GCC_LIST = ['stackless'] uwsgi-2.0.29/plugins/stats_pusher_file/000077500000000000000000000000001477626554400201725ustar00rootroot00000000000000uwsgi-2.0.29/plugins/stats_pusher_file/plugin.c000066400000000000000000000037041477626554400216400ustar00rootroot00000000000000#include struct uwsgi_stats_pusher_file_conf { char *path; char *freq; char *separator; }; static void stats_pusher_file(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) { struct uwsgi_stats_pusher_file_conf *uspic = (struct uwsgi_stats_pusher_file_conf *) uspi->data; if (!uspi->configured) { uspic = uwsgi_calloc(sizeof(struct uwsgi_stats_pusher_file_conf)); if (uspi->arg) { if (uwsgi_kvlist_parse(uspi->arg, strlen(uspi->arg), ',', '=', "path", &uspic->path, "separator", &uspic->separator, "freq", &uspic->freq, NULL)) { free(uspi); return; } } if (!uspic->path) uspic->path = "uwsgi.stats"; if (!uspic->separator) uspic->separator = "\n\n"; if (uspic->freq) uspi->freq = atoi(uspic->freq); uspi->configured = 1; uspi->data = uspic; } int fd = open(uspic->path, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP); if (fd < 0) { uwsgi_error_open(uspic->path); return; } ssize_t rlen = write(fd, json, json_len); if (rlen != (ssize_t) json_len) { uwsgi_error("uwsgi_stats_pusher_file() -> write()\n"); } rlen = write(fd, uspic->separator, strlen(uspic->separator)); if (rlen != (ssize_t) strlen(uspic->separator)) { uwsgi_error("uwsgi_stats_pusher_file() -> write()\n"); } close(fd); } static void stats_pusher_file_init(void) { uwsgi_register_stats_pusher("file", stats_pusher_file); } struct uwsgi_plugin stats_pusher_file_plugin = { .name = "stats_pusher_file", .on_load = stats_pusher_file_init, }; uwsgi-2.0.29/plugins/stats_pusher_file/uwsgiplugin.py000066400000000000000000000001241477626554400231160ustar00rootroot00000000000000NAME='stats_pusher_file' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['plugin'] uwsgi-2.0.29/plugins/stats_pusher_mongodb/000077500000000000000000000000001477626554400207005ustar00rootroot00000000000000uwsgi-2.0.29/plugins/stats_pusher_mongodb/plugin.c000066400000000000000000000005641477626554400223470ustar00rootroot00000000000000#include void stats_pusher_mongodb(struct uwsgi_stats_pusher_instance *, time_t, char *, size_t); static void stats_pusher_mongodb_init(void) { uwsgi_register_stats_pusher("mongodb", stats_pusher_mongodb); } struct uwsgi_plugin stats_pusher_mongodb_plugin = { .name = "stats_pusher_mongodb", .on_load = stats_pusher_mongodb_init, }; uwsgi-2.0.29/plugins/stats_pusher_mongodb/stats_pusher_mongodb.cc000066400000000000000000000032611477626554400254420ustar00rootroot00000000000000#include #include "client/dbclient.h" extern struct uwsgi_server uwsgi; // one for each mongodb stats pusher struct stats_pusher_mongodb_conf { char *address; char *collection; char *freq; }; extern "C" void stats_pusher_mongodb(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) { struct stats_pusher_mongodb_conf *spmc = (struct stats_pusher_mongodb_conf *) uspi->data; if (!uspi->configured) { spmc = (struct stats_pusher_mongodb_conf *) uwsgi_calloc(sizeof(struct stats_pusher_mongodb_conf)); if (uspi->arg) { if (uwsgi_kvlist_parse(uspi->arg, strlen(uspi->arg), ',', '=', "addr", &spmc->address, "address", &spmc->address, "collection", &spmc->collection, "freq", &spmc->freq, NULL)) { free(spmc); return; } } if (!spmc->address) spmc->address = (char *) "127.0.0.1:27017"; if (!spmc->collection) spmc->collection = (char *) "uwsgi.statistics"; if (spmc->freq) uspi->freq = atoi(spmc->freq); uspi->data = spmc; uspi->configured = 1; } try { int j_len = (int) json_len; mongo::BSONObj b = mongo::fromjson(json, &j_len); // the connection object (will be automatically destroyed at each cycle) mongo::DBClientConnection c; // set the socket timeout c.setSoTimeout(uwsgi.socket_timeout); // connect c.connect(spmc->address); c.insert(spmc->collection, b); } catch ( mongo::DBException &e ) { uwsgi_log("[stats-pusher-mongodb] ERROR(%s/%s): %s\n", spmc->address, spmc->collection, e.what()); } } uwsgi-2.0.29/plugins/stats_pusher_mongodb/uwsgiplugin.py000066400000000000000000000005671477626554400236370ustar00rootroot00000000000000import os NAME = 'stats_pusher_mongodb' CFLAGS = [ '-I/usr/include/mongo', '-I/usr/local/include/mongo', '-std=c++11', '-Wno-error' ] LDFLAGS = [] LIBS = [] if not 'UWSGI_MONGODB_NOLIB' in os.environ: LIBS.append('-lmongoclient') LIBS.append('-lboost_thread') LIBS.append('-lboost_filesystem') GCC_LIST = ['plugin', 'stats_pusher_mongodb.cc'] uwsgi-2.0.29/plugins/stats_pusher_socket/000077500000000000000000000000001477626554400205435ustar00rootroot00000000000000uwsgi-2.0.29/plugins/stats_pusher_socket/plugin.c000066400000000000000000000060241477626554400222070ustar00rootroot00000000000000#include /* this is a stats pusher plugin for sendign metrics over a udp socket --stats-push socket:address[,prefix] example: --stats-push socket:127.0.0.1:8125,myinstance it exports values exposed by the metric subsystem (it is based on the statsd plugin) */ extern struct uwsgi_server uwsgi; // configuration of a socket node struct socket_node { int fd; union uwsgi_sockaddr addr; socklen_t addr_len; char *prefix; uint16_t prefix_len; }; static int socket_send_metric(struct uwsgi_buffer *ub, struct uwsgi_stats_pusher_instance *uspi, struct uwsgi_metric *um) { struct socket_node *sn = (struct socket_node *) uspi->data; // reset the buffer ub->pos = 0; if (uwsgi_buffer_append(ub, sn->prefix, sn->prefix_len)) return -1; if (uwsgi_buffer_append(ub, ".", 1)) return -1; if (uwsgi_buffer_append(ub, um->name, um->name_len)) return -1; if (uwsgi_buffer_append(ub, " ", 1)) return -1; if (uwsgi_buffer_num64(ub, (int64_t) um->type)) return -1; if (uwsgi_buffer_append(ub, " ", 1)) return -1; if (uwsgi_buffer_num64(ub, *um->value)) return -1; if (sendto(sn->fd, ub->buf, ub->pos, 0, (struct sockaddr *) &sn->addr.sa_in, sn->addr_len) < 0) { uwsgi_error("socket_send_metric()/sendto()"); } return 0; } static void stats_pusher_socket(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) { if (!uspi->configured) { struct socket_node *sn = uwsgi_calloc(sizeof(struct socket_node)); char *comma = strchr(uspi->arg, ','); if (comma) { sn->prefix = comma+1; sn->prefix_len = strlen(sn->prefix); *comma = 0; } else { sn->prefix = "uwsgi"; sn->prefix_len = 5; } char *colon = strchr(uspi->arg, ':'); if (!colon) { uwsgi_log("invalid socket address %s\n", uspi->arg); if (comma) *comma = ','; free(sn); return; } sn->addr_len = socket_to_in_addr(uspi->arg, colon, 0, &sn->addr.sa_in); sn->fd = socket(AF_INET, SOCK_DGRAM, 0); if (sn->fd < 0) { uwsgi_error("stats_pusher_socket()/socket()"); if (comma) *comma = ','; free(sn); return; } uwsgi_socket_nb(sn->fd); if (comma) *comma = ','; uspi->data = sn; uspi->configured = 1; } // we use the same buffer for all of the packets struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); struct uwsgi_metric *um = uwsgi.metrics; while(um) { uwsgi_rlock(uwsgi.metrics_lock); socket_send_metric(ub, uspi, um); uwsgi_rwunlock(uwsgi.metrics_lock); if (um->reset_after_push){ uwsgi_wlock(uwsgi.metrics_lock); *um->value = um->initial_value; uwsgi_rwunlock(uwsgi.metrics_lock); } um = um->next; } uwsgi_buffer_destroy(ub); } static void stats_pusher_socket_init(void) { struct uwsgi_stats_pusher *usp = uwsgi_register_stats_pusher("socket", stats_pusher_socket); // we use a custom format not the JSON one usp->raw = 1; } struct uwsgi_plugin stats_pusher_socket_plugin = { .name = "stats_pusher_socket", .on_load = stats_pusher_socket_init, }; uwsgi-2.0.29/plugins/stats_pusher_socket/uwsgiplugin.py000066400000000000000000000001261477626554400234710ustar00rootroot00000000000000NAME='stats_pusher_socket' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['plugin'] uwsgi-2.0.29/plugins/stats_pusher_statsd/000077500000000000000000000000001477626554400205555ustar00rootroot00000000000000uwsgi-2.0.29/plugins/stats_pusher_statsd/plugin.c000066400000000000000000000061771477626554400222320ustar00rootroot00000000000000#include /* this is a stats pusher plugin for the statsd server: --stats-push statsd:address[,prefix] example: --stats-push statsd:127.0.0.1:8125,myinstance it exports values exposed by the metric subsystem */ extern struct uwsgi_server uwsgi; // configuration of a statsd node struct statsd_node { int fd; union uwsgi_sockaddr addr; socklen_t addr_len; char *prefix; uint16_t prefix_len; }; static int statsd_send_metric(struct uwsgi_buffer *ub, struct uwsgi_stats_pusher_instance *uspi, char *metric, size_t metric_len, int64_t value, char type[2]) { struct statsd_node *sn = (struct statsd_node *) uspi->data; // reset the buffer ub->pos = 0; if (uwsgi_buffer_append(ub, sn->prefix, sn->prefix_len)) return -1; if (uwsgi_buffer_append(ub, ".", 1)) return -1; if (uwsgi_buffer_append(ub, metric, metric_len)) return -1; if (uwsgi_buffer_append(ub, ":", 1)) return -1; if (uwsgi_buffer_num64(ub, value)) return -1; if (uwsgi_buffer_append(ub, type, 2)) return -1; if (sendto(sn->fd, ub->buf, ub->pos, 0, (struct sockaddr *) &sn->addr.sa_in, sn->addr_len) < 0) { uwsgi_error("statsd_send_metric()/sendto()"); } return 0; } static void stats_pusher_statsd(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) { if (!uspi->configured) { struct statsd_node *sn = uwsgi_calloc(sizeof(struct statsd_node)); char *comma = strchr(uspi->arg, ','); if (comma) { sn->prefix = comma+1; sn->prefix_len = strlen(sn->prefix); *comma = 0; } else { sn->prefix = "uwsgi"; sn->prefix_len = 5; } char *colon = strchr(uspi->arg, ':'); if (!colon) { uwsgi_log("invalid statsd address %s\n", uspi->arg); if (comma) *comma = ','; free(sn); return; } sn->addr_len = socket_to_in_addr(uspi->arg, colon, 0, &sn->addr.sa_in); sn->fd = socket(AF_INET, SOCK_DGRAM, 0); if (sn->fd < 0) { uwsgi_error("stats_pusher_statsd()/socket()"); if (comma) *comma = ','; free(sn); return; } uwsgi_socket_nb(sn->fd); if (comma) *comma = ','; uspi->data = sn; uspi->configured = 1; } // we use the same buffer for all of the packets struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); struct uwsgi_metric *um = uwsgi.metrics; while(um) { uwsgi_rlock(uwsgi.metrics_lock); // ignore return value if (um->type == UWSGI_METRIC_GAUGE) { statsd_send_metric(ub, uspi, um->name, um->name_len, *um->value, "|g"); } else { statsd_send_metric(ub, uspi, um->name, um->name_len, *um->value, "|c"); } uwsgi_rwunlock(uwsgi.metrics_lock); if (um->reset_after_push){ uwsgi_wlock(uwsgi.metrics_lock); *um->value = um->initial_value; uwsgi_rwunlock(uwsgi.metrics_lock); } um = um->next; } uwsgi_buffer_destroy(ub); } static void stats_pusher_statsd_init(void) { struct uwsgi_stats_pusher *usp = uwsgi_register_stats_pusher("statsd", stats_pusher_statsd); // we use a custom format not the JSON one usp->raw = 1; } struct uwsgi_plugin stats_pusher_statsd_plugin = { .name = "stats_pusher_statsd", .on_load = stats_pusher_statsd_init, }; uwsgi-2.0.29/plugins/stats_pusher_statsd/uwsgiplugin.py000066400000000000000000000001261477626554400235030ustar00rootroot00000000000000NAME='stats_pusher_statsd' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['plugin'] uwsgi-2.0.29/plugins/symcall/000077500000000000000000000000001477626554400161135ustar00rootroot00000000000000uwsgi-2.0.29/plugins/symcall/symcall_plugin.c000066400000000000000000000145071477626554400213100ustar00rootroot00000000000000#include extern struct uwsgi_server uwsgi; struct uwsgi_symcall { struct uwsgi_string_list *symcall_function_name; int (*symcall_function)(struct wsgi_request *); struct uwsgi_string_list *rpc; struct uwsgi_string_list *post_fork; int use_rtld_next; void *dlsym_handle; } usym; struct uwsgi_plugin symcall_plugin; static struct uwsgi_option uwsgi_symcall_options[] = { {"symcall", required_argument, 0, "load the specified C symbol as the symcall request handler (supports too)", uwsgi_opt_add_string_list, &usym.symcall_function_name, 0}, #ifdef RTLD_NEXT {"symcall-use-next", no_argument, 0, "use RTLD_NEXT when searching for symbols", uwsgi_opt_true, &usym.use_rtld_next, 0}, #endif {"symcall-register-rpc", required_argument, 0, "load the specified C symbol as an RPC function (syntax: name function)", uwsgi_opt_add_string_list, &usym.rpc, 0}, {"symcall-post-fork", required_argument, 0, "call the specified C symbol after each fork()", uwsgi_opt_add_string_list, &usym.post_fork, 0}, {0, 0, 0, 0}, }; static void uwsgi_symcall_init(){ #ifdef RTLD_NEXT if (usym.use_rtld_next) { usym.dlsym_handle = RTLD_NEXT; } #endif struct uwsgi_string_list *usl = NULL; int has_mountpoints = 0; uwsgi_foreach(usl, usym.symcall_function_name) { char *func = usl->value, *mountpoint = ""; char *equal = strchr(usl->value, '='); if (equal) { *equal = 0; func = equal+1; mountpoint = usl->value; has_mountpoints = 1; } usl->custom_ptr = dlsym(usym.dlsym_handle, func); if (!usl->custom_ptr) { uwsgi_log("unable to find symbol \"%s\" in process address space\n", func); exit(1); } int id = uwsgi_apps_cnt; struct uwsgi_app *ua = uwsgi_add_app(id, symcall_plugin.modifier1, mountpoint, strlen(mountpoint), usl->custom_ptr, NULL); uwsgi_log("symcall app %d (mountpoint: \"%.*s\") mapped to function ptr: %p\n", id, ua->mountpoint_len, ua->mountpoint, usl->custom_ptr); if (equal) *equal = '='; } if (!has_mountpoints && usym.symcall_function_name) { usym.symcall_function = usym.symcall_function_name->custom_ptr; } uwsgi_foreach(usl, usym.rpc) { char *space = strchr(usl->value, ' '); if (!space) { uwsgi_log("invalid symcall RPC syntax, must be: rpcname symbol\n"); exit(1); } *space = 0; void *func = dlsym(usym.dlsym_handle, space+1); if (!func) { uwsgi_log("unable to find symbol \"%s\" in process address space\n", space+1); exit(1); } if (uwsgi_register_rpc(usl->value, &symcall_plugin, 0, func)) { uwsgi_log("unable to register rpc function"); exit(1); } *space = ' '; } } static int uwsgi_symcall_request(struct wsgi_request *wsgi_req) { if (usym.symcall_function) { return usym.symcall_function(wsgi_req); } if (uwsgi_parse_vars(wsgi_req)) return -1; wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, symcall_plugin.modifier1); if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) { if (uwsgi_apps[uwsgi.default_app].modifier1 == symcall_plugin.modifier1) { wsgi_req->app_id = uwsgi.default_app; } } if (wsgi_req->app_id == -1) { uwsgi_404(wsgi_req); return UWSGI_OK; } struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id]; if (ua->interpreter) { int (*func)(struct wsgi_request *) = (int (*)(struct wsgi_request *)) ua->interpreter; return func(wsgi_req); } return UWSGI_OK; } static void uwsgi_symcall_after_request(struct wsgi_request *wsgi_req) { log_request(wsgi_req); } static uint64_t uwsgi_symcall_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char **buffer) { uint64_t (*casted_func)(uint8_t, char **, uint16_t *, char **) = (uint64_t (*)(uint8_t, char **, uint16_t *, char **)) func; return casted_func(argc, argv, argvs, buffer); } static void uwsgi_symcall_post_fork() { void (*func)(void); struct uwsgi_string_list *usl = usym.post_fork; while(usl) { func = dlsym(usym.dlsym_handle, usl->value); if (!func) { uwsgi_log("unable to find symbol \"%s\" in process address space\n", usl->value); exit(1); } func(); usl = usl->next; } } static int uwsgi_symcall_mule(char *opt) { if (uwsgi_endswith(opt, "()")) { char *func_name = uwsgi_concat2n(opt, strlen(opt)-2, "", 0); void (*func)() = dlsym(usym.dlsym_handle, func_name); if (!func) { uwsgi_log("unable to find symbol \"%s\" in process address space\n", func_name); exit(1); } free(func_name); func(); return 1; } return 0; } #ifdef UWSGI_ROUTING static int symcall_route(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; int (*func)(struct wsgi_request *) = (int (*)(struct wsgi_request *)) dlsym(usym.dlsym_handle, ub->buf); uwsgi_buffer_destroy(ub); if (func) { wsgi_req->async_status = func(wsgi_req); } else { if (ur->custom) return UWSGI_ROUTE_NEXT; uwsgi_404(wsgi_req); } return UWSGI_ROUTE_BREAK; } static int uwsgi_router_symcall(struct uwsgi_route *ur, char *args) { ur->func = symcall_route; ur->data = args; ur->data_len = strlen(args); return 0; } static int uwsgi_router_symcall_next(struct uwsgi_route *ur, char *args) { ur->custom = 1; return uwsgi_router_symcall(ur, args); } #endif static void uwsgi_symcall_register() { usym.dlsym_handle = RTLD_DEFAULT; #ifdef UWSGI_ROUTING uwsgi_register_router("symcall", uwsgi_router_symcall); uwsgi_register_router("symcall-next", uwsgi_router_symcall_next); #endif } struct uwsgi_plugin symcall_plugin = { .name = "symcall", .modifier1 = 18, .options = uwsgi_symcall_options, .init_apps = uwsgi_symcall_init, .request = uwsgi_symcall_request, .after_request = uwsgi_symcall_after_request, .rpc = uwsgi_symcall_rpc, .post_fork = uwsgi_symcall_post_fork, .mule = uwsgi_symcall_mule, .on_load = uwsgi_symcall_register, }; uwsgi-2.0.29/plugins/symcall/uwsgiplugin.py000066400000000000000000000001211477626554400210340ustar00rootroot00000000000000NAME='symcall' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['symcall_plugin'] uwsgi-2.0.29/plugins/syslog/000077500000000000000000000000001477626554400157675ustar00rootroot00000000000000uwsgi-2.0.29/plugins/syslog/syslog_plugin.c000066400000000000000000000051751477626554400210410ustar00rootroot00000000000000#include "../../uwsgi.h" #include extern struct uwsgi_server uwsgi; struct uwsgi_syslog_facility { const char *name; int facility; }; struct uwsgi_syslog_facility usf[] = { { "auth", LOG_AUTH, }, #ifdef LOG_AUTHPRIV { "authpriv", LOG_AUTHPRIV, }, #endif { "cron", LOG_CRON, }, { "daemon", LOG_DAEMON, }, #ifdef LOG_FTP { "ftp", LOG_FTP, }, #endif #ifdef LOG_INSTALL { "install", LOG_INSTALL }, #endif { "kern", LOG_KERN, }, { "lpr", LOG_LPR, }, { "mail", LOG_MAIL, }, #ifdef INTERNAL_MARK { "mark", INTERNAL_MARK, }, /* INTERNAL */ #endif #ifdef LOG_NETINFO { "netinfo", LOG_NETINFO, }, #endif #ifdef LOG_RAS { "ras", LOG_RAS }, #endif #ifdef LOG_REMOTEAUTH { "remoteauth", LOG_REMOTEAUTH }, #endif { "news", LOG_NEWS, }, { "security", LOG_AUTH }, /* DEPRECATED */ { "syslog", LOG_SYSLOG, }, { "user", LOG_USER, }, { "uucp", LOG_UUCP, }, { "local0", LOG_LOCAL0, }, { "local1", LOG_LOCAL1, }, { "local2", LOG_LOCAL2, }, { "local3", LOG_LOCAL3, }, { "local4", LOG_LOCAL4, }, { "local5", LOG_LOCAL5, }, { "local6", LOG_LOCAL6, }, { "local7", LOG_LOCAL7, }, #ifdef LOG_LAUNCHD { "launchd", LOG_LAUNCHD }, #endif { NULL, -1, } }; ssize_t uwsgi_syslog_logger(struct uwsgi_logger *ul, char *message, size_t len) { char *syslog_opts; int facility = LOG_DAEMON; if (!ul->configured) { setlinebuf(stderr); if (ul->arg == NULL) { syslog_opts = "uwsgi"; } else { char *colon = strchr(ul->arg, ','); if (colon) { struct uwsgi_syslog_facility *fn = usf; while(fn->name) { if (!strcmp(fn->name, colon+1)) { facility = fn->facility; break; } fn++; } syslog_opts = uwsgi_str(ul->arg); syslog_opts[colon-ul->arg] = 0; } else { syslog_opts = ul->arg; } } openlog(syslog_opts, 0, facility); ul->configured = 1; } #ifdef __APPLE__ syslog(LOG_NOTICE, "%.*s", (int) len, message); #else syslog(LOG_INFO, "%.*s", (int) len, message); #endif return 0; } void uwsgi_syslog_register() { uwsgi_register_logger("syslog", uwsgi_syslog_logger); } struct uwsgi_plugin syslog_plugin = { .name = "syslog", .on_load = uwsgi_syslog_register, }; uwsgi-2.0.29/plugins/syslog/uwsgiplugin.py000066400000000000000000000001171477626554400207150ustar00rootroot00000000000000NAME='syslog' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['syslog_plugin'] uwsgi-2.0.29/plugins/systemd_logger/000077500000000000000000000000001477626554400174765ustar00rootroot00000000000000uwsgi-2.0.29/plugins/systemd_logger/systemd_logger.c000066400000000000000000000013671477626554400227000ustar00rootroot00000000000000#include "../../uwsgi.h" #include ssize_t uwsgi_systemd_logger(struct uwsgi_logger *ul, char *message, size_t len) { // split multiline log messages to multiple journal lines size_t i; char *base = message; for(i=0;itimed_out = 1; uwsgi.resume(wsgi_req) io_loop.add_handler(fd, functools.partial(hook, wsgi_req), io_loop.READ) t = io_loop.add_timeout(timeout, functools.partial(hook, wsgi_req)) uwsgi.suspend() io_loop.remove_handler(fd) io_loop.remove_timeout(t) if wsgi_req->timed_out: return 0 */ struct wsgi_request *wsgi_req = current_wsgi_req(); PyObject *cb_fd = PyObject_CallMethod(utornado.functools, "partial", "Ol", utornado.hook_fd, (long) wsgi_req); if (!cb_fd) goto error; PyObject *cb_timeout = PyObject_CallMethod(utornado.functools, "partial", "Ol", utornado.hook_timeout, (long) wsgi_req); if (!cb_timeout) { Py_DECREF(cb_fd); goto error; } if (PyObject_CallMethod(utornado.ioloop, "add_handler", "iOO", fd, cb_fd, utornado.read) == NULL) { Py_DECREF(cb_fd); Py_DECREF(cb_timeout); goto error; } PyObject *ob_timeout = PyObject_CallMethod(utornado.ioloop, "add_timeout", "iO", uwsgi_now() + timeout, cb_timeout); if (!ob_timeout) { Py_DECREF(cb_fd); Py_DECREF(cb_timeout); goto error; } // back to ioloop if (uwsgi.schedule_to_main) uwsgi.schedule_to_main(wsgi_req); // back from ioloop if (PyObject_CallMethod(utornado.ioloop, "remove_handler", "i", fd) == NULL) PyErr_Print(); if (PyObject_CallMethod(utornado.ioloop, "remove_timeout", "O", ob_timeout) == NULL) PyErr_Print(); Py_DECREF(ob_timeout); Py_DECREF(cb_fd); Py_DECREF(cb_timeout); if (wsgi_req->async_timed_out) return 0; return 1; error: PyErr_Print(); return -1; } static int uwsgi_tornado_wait_write_hook(int fd, int timeout) { struct wsgi_request *wsgi_req = current_wsgi_req(); PyObject *cb_fd = PyObject_CallMethod(utornado.functools, "partial", "Ol", utornado.hook_fd, (long) wsgi_req); if (!cb_fd) goto error; PyObject *cb_timeout = PyObject_CallMethod(utornado.functools, "partial", "Ol", utornado.hook_timeout, (long) wsgi_req); if (!cb_timeout) { Py_DECREF(cb_fd); goto error; } if (PyObject_CallMethod(utornado.ioloop, "add_handler", "iOO", fd, cb_fd, utornado.write) == NULL) { Py_DECREF(cb_fd); Py_DECREF(cb_timeout); goto error; } PyObject *ob_timeout = PyObject_CallMethod(utornado.ioloop, "add_timeout", "iO", uwsgi_now() + timeout, cb_timeout); if (!ob_timeout) { Py_DECREF(cb_fd); Py_DECREF(cb_timeout); goto error; } // back to ioloop if (uwsgi.schedule_to_main) { uwsgi.schedule_to_main(wsgi_req); } // back from ioloop if (PyObject_CallMethod(utornado.ioloop, "remove_handler", "i", fd) == NULL) PyErr_Print(); if (PyObject_CallMethod(utornado.ioloop, "remove_timeout", "O", ob_timeout) == NULL) PyErr_Print(); Py_DECREF(ob_timeout); Py_DECREF(cb_fd); Py_DECREF(cb_timeout); if (wsgi_req->async_timed_out) return 0; return 1; error: PyErr_Print(); return -1; } PyObject *py_uwsgi_tornado_request(PyObject *self, PyObject *args) { int fd = -1; PyObject *events = NULL; if (!PyArg_ParseTuple(args, "iO:uwsgi_tornado_request", &fd, &events)) { uwsgi_log_verbose("[BUG] invalid arguments for tornado callback !!!\n"); exit(1); } struct wsgi_request *wsgi_req = find_wsgi_req_proto_by_fd(fd); uwsgi.wsgi_req = wsgi_req; int status = wsgi_req->socket->proto(wsgi_req); if (status > 0) goto again; if (PyObject_CallMethod(utornado.ioloop, "remove_handler", "i", fd) == NULL) { PyErr_Print(); goto end; } if (status == 0) { // we call this two time... overengineering :( uwsgi.async_proto_fd_table[wsgi_req->fd] = NULL; uwsgi.schedule_to_req(); goto again; } end: uwsgi.async_proto_fd_table[wsgi_req->fd] = NULL; uwsgi_close_request(uwsgi.wsgi_req); free_req_queue; again: Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_tornado_accept(PyObject *self, PyObject *args) { int fd = -1; PyObject *events = NULL; if (!PyArg_ParseTuple(args, "iO:uwsgi_tornado_accept", &fd, &events)) { return NULL; } struct wsgi_request *wsgi_req = find_first_available_wsgi_req(); if (wsgi_req == NULL) { uwsgi_async_queue_is_full(uwsgi_now()); goto end; } uwsgi.wsgi_req = wsgi_req; // TODO better to move it to a function api ... struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while(uwsgi_sock) { if (uwsgi_sock->fd == fd) break; uwsgi_sock = uwsgi_sock->next; } if (!uwsgi_sock) { free_req_queue; goto end; } // fill wsgi_request structure wsgi_req_setup(wsgi_req, wsgi_req->async_id, uwsgi_sock ); // mark core as used uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 1; // accept the connection (since uWSGI 1.5 all of the sockets are non-blocking) if (wsgi_req_simple_accept(wsgi_req, uwsgi_sock->fd)) { // in case of errors (or thundering herd, just reset it) uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].in_request = 0; free_req_queue; goto end; } wsgi_req->start_of_request = uwsgi_micros(); wsgi_req->start_of_request_in_sec = wsgi_req->start_of_request/1000000; // enter harakiri mode if (uwsgi.harakiri_options.workers > 0) { set_harakiri(uwsgi.harakiri_options.workers); } uwsgi.async_proto_fd_table[wsgi_req->fd] = wsgi_req; // add callback for protocol if (PyObject_CallMethod(utornado.ioloop, "add_handler", "iOO", wsgi_req->fd, utornado.request, utornado.read) == NULL) { free_req_queue; PyErr_Print(); } end: Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_tornado_hook_fd(PyObject *self, PyObject *args) { long wsgi_req_ptr = 0; int fd = -1; PyObject *events = NULL; if (!PyArg_ParseTuple(args, "liO:uwsgi_tornado_hook_fd", &wsgi_req_ptr, &fd, &events)) { return NULL; } uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr; uwsgi.schedule_to_req(); Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_tornado_hook_timeout(PyObject *self, PyObject *args) { long wsgi_req_ptr = 0; if (!PyArg_ParseTuple(args, "l", &wsgi_req_ptr)) { return NULL; } uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr; uwsgi.wsgi_req->async_timed_out = 1; uwsgi.schedule_to_req(); Py_INCREF(Py_None); return Py_None; } PyObject *py_uwsgi_tornado_hook_fix(PyObject *self, PyObject *args) { long wsgi_req_ptr = 0; if (!PyArg_ParseTuple(args, "l", &wsgi_req_ptr)) { return NULL; } uwsgi.wsgi_req = (struct wsgi_request *) wsgi_req_ptr; uwsgi.schedule_to_req(); Py_INCREF(Py_None); return Py_None; } PyMethodDef uwsgi_tornado_accept_def[] = { {"uwsgi_tornado_accept", py_uwsgi_tornado_accept, METH_VARARGS, ""} }; PyMethodDef uwsgi_tornado_request_def[] = { {"uwsgi_tornado_request", py_uwsgi_tornado_request, METH_VARARGS, ""} }; PyMethodDef uwsgi_tornado_hook_fd_def[] = { {"uwsgi_tornado_hook_fd", py_uwsgi_tornado_hook_fd, METH_VARARGS, ""} }; PyMethodDef uwsgi_tornado_hook_timeout_def[] = { {"uwsgi_tornado_hook_timeout", py_uwsgi_tornado_hook_timeout, METH_VARARGS, ""} }; PyMethodDef uwsgi_tornado_hook_fix_def[] = { {"uwsgi_tornado_hook_fix", py_uwsgi_tornado_hook_fix, METH_VARARGS, ""} }; static void uwsgi_tornado_schedule_fix(struct wsgi_request *wsgi_req) { PyObject *cb_fix = PyObject_CallMethod(utornado.functools, "partial", "Ol", utornado.hook_fix, (long) wsgi_req); if (!cb_fix) goto error; if (PyObject_CallMethod(utornado.ioloop, "add_callback", "O", cb_fix) == NULL) { Py_DECREF(cb_fix); goto error; } Py_DECREF(cb_fix); return; error: PyErr_Print(); } static void tornado_loop() { if (!uwsgi.has_threads && uwsgi.mywid == 1) { uwsgi_log("!!! Running tornado without threads IS NOT recommended, enable them with --enable-threads !!!\n"); } if (uwsgi.socket_timeout < 30) { uwsgi_log("!!! Running tornado with a socket-timeout lower than 30 seconds is not recommended, tune it with --socket-timeout !!!\n"); } if (!uwsgi.async_waiting_fd_table) uwsgi.async_waiting_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd); if (!uwsgi.async_proto_fd_table) uwsgi.async_proto_fd_table = uwsgi_calloc(sizeof(struct wsgi_request *) * uwsgi.max_fd); // get the GIL UWSGI_GET_GIL up.gil_get = gil_tornado_get; up.gil_release = gil_tornado_release; uwsgi.wait_write_hook = uwsgi_tornado_wait_write_hook; uwsgi.wait_read_hook = uwsgi_tornado_wait_read_hook; uwsgi.schedule_fix = uwsgi_tornado_schedule_fix; if (uwsgi.async < 2) { uwsgi_log("the tornado loop engine requires async mode (--async )\n"); exit(1); } if (!uwsgi.schedule_to_main) { uwsgi_log("*** DANGER *** tornado mode without coroutine/greenthread engine loaded !!!\n"); } PyObject *tornado_dict = get_uwsgi_pydict("tornado.ioloop"); if (!tornado_dict) uwsgi_pyexit; PyObject *tornado_IOLoop = PyDict_GetItemString(tornado_dict, "IOLoop"); if (!tornado_IOLoop) uwsgi_pyexit; utornado.ioloop = PyObject_CallMethod(tornado_IOLoop, "instance", NULL); if (!utornado.ioloop) uwsgi_pyexit; // main greenlet waiting for connection (one greenlet per-socket) PyObject *uwsgi_tornado_accept = PyCFunction_New(uwsgi_tornado_accept_def, NULL); Py_INCREF(uwsgi_tornado_accept); utornado.request = PyCFunction_New(uwsgi_tornado_request_def, NULL); if (!utornado.request) uwsgi_pyexit; utornado.hook_fd = PyCFunction_New(uwsgi_tornado_hook_fd_def, NULL); if (!utornado.hook_fd) uwsgi_pyexit; utornado.hook_timeout = PyCFunction_New(uwsgi_tornado_hook_timeout_def, NULL); if (!utornado.hook_timeout) uwsgi_pyexit; utornado.hook_fix = PyCFunction_New(uwsgi_tornado_hook_fix_def, NULL); if (!utornado.hook_fix) uwsgi_pyexit; utornado.read = PyObject_GetAttrString(utornado.ioloop, "READ"); if (!utornado.read) uwsgi_pyexit; utornado.write = PyObject_GetAttrString(utornado.ioloop, "WRITE"); if (!utornado.write) uwsgi_pyexit; utornado.functools = PyImport_ImportModule("functools"); if (!utornado.functools) uwsgi_pyexit; Py_INCREF(utornado.request); Py_INCREF(utornado.hook_fd); Py_INCREF(utornado.hook_timeout); Py_INCREF(utornado.hook_fix); Py_INCREF(utornado.read); Py_INCREF(utornado.write); // call add_handler on each socket struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while(uwsgi_sock) { if (PyObject_CallMethod(utornado.ioloop, "add_handler", "iOO", uwsgi_sock->fd, uwsgi_tornado_accept, utornado.read) == NULL) { uwsgi_pyexit; } uwsgi_sock = uwsgi_sock->next; } if (PyObject_CallMethod(utornado.ioloop, "start", NULL) == NULL) { uwsgi_pyexit; } // never here ? } static void tornado_init() { uwsgi_register_loop( (char *) "tornado", tornado_loop); } struct uwsgi_plugin tornado_plugin = { .name = "tornado", .options = tornado_options, .on_load = tornado_init, }; uwsgi-2.0.29/plugins/tornado/uwsgiplugin.py000066400000000000000000000006211477626554400210430ustar00rootroot00000000000000try: from distutils import sysconfig paths = [ sysconfig.get_python_inc(), sysconfig.get_python_inc(plat_specific=True), ] except ImportError: import sysconfig paths = [ sysconfig.get_path('include'), sysconfig.get_path('platinclude'), ] NAME = 'tornado' CFLAGS = ['-I' + path for path in paths] LDFLAGS = [] LIBS = [] GCC_LIST = ['tornado'] uwsgi-2.0.29/plugins/transformation_chunked/000077500000000000000000000000001477626554400212165ustar00rootroot00000000000000uwsgi-2.0.29/plugins/transformation_chunked/chunked.c000066400000000000000000000027031477626554400230050ustar00rootroot00000000000000#include #if defined(UWSGI_ROUTING) /* transfer-encoding is added to the headers */ static int transform_chunked(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) { struct uwsgi_buffer *ub = ut->chunk; if (ut->is_final) { if (uwsgi_buffer_append(ub, "0\r\n\r\n", 5)) return -1; return 0; } if (ut->round == 1) { // do not check for errors !!! uwsgi_response_add_header(wsgi_req, "Transfer-Encoding", 17, "chunked", 7); } if (ub->pos > 0) { if (uwsgi_buffer_insert_chunked(ub, 0, ub->pos)) return -1; if (uwsgi_buffer_append(ub, "\r\n", 2)) return -1; } return 0; } static int uwsgi_routing_func_chunked(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_transformation *ut = uwsgi_add_transformation(wsgi_req, transform_chunked, NULL); ut->can_stream = 1; // add a "final" transformation to add the trailing chunk ut = uwsgi_add_transformation(wsgi_req, transform_chunked, NULL); ut->is_final = 1; return UWSGI_ROUTE_NEXT; } static int uwsgi_router_chunked(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_chunked; return 0; } static void router_chunked_register(void) { uwsgi_register_router("chunked", uwsgi_router_chunked); } struct uwsgi_plugin transformation_chunked_plugin = { .name = "transformation_chunked", .on_load = router_chunked_register, }; #else struct uwsgi_plugin transformation_chunked_plugin = { .name = "transformation_chunked", }; #endif uwsgi-2.0.29/plugins/transformation_chunked/uwsgiplugin.py000066400000000000000000000001311477626554400241400ustar00rootroot00000000000000NAME='transformation_chunked' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['chunked'] uwsgi-2.0.29/plugins/transformation_gzip/000077500000000000000000000000001477626554400205465ustar00rootroot00000000000000uwsgi-2.0.29/plugins/transformation_gzip/gzip.c000066400000000000000000000043141477626554400216650ustar00rootroot00000000000000#include #if defined(UWSGI_ROUTING) && defined(UWSGI_ZLIB) /* gzip transformations add content-encoding to your headers and changes the final size !!! remember to fix the content_length (or use chunked encoding) !!! */ struct uwsgi_transformation_gzip { z_stream z; uint32_t crc32; size_t len; uint8_t header; }; extern char gzheader[]; static int transform_gzip(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) { struct uwsgi_transformation_gzip *utgz = (struct uwsgi_transformation_gzip *) ut->data; struct uwsgi_buffer *ub = ut->chunk; if (ut->is_final) { if (utgz->len > 0 && uwsgi_gzip_fix(&utgz->z, utgz->crc32, ub, utgz->len)) { free(utgz); return -1; } free(utgz); return 0; } if (ub->pos == 0) { // Don't try to compress empty responses. return 0; } size_t dlen = 0; char *gzipped = uwsgi_gzip_chunk(&utgz->z, &utgz->crc32, ub->buf, ub->pos, &dlen); if (!gzipped) return -1; utgz->len += ub->pos; uwsgi_buffer_map(ub, gzipped, dlen); if (!utgz->header) { // do not check for errors !!! uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4); utgz->header = 1; if (uwsgi_buffer_insert(ub, 0, gzheader, 10)) { return -1; } } return 0; } static int uwsgi_routing_func_gzip(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_transformation_gzip *utgz = uwsgi_calloc(sizeof(struct uwsgi_transformation_gzip)); if (uwsgi_gzip_prepare(&utgz->z, NULL, 0, &utgz->crc32)) { free(utgz); return UWSGI_ROUTE_BREAK; } struct uwsgi_transformation *ut = uwsgi_add_transformation(wsgi_req, transform_gzip, utgz); ut->can_stream = 1; // this is the trasformation clearing the memory ut = uwsgi_add_transformation(wsgi_req, transform_gzip, utgz); ut->is_final = 1; return UWSGI_ROUTE_NEXT; } static int uwsgi_router_gzip(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_gzip; return 0; } static void router_gzip_register(void) { uwsgi_register_router("gzip", uwsgi_router_gzip); } struct uwsgi_plugin transformation_gzip_plugin = { .name = "transformation_gzip", .on_load = router_gzip_register, }; #else struct uwsgi_plugin transformation_gzip_plugin = { .name = "transformation_gzip", }; #endif uwsgi-2.0.29/plugins/transformation_gzip/uwsgiplugin.py000066400000000000000000000001231477626554400234710ustar00rootroot00000000000000NAME='transformation_gzip' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['gzip'] uwsgi-2.0.29/plugins/transformation_offload/000077500000000000000000000000001477626554400212075ustar00rootroot00000000000000uwsgi-2.0.29/plugins/transformation_offload/offload.c000066400000000000000000000076111477626554400227720ustar00rootroot00000000000000#include #if defined(UWSGI_ROUTING) /* offload transformation each chunk is buffered to the transformation custom buffer if the buffer grows higher than the specified limit, the response will be buffered to disk on final the memory (or the tmpfile) will be offloaded even if we are talking about buffering, this is a streaming transformation as we need to hold control on memory usage "offload" MUST BE the last transformation in the chain. Hellish things will happen otherwise... */ static int transform_offload(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) { if (ut->is_final) { struct uwsgi_transformation *orig_ut = (struct uwsgi_transformation *) ut->data; // sendfile offload if (orig_ut->fd > -1) { if (!uwsgi_offload_request_sendfile_do(wsgi_req, orig_ut->fd, 0, orig_ut->len)) { // the fd will be closed by the offload engine orig_ut->fd = -1; wsgi_req->via = UWSGI_VIA_OFFLOAD; wsgi_req->response_size += orig_ut->len; return 0; } // fallback to non-offloaded write if (uwsgi_simple_sendfile(wsgi_req, orig_ut->fd, 0, orig_ut->len)) { return -1; } wsgi_req->response_size += orig_ut->len; return 0; } // memory offload if (orig_ut->ub) { if (!uwsgi_offload_request_memory_do(wsgi_req, orig_ut->ub->buf, orig_ut->ub->pos)) { // memory will be freed by the offload engine orig_ut->ub->buf = NULL; wsgi_req->via = UWSGI_VIA_OFFLOAD; wsgi_req->response_size += orig_ut->ub->pos; return 0; } // fallback to non-offloaded write if (uwsgi_simple_write(wsgi_req, orig_ut->ub->buf, orig_ut->ub->pos)) { return -1; } wsgi_req->response_size += orig_ut->ub->pos; return -1; } return 0; } // check if we need to start buffering to disk if (ut->fd == -1 && ut->len + ut->chunk->pos > ut->custom64) { ut->fd = uwsgi_tmpfd(); if (ut->fd < 0) return -1; // save already buffered data if (ut->ub) { ssize_t wlen = write(ut->fd, ut->ub->buf, ut->ub->pos); if (wlen != (ssize_t) ut->ub->pos) { uwsgi_req_error("transform_offload/write()"); return -1; } } } // if fd > -1, append to file if (ut->fd > -1) { ssize_t wlen = write(ut->fd, ut->chunk->buf, ut->chunk->pos); if (wlen != (ssize_t) ut->chunk->pos) { uwsgi_req_error("transform_offload/write()"); return -1; } ut->len += wlen; goto done; } // buffer to memory if (!ut->ub) { ut->ub = uwsgi_buffer_new(ut->chunk->pos); } // append the chunk to the custom buffer if (uwsgi_buffer_append(ut->ub, ut->chunk->buf, ut->chunk->pos)) return -1; ut->len += ut->chunk->pos; done: // reset the chunk !!! ut->chunk->pos = 0; return 0; } static int uwsgi_routing_func_offload(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { if (!wsgi_req->socket->can_offload) { uwsgi_log("unable to use the offload transformation without offload threads !!!\n"); return UWSGI_ROUTE_BREAK; } struct uwsgi_transformation *ut = uwsgi_add_transformation(wsgi_req, transform_offload, NULL); ut->can_stream = 1; ut->custom64 = ur->custom; // add a "final" transformation to add the trailing chunk ut = uwsgi_add_transformation(wsgi_req, transform_offload, ut); ut->is_final = 1; return UWSGI_ROUTE_NEXT; } static int uwsgi_router_offload(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_offload; if (args[0] == 0) { // 1 MB limit ur->custom = 1024 * 1024; } else { ur->custom = strtoul(args, NULL, 10); } return 0; } static void router_offload_register(void) { uwsgi_register_router("offload", uwsgi_router_offload); } struct uwsgi_plugin transformation_offload_plugin = { .name = "transformation_offload", .on_load = router_offload_register, }; #else struct uwsgi_plugin transformation_offload_plugin = { .name = "transformation_offload", }; #endif uwsgi-2.0.29/plugins/transformation_offload/uwsgiplugin.py000066400000000000000000000001311477626554400241310ustar00rootroot00000000000000NAME='transformation_offload' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['offload'] uwsgi-2.0.29/plugins/transformation_template/000077500000000000000000000000001477626554400214105ustar00rootroot00000000000000uwsgi-2.0.29/plugins/transformation_template/tt.c000066400000000000000000000025611477626554400222070ustar00rootroot00000000000000#include #ifdef UWSGI_ROUTING // apply templating static int transform_template(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) { struct uwsgi_route *ur = (struct uwsgi_route *) ut->data; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ut->chunk->buf, ut->chunk->pos); if (!ub) return -1; uwsgi_buffer_map(ut->chunk, ub->buf, ub->pos); ub->buf = NULL; uwsgi_buffer_destroy(ub); return 0; } static int uwsgi_router_template_func(struct wsgi_request *wsgi_req, struct uwsgi_route *route) { uwsgi_add_transformation(wsgi_req, transform_template, route); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_template(struct uwsgi_route *ur, char *arg) { ur->func = uwsgi_router_template_func; return 0; } static void transformation_template_register(void) { uwsgi_register_router("template", uwsgi_router_template); } struct uwsgi_plugin transformation_template_plugin = { .name = "transformation_template", .on_load = transformation_template_register, }; #else struct uwsgi_plugin transformation_template_plugin = { .name = "transformation_template", }; #endif uwsgi-2.0.29/plugins/transformation_template/uwsgiplugin.py000066400000000000000000000001251477626554400243350ustar00rootroot00000000000000NAME='transformation_template' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['tt'] uwsgi-2.0.29/plugins/transformation_tofile/000077500000000000000000000000001477626554400210575ustar00rootroot00000000000000uwsgi-2.0.29/plugins/transformation_tofile/tofile.c000066400000000000000000000067761477626554400225250ustar00rootroot00000000000000#include #ifdef UWSGI_ROUTING extern struct uwsgi_server uwsgi; struct uwsgi_router_tofile_conf { // the name of the file char *filename; size_t filename_len; // the mode of the file char *mode; size_t mode_len; }; // this is allocated for each transformation struct uwsgi_transformation_tofile_conf { struct uwsgi_buffer *filename; }; static int transform_tofile(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) { struct uwsgi_transformation_tofile_conf *uttc = (struct uwsgi_transformation_tofile_conf *) ut->data; struct uwsgi_buffer *ub = ut->chunk; // store only successfull response if (wsgi_req->write_errors == 0 && wsgi_req->status == 200 && ub->pos > 0) { if (uttc->filename) { int fd = open(uttc->filename->buf, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if (fd < 0) { uwsgi_error_open(uttc->filename->buf); goto end; } // lock the file if (uwsgi_fcntl_lock(fd)) { close(fd); goto end; } // write to it size_t remains = ub->pos; while(remains) { ssize_t rlen = write(fd, ub->buf + (ub->pos - remains), remains); if (rlen <= 0) { uwsgi_req_error("transform_tofile()/write()"); unlink(uttc->filename->buf); break; } remains -= rlen; } // unlock/close close(fd); } } end: // free resources if (uttc->filename) uwsgi_buffer_destroy(uttc->filename); free(uttc); // reset the buffer return 0; } // be tolerant on errors static int uwsgi_routing_func_tofile(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_router_tofile_conf *urtc = (struct uwsgi_router_tofile_conf *) ur->data2; struct uwsgi_transformation_tofile_conf *uttc = uwsgi_calloc(sizeof(struct uwsgi_transformation_tofile_conf)); // build key and name char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); uttc->filename = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urtc->filename, urtc->filename_len); if (!uttc->filename) goto error; uwsgi_add_transformation(wsgi_req, transform_tofile, uttc); return UWSGI_ROUTE_NEXT; error: if (uttc->filename) uwsgi_buffer_destroy(uttc->filename); free(uttc); return UWSGI_ROUTE_NEXT; } static int uwsgi_router_tofile(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_tofile; ur->data = args; ur->data_len = strlen(args); struct uwsgi_router_tofile_conf *urtc = uwsgi_calloc(sizeof(struct uwsgi_router_tofile_conf)); if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=', "filename", &urtc->filename, "name", &urtc->filename, "mode", &urtc->mode, NULL)) { uwsgi_log("invalid tofile route syntax: %s\n", args); goto error; } if (!urtc->filename) { uwsgi_log("invalid tofile route syntax, you need to specify a filename\n"); goto error; } urtc->filename_len = strlen(urtc->filename); ur->data2 = urtc; return 0; error: if (urtc->filename) free(urtc->filename); free(urtc); return -1; } static void router_tofile_register() { uwsgi_register_router("tofile", uwsgi_router_tofile); uwsgi_register_router("to-file", uwsgi_router_tofile); } struct uwsgi_plugin transformation_tofile_plugin = { .name = "transformation_tofile", .on_load = router_tofile_register, }; #else struct uwsgi_plugin transformation_tofile_plugin = { .name = "transformation_tofile", }; #endif uwsgi-2.0.29/plugins/transformation_tofile/uwsgiplugin.py000066400000000000000000000001271477626554400240060ustar00rootroot00000000000000NAME='transformation_tofile' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['tofile'] uwsgi-2.0.29/plugins/transformation_toupper/000077500000000000000000000000001477626554400212735ustar00rootroot00000000000000uwsgi-2.0.29/plugins/transformation_toupper/toupper.c000066400000000000000000000014761477626554400231450ustar00rootroot00000000000000#include static int transform_toupper(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) { size_t i; for(i=0;ichunk->pos;i++) { ut->chunk->buf[i] = toupper((int) ut->chunk->buf[i]); } return 0; } static int uwsgi_routing_func_toupper(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_transformation *ut = uwsgi_add_transformation(wsgi_req, transform_toupper, NULL); ut->can_stream = 1; return UWSGI_ROUTE_NEXT; } static int uwsgi_router_toupper(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_toupper; return 0; } static void router_toupper_register(void) { uwsgi_register_router("toupper", uwsgi_router_toupper); } struct uwsgi_plugin transformation_toupper_plugin = { .name = "transformation_toupper", .on_load = router_toupper_register, }; uwsgi-2.0.29/plugins/transformation_toupper/uwsgiplugin.py000066400000000000000000000001311477626554400242150ustar00rootroot00000000000000NAME='transformation_toupper' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['toupper'] uwsgi-2.0.29/plugins/tuntap/000077500000000000000000000000001477626554400157625ustar00rootroot00000000000000uwsgi-2.0.29/plugins/tuntap/common.c000066400000000000000000000236051477626554400174240ustar00rootroot00000000000000#include "common.h" extern struct uwsgi_tuntap utt; // error reporting void uwsgi_tuntap_error_do(struct uwsgi_tuntap_peer *uttp, char *msg, char *file, int line) { if (uttp) { uwsgi_log_verbose("[tuntap] peer fd: %d ip: %s %s: %s [%s line %d]\n", uttp->fd, uttp->ip, msg, strerror(errno), file, line); } else { uwsgi_log_verbose("[tuntap] %s: %s [%s line %d]\n", msg, strerror(errno), file, line); } } // create a new peer struct uwsgi_tuntap_peer *uwsgi_tuntap_peer_create(struct uwsgi_tuntap_router *uttr, int fd, int is_router) { struct uwsgi_tuntap_peer *uttp = uwsgi_calloc(sizeof(struct uwsgi_tuntap_peer)); uttp->fd = fd; // leave space fot he uwsgi header uttp->buf = uwsgi_malloc(utt.buffer_size + 4); uttp->write_buf = uwsgi_malloc(utt.buffer_size); if (uttr->peers_tail) { uttr->peers_tail->next = uttp; uttp->prev = uttr->peers_tail; uttr->peers_tail = uttp; } else { uttr->peers_head = uttp; uttr->peers_tail = uttp; } if (!is_router) { if (utt.use_credentials) { uwsgi_log_verbose("[uwsgi-tuntap] waiting for privileges drop...\n"); for(;;) { if (getuid() > 0) break; sleep(1); } uwsgi_log_verbose("[uwsgi-tuntap] privileges dropped\n"); if (uwsgi_pass_cred(fd, "uwsgi-tuntap", 12)) { // better to exit exit(1); } } uwsgi_tuntap_peer_send_rules(fd, uttp); } return uttp; } // destroy a peer void uwsgi_tuntap_peer_destroy(struct uwsgi_tuntap_router *uttr, struct uwsgi_tuntap_peer *uttp) { struct uwsgi_tuntap_peer *prev = uttp->prev; struct uwsgi_tuntap_peer *next = uttp->next; if (prev) { prev->next = next; } if (next) { next->prev = prev; } if (uttp == uttr->peers_head) { uttr->peers_head = next; } if (uttp == uttr->peers_tail) { uttr->peers_tail = prev; } free(uttp->buf); free(uttp->write_buf); if (uttp->rules) free(uttp->rules); close(uttp->fd); free(uttp); } // get a peer by addr struct uwsgi_tuntap_peer *uwsgi_tuntap_peer_get_by_addr(struct uwsgi_tuntap_router *uttr, uint32_t addr) { struct uwsgi_tuntap_peer *uttp = uttr->peers_head; while (uttp) { if (uttp->addr == addr) return uttp; uttp = uttp->next; } return NULL; } // block all reading peers void uwsgi_tuntap_block_reads(struct uwsgi_tuntap_router *uttr) { struct uwsgi_tuntap_peer *uttp = uttr->peers_head; while (uttp) { if (!uttp->blocked_read) { if (!uttp->wait_for_write) { if (event_queue_del_fd(uttr->queue, uttp->fd, event_queue_read())) { struct uwsgi_tuntap_peer *tmp_uttp = uttp; uttp = uttp->next; uwsgi_tuntap_peer_destroy(uttr, tmp_uttp); continue; } } else { if (event_queue_fd_readwrite_to_write(uttr->queue, uttp->fd)) { struct uwsgi_tuntap_peer *tmp_uttp = uttp; uttp = uttp->next; uwsgi_tuntap_peer_destroy(uttr, tmp_uttp); continue; } } uttp->blocked_read = 1; } uttp = uttp->next; } } //unblock all reading peers void uwsgi_tuntap_unblock_reads(struct uwsgi_tuntap_router *uttr) { struct uwsgi_tuntap_peer *uttp = uttr->peers_head; while (uttp) { if (uttp->blocked_read) { if (!uttp->wait_for_write) { if (event_queue_add_fd_read(uttr->queue, uttp->fd)) { struct uwsgi_tuntap_peer *tmp_uttp = uttp; uttp = uttp->next; uwsgi_tuntap_peer_destroy(uttr, tmp_uttp); continue; } } else { if (event_queue_fd_write_to_readwrite(uttr->queue, uttp->fd)) { struct uwsgi_tuntap_peer *tmp_uttp = uttp; uttp = uttp->next; uwsgi_tuntap_peer_destroy(uttr, tmp_uttp); continue; } } uttp->blocked_read = 0; } uttp = uttp->next; } } // enqueue a packet in the tuntap device void uwsgi_tuntap_enqueue(struct uwsgi_tuntap_router *uttr) { ssize_t rlen = write(uttr->fd, uttr->write_buf + uttr->write_pos, uttr->write_pktsize - uttr->write_pos); // error on the tuntap device, destroy !!! if (rlen == 0) { uwsgi_error("uwsgi_tuntap_enqueue()/write()"); exit(1); } if (rlen < 0) { if (uwsgi_is_again()) goto retry; uwsgi_error("uwsgi_tuntap_enqueue()/write()"); exit(1); } uttr->write_pos += rlen; if (uttr->write_pos >= uttr->write_pktsize) { uttr->write_pos = 0; if (uttr->wait_for_write) { if (event_queue_fd_write_to_read(uttr->queue, uttr->fd)) { uwsgi_error("uwsgi_tuntap_enqueue()/event_queue_fd_read_to_write()"); exit(1); } uttr->wait_for_write = 0; } uwsgi_tuntap_unblock_reads(uttr); return; } retry: if (!uttr->wait_for_write) { uwsgi_tuntap_block_reads(uttr); if (event_queue_fd_read_to_write(uttr->queue, uttr->fd)) { uwsgi_error("uwsgi_tuntap_enqueue()/event_queue_fd_read_to_write()"); exit(1); } uttr->wait_for_write = 1; } } int uwsgi_tuntap_register_addr(struct uwsgi_tuntap_router *uttr, struct uwsgi_tuntap_peer *uttp) { struct uwsgi_tuntap_peer *tmp_uttp = uwsgi_tuntap_peer_get_by_addr(uttr, uttp->addr); char ip[INET_ADDRSTRLEN + 1]; memset(ip, 0, INET_ADDRSTRLEN + 1); if (!inet_ntop(AF_INET, &uttp->addr, ip, INET_ADDRSTRLEN)) { uwsgi_tuntap_error(uttp, "uwsgi_tuntap_register_addr()/inet_ntop()"); return -1; } if (uttp != tmp_uttp) { uwsgi_log("[tuntap-router] detected ip collision for %s\n", ip); uwsgi_tuntap_peer_destroy(uttr, tmp_uttp); } uwsgi_log("[tuntap-router] registered new peer %s (fd: %d)\n", ip, uttp->fd); memcpy(uttp->ip, ip, INET_ADDRSTRLEN + 1); return 0; } // receive a packet from the client int uwsgi_tuntap_peer_dequeue(struct uwsgi_tuntap_router *uttr, struct uwsgi_tuntap_peer *uttp, int is_router) { // get body if (uttp->header_pos >= 4) { ssize_t rlen = read(uttp->fd, uttp->buf + uttp->buf_pos, uttp->buf_pktsize - uttp->buf_pos); if (rlen == 0) return -1; if (rlen < 0) { if (uwsgi_is_again()) return 0; uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_dequeue()/read()"); return -1; } uttp->buf_pos += rlen; uttp->rx += rlen; // a whole pkt has been received if (uttp->buf_pos >= uttp->buf_pktsize) { uttp->header_pos = 0; uttp->buf_pos = 0; if (!is_router) goto enqueue; // a rule block if (uttp->header[3] == 1) { if (uttp->rules) free(uttp->rules); uttp->rules = uwsgi_malloc(uttp->buf_pktsize); memcpy(uttp->rules, uttp->buf, uttp->buf_pktsize); uttp->rules_cnt = uttp->buf_pktsize / sizeof(struct uwsgi_tuntap_peer_rule); return 0; } if (uwsgi_tuntap_firewall_check(utt.fw_out, uttp->buf, uttp->buf_pktsize)) return 0; // if there is no associated address store the source if (!uttp->addr) { // close on invalid first packet if (uttp->buf_pktsize < 20) return -1; uint32_t *src_ip = (uint32_t *) (&uttp->buf[12]); uttp->addr = *src_ip; // drop invalid ip addresses if (!uttp->addr) return -1; if (uwsgi_tuntap_register_addr(uttr, uttp)) { return -1; } } if (uwsgi_tuntap_peer_rules_check(uttr, uttp, uttp->buf, uttp->buf_pktsize, 1)) return 0; // check four routing rule if (uttr->gateway_fd > -1) { if (uwsgi_tuntap_route_check(uttr->gateway_fd, uttp->buf, uttp->buf_pktsize)) return 0; } enqueue: memcpy(uttr->write_buf, uttp->buf, uttp->buf_pktsize); uttr->write_pktsize = uttp->buf_pktsize; uwsgi_tuntap_enqueue(uttr); } return 0; } ssize_t rlen = read(uttp->fd, uttp->header + uttp->header_pos, 4 - uttp->header_pos); if (rlen == 0) return -1; if (rlen < 0) { if (uwsgi_is_again()) return 0; uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_dequeue()/read()"); return -1; } uttp->header_pos += rlen; if (uttp->header_pos >= 4) { uint16_t *pktsize = (uint16_t *) &uttp->header[1]; uttp->buf_pktsize = *pktsize; uttp->rx += 4; } return 0; } // enqueue a packet to the client int uwsgi_tuntap_peer_enqueue(struct uwsgi_tuntap_router *uttr, struct uwsgi_tuntap_peer *uttp) { ssize_t rlen = write(uttp->fd, uttp->write_buf + uttp->written, uttp->write_buf_pktsize - uttp->written); if (rlen == 0) { uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_enqueue()/write()"); return -1; } if (rlen < 0) { if (uwsgi_is_again()) goto retry; uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_enqueue()/write()"); return -1; } uttp->written += rlen; uttp->tx += rlen; if (uttp->written >= uttp->write_buf_pktsize) { uttp->written = 0; uttp->write_buf_pktsize = 0; if (uttp->wait_for_write) { // if the write ends while we are writing to the tuntap, block the reads if (uttr->wait_for_write) { uttp->blocked_read = 1; if (event_queue_del_fd(uttr->queue, uttp->fd, event_queue_write())) { uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_enqueue()/event_queue_del_fd()"); return -1; } } else { if (event_queue_fd_readwrite_to_read(uttr->queue, uttp->fd)) { uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_enqueue()/event_queue_fd_write_to_read()"); return -1; } } uttp->wait_for_write = 0; } return 0; } memmove(uttp->write_buf, uttp->write_buf + rlen, uttp->write_buf_pktsize - rlen); uttp->write_buf_pktsize -= rlen; retry: if (!uttp->wait_for_write) { if (event_queue_fd_read_to_readwrite(uttr->queue, uttp->fd)) { uwsgi_tuntap_error(uttp, "uwsgi_tuntap_peer_enqueue()/event_queue_fd_read_to_write()"); return -1; } uttp->wait_for_write = 1; } return 0; } int uwsgi_tuntap_device(char *name) { struct ifreq ifr; int fd = open(UWSGI_TUNTAP_DEVICE, O_RDWR); if (fd < 0) { uwsgi_error_open(UWSGI_TUNTAP_DEVICE); exit(1); } memset(&ifr, 0, sizeof(struct ifreq)); ifr.ifr_flags = IFF_TUN | IFF_NO_PI; strncpy(ifr.ifr_name, name, IFNAMSIZ); if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) { uwsgi_error("uwsgi_tuntap_device()/ioctl()"); exit(1); } uwsgi_log("initialized tuntap device %s (fd: %d)\n", ifr.ifr_name, fd); return fd; } uwsgi-2.0.29/plugins/tuntap/common.h000066400000000000000000000070111477626554400174220ustar00rootroot00000000000000#include #ifdef __linux__ #include #define UWSGI_TUNTAP_DEVICE "/dev/net/tun" #endif /* a peer is a client connected to the router. It has 2 queue, one for read and one for write. The write queue can be filled up. If the write queue is full, packets are dropped. */ struct uwsgi_tuntap_peer_rule { uint8_t direction; uint32_t src; uint32_t src_mask; uint32_t dst; uint32_t dst_mask; uint8_t action; uint32_t target; uint16_t target_port; } __attribute__ ((__packed__)); struct uwsgi_tuntap_peer { int fd; uint32_t addr; char ip[INET_ADDRSTRLEN+1]; int wait_for_write; int blocked_read; size_t written; char header[4]; uint8_t header_pos; char *buf; uint16_t buf_pktsize; uint16_t buf_pos; char *write_buf; uint16_t write_buf_pktsize; uint16_t write_buf_pos; struct uwsgi_tuntap_peer *prev; struct uwsgi_tuntap_peer *next; // counters uint64_t tx; uint64_t rx; uint64_t dropped; uint8_t sent_credentials; pid_t pid; uid_t uid; gid_t gid; struct uwsgi_tuntap_peer_rule *rules; int rules_cnt; }; struct uwsgi_tuntap_firewall_rule { uint8_t action; uint32_t src; uint32_t src_mask; uint32_t dst; uint32_t dst_mask; // for gateway struct sockaddr_in dest_addr; socklen_t addrlen; struct uwsgi_tuntap_firewall_rule *next; }; struct uwsgi_tuntap_router { int fd; int server_fd; int queue; char *buf; char *write_buf; struct uwsgi_tuntap_peer *peers_head; struct uwsgi_tuntap_peer *peers_tail; uint16_t write_pktsize; uint16_t write_pos; int wait_for_write; char *stats_server; int stats_server_fd; char *gateway; int gateway_fd; char *gateway_buf; char *subscription_server; int subscription_server_fd; }; struct uwsgi_tuntap { struct uwsgi_string_list *routers; struct uwsgi_string_list *devices; uint16_t buffer_size; struct uwsgi_tuntap_firewall_rule *fw_in; struct uwsgi_tuntap_firewall_rule *fw_out; struct uwsgi_tuntap_firewall_rule *routes; struct uwsgi_string_list *device_rules; char *stats_server; char *use_credentials; uint32_t (*addr_by_credentials)(pid_t, uid_t, gid_t); }; int uwsgi_tuntap_peer_dequeue(struct uwsgi_tuntap_router *, struct uwsgi_tuntap_peer *, int); int uwsgi_tuntap_peer_enqueue(struct uwsgi_tuntap_router *, struct uwsgi_tuntap_peer *); void uwsgi_tuntap_enqueue(struct uwsgi_tuntap_router *); int uwsgi_tuntap_firewall_check(struct uwsgi_tuntap_firewall_rule *, char *, uint16_t); int uwsgi_tuntap_route_check(int , char *, uint16_t); struct uwsgi_tuntap_peer *uwsgi_tuntap_peer_create(struct uwsgi_tuntap_router *, int, int); struct uwsgi_tuntap_peer *uwsgi_tuntap_peer_get_by_addr(struct uwsgi_tuntap_router *,uint32_t); void uwsgi_tuntap_peer_destroy(struct uwsgi_tuntap_router *, struct uwsgi_tuntap_peer *); int uwsgi_tuntap_device(char *); void uwsgi_tuntap_opt_firewall(char *, char *, void *); void uwsgi_tuntap_opt_route(char *, char *, void *); int uwsgi_tuntap_register_addr(struct uwsgi_tuntap_router *, struct uwsgi_tuntap_peer *); void uwsgi_tuntap_peer_send_rules(int, struct uwsgi_tuntap_peer *); int uwsgi_tuntap_peer_rules_check(struct uwsgi_tuntap_router *, struct uwsgi_tuntap_peer *, char *, size_t, int); #define uwsgi_tuntap_error(x, y) uwsgi_tuntap_error_do(x, y, __FILE__, __LINE__) void uwsgi_tuntap_error_do(struct uwsgi_tuntap_peer *, char *, char *, int); uwsgi-2.0.29/plugins/tuntap/firewall.c000066400000000000000000000270231477626554400177370ustar00rootroot00000000000000#include "common.h" extern struct uwsgi_tuntap utt; extern struct uwsgi_server uwsgi; int uwsgi_tuntap_peer_rules_check(struct uwsgi_tuntap_router *uttr, struct uwsgi_tuntap_peer *uttp, char *pkt, size_t len, int direction) { if (uttp->rules_cnt == 0) return 0; // sanity check if (len < 20) return -1; uint32_t *src_ip = (uint32_t *) &pkt[12]; uint32_t *dst_ip = (uint32_t *) &pkt[16]; uint32_t src = ntohl(*src_ip); uint32_t dst = ntohl(*dst_ip); #ifdef UWSGI_DEBUG uwsgi_log("%d %X %X\n",direction, src, dst); #endif int i; for(i=0;irules_cnt;i++) { struct uwsgi_tuntap_peer_rule *rule = &uttp->rules[i]; #ifdef UWSGI_DEBUG uwsgi_log("cnt = %i/%d direction = %d action = %d %X %X\n", i, uttp->rules_cnt, rule->direction, rule->action, rule->src_mask, rule->dst_mask); #endif if (rule->direction != direction) continue; if (rule->src) { uint32_t src_masked = src & rule->src_mask; if (src_masked != rule->src) continue; } if (rule->dst) { uint32_t dst_masked = dst & rule->dst_mask; if (dst_masked != rule->dst) continue; } if (rule->action == 0) return 0; if (rule->action == 1) return 1; if (rule->action == 2) { // if IN do not honour gateway/route if (!direction) return -1; if (uttr->gateway_fd > -1) { struct sockaddr_in sin; memset(&sin, 0, sizeof(struct sockaddr_in)); sin.sin_family = AF_INET; sin.sin_port = rule->target_port; sin.sin_addr.s_addr = rule->target; if (sendto(uttr->gateway_fd, pkt, len, 0, (struct sockaddr *) &sin, sizeof(struct sockaddr_in)) < 0) { if (uwsgi_is_again()) { // suspend and retry struct pollfd pfd; memset(&pfd, 0, sizeof(struct pollfd)); pfd.fd = uttr->gateway_fd; pfd.events = POLLOUT; int ret = poll(&pfd, 1, uwsgi.socket_timeout * 1000); if (ret > 0) { if (sendto(uttr->gateway_fd, pkt, len, 0, (struct sockaddr *) &sin, sizeof(struct sockaddr_in)) < 0) { uwsgi_tuntap_error(uttp,"uwsgi_tuntap_route_check()/sendto()"); } } else { uwsgi_tuntap_error(uttp,"uwsgi_tuntap_route_check()/poll()"); } } else { uwsgi_tuntap_error(uttp,"uwsgi_tuntap_route_check()/sendto()"); } } } return 2; } } return 0; } int uwsgi_tuntap_firewall_check(struct uwsgi_tuntap_firewall_rule *direction, char *pkt, uint16_t len) { // sanity check if (len < 20) return -1; uint32_t *src_ip = (uint32_t *) &pkt[12]; uint32_t *dst_ip = (uint32_t *) &pkt[16]; uint32_t src = ntohl(*src_ip); uint32_t dst = ntohl(*dst_ip); struct uwsgi_tuntap_firewall_rule *utfr = direction; while(utfr) { if (utfr->src) { uint32_t src_masked = src & utfr->src_mask; if (src_masked != utfr->src) goto next; } if (utfr->dst) { uint32_t dst_masked = dst & utfr->dst_mask; if (dst_masked != utfr->dst) goto next; } return utfr->action; next: utfr = utfr->next; } return 0; } int uwsgi_tuntap_route_check(int fd, char *pkt, uint16_t len) { // sanity check if (len < 20) return -1; uint32_t *src_ip = (uint32_t *) &pkt[12]; uint32_t *dst_ip = (uint32_t *) &pkt[16]; uint32_t src = ntohl(*src_ip); uint32_t dst = ntohl(*dst_ip); struct uwsgi_tuntap_firewall_rule *utrr = utt.routes; while(utrr) { if (utrr->src) { uint32_t src_masked = src & utrr->src_mask; if (src_masked != utrr->src) goto next; } if (utrr->dst) { uint32_t dst_masked = dst & utrr->dst_mask; if (dst_masked != utrr->dst) goto next; } if (sendto(fd, pkt, len, 0, (struct sockaddr *) &utrr->dest_addr, utrr->addrlen) < 0) { uwsgi_error("uwsgi_tuntap_route_check()/sendto()"); } return 1; next: utrr = utrr->next; } return 0; } static struct uwsgi_tuntap_firewall_rule *uwsgi_tuntap_firewall_add_rule(struct uwsgi_tuntap_firewall_rule **direction, uint8_t action, uint32_t src, uint32_t src_mask, uint32_t dst, uint32_t dst_mask) { #ifdef UWSGI_DEBUG uwsgi_log("[tuntap-router] firewall action %d %x %x %x %x\n",action, src,src_mask,dst,dst_mask); #endif struct uwsgi_tuntap_firewall_rule *old_uttr = NULL, *uttr = *direction; while(uttr) { old_uttr = uttr; uttr = uttr->next; } uttr = uwsgi_calloc(sizeof(struct uwsgi_tuntap_firewall_rule)); uttr->action = action; uttr->src = src & src_mask; uttr->src_mask = src_mask; uttr->dst = dst & dst_mask; uttr->dst_mask = dst_mask; if (old_uttr) { old_uttr->next = uttr; } else { *direction = uttr; } return uttr; } void uwsgi_tuntap_opt_firewall(char *opt, char *value, void *direction) { char *space = strchr(value, ' '); if (!space) { if (!strcmp("deny", value)) { uwsgi_tuntap_firewall_add_rule((struct uwsgi_tuntap_firewall_rule **) direction, 1, 0, 0, 0, 0); return; } uwsgi_tuntap_firewall_add_rule((struct uwsgi_tuntap_firewall_rule **) direction, 0, 0, 0, 0, 0); return; } *space = 0; uint8_t action = 0; if (!strcmp(value, "deny")) action = 1; char *space2 = strchr(space + 1, ' '); if (!space2) { uwsgi_log("invalid tuntap firewall rule syntax. must be "); return; } *space2 = 0; uint32_t src = 0; uint32_t src_mask = 32; uint32_t dst = 0; uint32_t dst_mask = 32; char *slash = strchr(space + 1 , '/'); if (slash) { src_mask = atoi(slash+1); *slash = 0; } if (inet_pton(AF_INET, space + 1, &src) != 1) { uwsgi_error("uwsgi_tuntap_opt_firewall()/inet_pton()"); exit(1); } if (slash) *slash = '/'; *space = ' '; slash = strchr(space2 + 1 , '/'); if (slash) { dst_mask = atoi(slash+1); *slash = 0; } if (inet_pton(AF_INET, space2 + 1, &dst) != 1) { uwsgi_error("uwsgi_tuntap_opt_firewall()/inet_pton()"); exit(1); } if (slash) *slash = '/'; *space2 = ' '; uwsgi_tuntap_firewall_add_rule((struct uwsgi_tuntap_firewall_rule **) direction, action, ntohl(src), (0xffffffff << (32-src_mask)), ntohl(dst), (0xffffffff << (32-dst_mask))); } void uwsgi_tuntap_opt_route(char *opt, char *value, void *table) { char *space = strchr(value, ' '); if (!space) { uwsgi_log("invalid tuntap routing rule syntax, must be: \n"); exit(1); } *space = 0; char *space2 = strchr(space + 1, ' '); if (!space2) { uwsgi_log("invalid tuntap routing rule syntax, must be: \n"); exit(1); } *space2 = 0; uint32_t src = 0; uint32_t src_mask = 32; uint32_t dst = 0; uint32_t dst_mask = 32; char *slash = strchr(value , '/'); if (slash) { src_mask = atoi(slash+1); *slash = 0; } if (inet_pton(AF_INET, value, &src) != 1) { uwsgi_error("uwsgi_tuntap_opt_route()/inet_pton()"); exit(1); } if (slash) *slash = '/'; slash = strchr(space+1 , '/'); if (slash) { dst_mask = atoi(slash+1); *slash = 0; } if (inet_pton(AF_INET, space+1, &dst) != 1) { uwsgi_error("uwsgi_tuntap_opt_route()/inet_pton()"); exit(1); } if (slash) *slash = '/'; *space = ' '; *space2 = ' '; struct uwsgi_tuntap_firewall_rule * utfr = uwsgi_tuntap_firewall_add_rule((struct uwsgi_tuntap_firewall_rule **) table, 1, ntohl(src), (0xffffffff << (32-src_mask)), ntohl(dst), (0xffffffff << (32-dst_mask))); char *colon = strchr(space2+1, ':'); if (!colon) { uwsgi_log("tuntap routing gateway must be a udp address in the form addr:port\n"); exit(1); } utfr->dest_addr.sin_family = AF_INET; utfr->dest_addr.sin_port = htons(atoi(colon+1)); *colon = 0; utfr->dest_addr.sin_addr.s_addr = inet_addr(space2+1); *colon = ':'; utfr->addrlen = sizeof(struct sockaddr_in); } void uwsgi_tuntap_peer_send_rules(int fd, struct uwsgi_tuntap_peer *peer) { struct uwsgi_string_list *usl = NULL; if (!utt.device_rules) return; struct uwsgi_buffer *ub = uwsgi_buffer_new(sizeof(struct uwsgi_tuntap_peer_rule) + 4); // leave space for the uwsgi header ub->pos = 4; uwsgi_foreach(usl, utt.device_rules) { size_t rlen; char **argv = uwsgi_split_quoted(usl->value, usl->len, " \t", &rlen); if (rlen < 4) { uwsgi_log("invalid tuntap device rule, must be [target]\n"); exit(1); } struct uwsgi_tuntap_peer_rule utpr; memset(&utpr, 0, sizeof(struct uwsgi_tuntap_peer_rule)); utpr.src_mask = 0xffffffff; utpr.dst_mask = 0xffffffff; if (!strcmp(argv[0], "in")) { utpr.direction = 0; } else if (!strcmp(argv[0], "out")) { utpr.direction = 1; } else { uwsgi_log("invalid tuntap device rule direction, must be 'in' or 'out'\n"); exit(1); } char *slash = strchr(argv[1],'/'); if (slash) { utpr.src_mask = (0xffffffff << ((atoi(slash+1))-32)); *slash = 0; } if (inet_pton(AF_INET, argv[1], &utpr.src) != 1) { uwsgi_tuntap_error(peer, "uwsgi_tuntap_peer_send_rules()/inet_pton()"); exit(1); } if (slash) *slash = '/'; utpr.src = ntohl(utpr.src); slash = strchr(argv[2],'/'); if (slash) { utpr.dst_mask = (0xffffffff << ((atoi(slash+1))-32)); *slash = 0; } if (inet_pton(AF_INET, argv[2], &utpr.dst) != 1) { uwsgi_tuntap_error(peer, "uwsgi_tuntap_peer_send_rules()/inet_pton()"); exit(1); } if (slash) *slash = '/'; utpr.dst = ntohl(utpr.dst); if (!strcmp(argv[3], "deny")) { utpr.action = 1; } else if (!strcmp(argv[3], "allow")) { utpr.action = 0; } else if (!strcmp(argv[3], "route")) { utpr.action = 2; } else if (!strcmp(argv[3], "gateway")) { utpr.action = 2; } else { uwsgi_log("unsupported tuntap rule action: %s\n", argv[3]); exit(1); } if (utpr.action == 2) { if (rlen < 4) { uwsgi_log("tuntap rule route/gateway requires a target\n"); exit(1); } char *colon = strchr(argv[4], ':'); if (!colon) { uwsgi_log("tuntap target must be in the form addr:port\n"); exit(1); } *colon = 0; if (inet_pton(AF_INET, argv[4], &utpr.target) != 1) { uwsgi_tuntap_error(peer, "uwsgi_tuntap_peer_send_rules()/inet_pton()"); exit(1); } *colon = ':'; utpr.target = utpr.target; utpr.target_port = htons(atoi(colon+1)); } if (uwsgi_buffer_append(ub, (char *) &utpr, sizeof(struct uwsgi_tuntap_peer_rule))) goto error; peer->rules_cnt++; } // we still do not have an official modifier for the tuntap router if (uwsgi_buffer_set_uh(ub, 0, 1)) goto error; peer->rules = (struct uwsgi_tuntap_peer_rule *)ub->buf; ub->buf = NULL; size_t len = ub->pos; uwsgi_buffer_destroy(ub); if (write(fd,peer->rules, len) != (ssize_t)len) { uwsgi_tuntap_error(peer, "uwsgi_tuntap_peer_send_rules()/write()"); exit(1); } return; error: uwsgi_log("unable to create tuntap device rules packet\n"); exit(1); } uwsgi-2.0.29/plugins/tuntap/tuntap.c000066400000000000000000000440201477626554400174410ustar00rootroot00000000000000#include "common.h" extern struct uwsgi_server uwsgi; struct uwsgi_tuntap utt; /* The tuntap router is a non-blocking highly optimized ip router translating from tuntap device to socket streams. It is meant as a replacement for the currently available networking namespaces approaches. Compared to veth or macvlan it is really simple and allows total control over the routing subsystem (in addition to a simple customizable firewalling engine) Generally you spawn the tuntap router in the Emperor instance [uwsgi] master = true emperor = /etc/uwsgi emperor-use-clone = fs,uts,ipc,pid,net tuntap-router = emperor0 /tmp/tuntap.socket exec-as-root = ifconfig emperor0 192.168.0.1 netmask 255.255.255.0 up exec-as-root = iptables -t nat -F exec-as-root = iptables -t nat -A POSTROUTING -o eth0 -s 192.168.0.0/24 -j MASQUERADE exec-as-root = echo 1 > /proc/sys/net/ipv4/ip_forward vassals will run in new namespaces in which they create a tuntap device attached to the tuntap router. UNIX sockets are the only way to connect to the tuntap router after jailing. Firewalling is based on 2 chains (in and out), and each rule is formed by 3 parameters: The firewall is applied to traffic from the clients to the tuntap device (out) and the opposite (in) The first matching rule stop the chain, if no rule applies, the policy is "allow" the following rules allows access from vassals to the internet, but block vassals intercommunication --tuntap-router-firewall-out = allow 192.168.0.0/24 192.168.0.1 --tuntap-router-firewall-out = deny 192.168.0.0/24 192.168.0.0/24 --tuntap-router-firewall-out = allow 192.168.0.0/24 0.0.0.0 --tuntap-router-firewall-out = deny --tuntap-router-firewall-in = allow 192.168.0.1 192.168.0.0/24 --tuntap-router-firewall-in = deny 192.168.0.0/24 192.168.0.0/24 --tuntap-router-firewall-in = allow 0.0.0.0 192.168.0.0/24 --tuntap-router-firewall-in = deny Author: Roberto De Ioris TODO: - some form of security to disallow raw access to the tuntap router unix socket - stats server - port to other platforms ? */ static struct uwsgi_option uwsgi_tuntap_options[] = { {"tuntap-router", required_argument, 0, "run the tuntap router (syntax: [stats] [gateway])", uwsgi_opt_add_string_list, &utt.routers, 0}, {"tuntap-device", required_argument, 0, "add a tuntap device to the instance (syntax: [ ])", uwsgi_opt_add_string_list, &utt.devices, 0}, {"tuntap-use-credentials", optional_argument, 0, "enable check of SCM_CREDENTIALS for tuntap client/server", uwsgi_opt_set_str, &utt.use_credentials, 0}, {"tuntap-router-firewall-in", required_argument, 0, "add a firewall rule to the tuntap router (syntax: )", uwsgi_tuntap_opt_firewall, &utt.fw_in, 0}, {"tuntap-router-firewall-out", required_argument, 0, "add a firewall rule to the tuntap router (syntax: )", uwsgi_tuntap_opt_firewall, &utt.fw_out, 0}, {"tuntap-router-route", required_argument, 0, "add a routing rule to the tuntap router (syntax: )", uwsgi_tuntap_opt_route, &utt.routes, 0}, {"tuntap-router-stats", required_argument, 0, "run the tuntap router stats server", uwsgi_opt_set_str, &utt.stats_server, 0}, {"tuntap-device-rule", required_argument, 0, "add a tuntap device rule (syntax: [target])", uwsgi_opt_add_string_list, &utt.device_rules, 0}, {NULL, 0, 0, NULL, NULL, NULL, 0}, }; static void *uwsgi_tuntap_loop(void *arg) { // block signals on this thread sigset_t smask; sigfillset(&smask); #ifndef UWSGI_DEBUG sigdelset(&smask, SIGSEGV); #endif pthread_sigmask(SIG_BLOCK, &smask, NULL); struct uwsgi_tuntap_router *uttr = (struct uwsgi_tuntap_router *) arg; uwsgi_socket_nb(uttr->fd); if (!utt.buffer_size) utt.buffer_size = 8192; uttr->buf = uwsgi_malloc(utt.buffer_size); uttr->write_buf = uwsgi_malloc(utt.buffer_size); uttr->queue = event_queue_init(); if (event_queue_add_fd_read(uttr->queue, uttr->fd)) { exit(1); } if (event_queue_add_fd_read(uttr->queue, uttr->server_fd)) { exit(1); } uwsgi_socket_nb(uttr->server_fd); struct uwsgi_tuntap_peer *uttp = uwsgi_tuntap_peer_create(uttr, uttr->server_fd, 0); for (;;) { int interesting_fd = -1; int ret = event_queue_wait(uttr->queue, -1, &interesting_fd); if (ret <= 0) continue; if (interesting_fd == uttr->fd) { if (uttr->wait_for_write) { uwsgi_tuntap_enqueue(uttr); continue; } ssize_t rlen = read(uttr->fd, uttr->buf, utt.buffer_size); if (rlen <= 0) { uwsgi_error("uwsgi_tuntap_loop()/read()"); exit(1); } // check for full write buffer if (uttp->write_buf_pktsize + 4 + rlen > utt.buffer_size) { uttp->dropped++; continue; } uint16_t pktsize = rlen; char *ptr = uttp->write_buf + uttp->write_buf_pktsize; memcpy(ptr + 4, uttr->buf, rlen); ptr[0] = 0; ptr[1] = (uint8_t) (pktsize & 0xff); ptr[2] = (uint8_t) ((pktsize >> 8) & 0xff); ptr[3] = 0; uttp->write_buf_pktsize+= pktsize+4; if (uwsgi_tuntap_peer_enqueue(uttr, uttp)) { uwsgi_log_verbose("tuntap server disconnected...\n"); exit(1); } continue; } if (interesting_fd == uttr->server_fd) { // read from the client if (!uttp->wait_for_write) { if (uwsgi_tuntap_peer_dequeue(uttr, uttp, 0)) { uwsgi_log_verbose("tuntap server disconnected...\n"); exit(1); } } else { // something is wrong (the tuntap device is blocked) if (uttr->wait_for_write) { continue; } // write to the client if (uwsgi_tuntap_peer_enqueue(uttr, uttp)) { uwsgi_log_verbose("tuntap server disconnected...\n"); exit(1); } } } } return NULL; } static void uwsgi_tuntap_client() { if (!utt.devices) return; struct uwsgi_string_list *usl; uwsgi_foreach(usl, utt.devices) { char *space = strchr(usl->value, ' '); if (space) { *space = 0; struct uwsgi_tuntap_router *uttr = uwsgi_calloc(sizeof(struct uwsgi_tuntap_router)); uttr->fd = uwsgi_tuntap_device(usl->value); uttr->server_fd = uwsgi_connect(space+1, 30, 0); if (uttr->server_fd < 0) { uwsgi_error("uwsgi_tuntap_client()/uwsgi_connect()"); exit(1); } *space = ' '; pthread_t t; pthread_create(&t, NULL, uwsgi_tuntap_loop, uttr); } else { if (uwsgi_tuntap_device(usl->value) < 0) { // foo } } } } void tuntaprouter_send_stats(struct uwsgi_tuntap_router *); void uwsgi_tuntap_router_loop(int id, void *arg) { int i; struct uwsgi_tuntap_router *uttr = (struct uwsgi_tuntap_router *) arg; uttr->buf = uwsgi_malloc(utt.buffer_size); uttr->write_buf = uwsgi_malloc(utt.buffer_size); uttr->queue = event_queue_init(); uttr->stats_server_fd = -1; uttr->gateway_fd = -1; void *events = event_queue_alloc(64); if (event_queue_add_fd_read(uttr->queue, uttr->server_fd)) exit(1); if (event_queue_add_fd_read(uttr->queue, uttr->fd)) exit(1); char *stats_server = utt.stats_server; if (uttr->stats_server) stats_server = uttr->stats_server; if (stats_server) { char *tcp_port = strchr(stats_server, ':'); if (tcp_port) { // disable deferred accept for this socket int current_defer_accept = uwsgi.no_defer_accept; uwsgi.no_defer_accept = 1; uttr->stats_server_fd = bind_to_tcp(stats_server, uwsgi.listen_queue, tcp_port); uwsgi.no_defer_accept = current_defer_accept; } else { uttr->stats_server_fd = bind_to_unix(stats_server, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); } if (event_queue_add_fd_read(uttr->queue, uttr->stats_server_fd)) exit(1); uwsgi_log("*** tuntap stats server enabled on %s fd: %d ***\n", stats_server, uttr->stats_server_fd); uwsgi_socket_nb(uttr->stats_server_fd); } if (uttr->gateway) { uttr->gateway_fd = bind_to_udp(uttr->gateway, 0, 0); if (uttr->gateway_fd < 0) exit(1); if (event_queue_add_fd_read(uttr->queue, uttr->gateway_fd)) exit(1); uwsgi_log("*** tuntap gateway address enabled on %s\n", uttr->gateway); uttr->gateway_buf = uwsgi_malloc(utt.buffer_size); uwsgi_socket_nb(uttr->gateway_fd); } for (;;) { int nevents = event_queue_wait_multi(uttr->queue, -1, events, 64); for (i = 0; i < nevents; i++) { int interesting_fd = event_queue_interesting_fd(events, i); if (interesting_fd == uttr->fd) { // if writing, continue enqueuing if (uttr->wait_for_write) { uwsgi_tuntap_enqueue(uttr); continue; } ssize_t rlen = read(uttr->fd, uttr->buf, utt.buffer_size); if (rlen <= 0) { uwsgi_error("uwsgi_tuntap_router_loop()/read()"); exit(1); } if (rlen < 20) continue; if (uwsgi_tuntap_firewall_check(utt.fw_in, uttr->buf, rlen)) continue; uint32_t *dst_ip = (uint32_t *) & uttr->buf[16]; struct uwsgi_tuntap_peer *uttp = uwsgi_tuntap_peer_get_by_addr(uttr, *dst_ip); if (!uttp) continue; if (uwsgi_tuntap_peer_rules_check(uttr, uttp, uttr->buf, rlen, 0)) continue; // check for full write buffer if (uttp->write_buf_pktsize + 4 + rlen > utt.buffer_size) { uttp->dropped++; continue; } uint16_t pktsize = rlen; char *ptr = uttp->write_buf + uttp->write_buf_pktsize; memcpy(ptr + 4, uttr->buf, rlen); ptr[0] = 0; ptr[1] = (uint8_t) (pktsize & 0xff); ptr[2] = (uint8_t) ((pktsize >> 8) & 0xff); ptr[3] = 0; uttp->write_buf_pktsize+= pktsize+4; if (uwsgi_tuntap_peer_enqueue(uttr, uttp)) { uwsgi_tuntap_peer_destroy(uttr, uttp); } continue; } if (interesting_fd == uttr->server_fd) { int client_fd = uwsgi_accept(uttr->server_fd); if (client_fd < 0) { uwsgi_error("uwsgi_tuntap_server_loop()/accept()"); continue; } if (utt.use_credentials) { if (uwsgi_socket_passcred(client_fd)) { close(client_fd); continue; } } struct uwsgi_tuntap_peer *uttp = uwsgi_tuntap_peer_create(uttr, client_fd, 1); if (event_queue_add_fd_read(uttr->queue, uttp->fd)) { uwsgi_tuntap_peer_destroy(uttr, uttp); } continue; } if (uttr->stats_server_fd > -1 && interesting_fd == uttr->stats_server_fd) { tuntaprouter_send_stats(uttr); continue; } if (uttr->gateway_fd > -1 && interesting_fd == uttr->gateway_fd) { ssize_t rlen = read(uttr->gateway_fd, uttr->gateway_buf, utt.buffer_size); if (rlen <= 0) { uwsgi_error("uwsgi_tuntap_router_loop()/read()"); continue; } if (rlen < 20) continue; if (uwsgi_tuntap_firewall_check(utt.fw_in, uttr->gateway_buf, rlen)) continue; uint32_t *dst_ip = (uint32_t *) & uttr->gateway_buf[16]; struct uwsgi_tuntap_peer *uttp = uwsgi_tuntap_peer_get_by_addr(uttr, *dst_ip); if (!uttp) continue; // check for full write buffer if (uttp->write_buf_pktsize + 4 + rlen > utt.buffer_size) { uttp->dropped++; continue; } uint16_t pktsize = rlen; char *ptr = uttp->write_buf + uttp->write_buf_pktsize; memcpy(ptr + 4, uttr->gateway_buf, rlen); ptr[0] = 0; ptr[1] = (uint8_t) (pktsize & 0xff); ptr[2] = (uint8_t) ((pktsize >> 8) & 0xff); ptr[3] = 0; uttp->write_buf_pktsize+= pktsize+4; if (uwsgi_tuntap_peer_enqueue(uttr, uttp)) { uwsgi_tuntap_peer_destroy(uttr, uttp); } continue; } struct uwsgi_tuntap_peer *uttp = uttr->peers_head; while (uttp) { if (interesting_fd == uttp->fd) { // read from the client if (event_queue_interesting_fd_is_read(events, i)) { if (utt.use_credentials) { if (uttp->addr == 0) { if (!uttp->sent_credentials) { if (uwsgi_recv_cred(uttp->fd, "uwsgi-tuntap", 12, &uttp->pid, &uttp->uid, &uttp->gid)) { uwsgi_tuntap_peer_destroy(uttr, uttp); break; } if (utt.addr_by_credentials) { uttp->addr = utt.addr_by_credentials(uttp->pid, uttp->uid, uttp->gid); if (!uttp->addr) { uwsgi_tuntap_peer_destroy(uttr, uttp); break; } if (uwsgi_tuntap_register_addr(uttr, uttp)) { uwsgi_tuntap_peer_destroy(uttr, uttp); break; } } uttp->sent_credentials = 1; break; } else { // if credentials are sent and a function is available, destroy the peer (if addr is 0) if (utt.addr_by_credentials) { uwsgi_tuntap_peer_destroy(uttr, uttp); break; } } } } if (uwsgi_tuntap_peer_dequeue(uttr, uttp, 1)) { uwsgi_tuntap_peer_destroy(uttr, uttp); break; } } if (event_queue_interesting_fd_is_write(events, i)) { // something is wrong (the tuntap device is blocked) if (uttr->wait_for_write) break; // write to the client if (uwsgi_tuntap_peer_enqueue(uttr, uttp)) { uwsgi_tuntap_peer_destroy(uttr, uttp); break; } } break; } uttp = uttp->next; } } } } static void uwsgi_tuntap_router() { if (!utt.routers) return; if (!utt.buffer_size) utt.buffer_size = 8192; if (utt.use_credentials) { if (utt.use_credentials[0] != 0 && strcmp(utt.use_credentials, "true")) { utt.addr_by_credentials = (uint32_t (*)(pid_t, uid_t, gid_t)) dlsym(RTLD_DEFAULT, utt.use_credentials); if (!utt.addr_by_credentials) { uwsgi_log("[uwsgi-tuntap] unable to find symbol %s\n", utt.use_credentials); exit(1); } } } struct uwsgi_string_list *usl; uwsgi_foreach(usl, utt.routers) { size_t rlen = 0; char **args = uwsgi_split_quoted(usl->value, usl->len, " \t", &rlen); if (rlen < 2) { uwsgi_log("invalid tuntap router syntax, must be [stats] [gateway]\n"); exit(1); } struct uwsgi_tuntap_router *uttr = uwsgi_calloc(sizeof(struct uwsgi_tuntap_router)); uttr->server_fd = bind_to_unix(args[1], uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); uttr->fd = uwsgi_tuntap_device(args[0]); if (rlen > 2) uttr->stats_server = args[2]; if (rlen > 3) uttr->gateway = args[3]; if (register_gateway("uWSGI tuntap router", uwsgi_tuntap_router_loop, uttr) == NULL) { uwsgi_log("unable to register the tuntap server gateway\n"); exit(1); } } } void tuntaprouter_send_stats(struct uwsgi_tuntap_router *uttr) { struct sockaddr_un client_src; socklen_t client_src_len = 0; int client_fd = accept(uttr->stats_server_fd, (struct sockaddr *) &client_src, &client_src_len); if (client_fd < 0) { uwsgi_error("tuntaprouter_send_stats()/accept()"); return; } if (uwsgi.stats_http) { if (uwsgi_send_http_stats(client_fd)) { close(client_fd); return; } } struct uwsgi_stats *us = uwsgi_stats_new(8192); if (uwsgi_stats_keyval_comma(us, "version", UWSGI_VERSION)) goto end; if (uwsgi_stats_keylong_comma(us, "pid", (unsigned long long) getpid())) goto end; if (uwsgi_stats_keylong_comma(us, "uid", (unsigned long long) getuid())) goto end; if (uwsgi_stats_keylong_comma(us, "gid", (unsigned long long) getgid())) goto end; char *cwd = uwsgi_get_cwd(); if (uwsgi_stats_keyval_comma(us, "cwd", cwd)) goto end0; if (uwsgi_stats_key(us , "peers")) goto end0; if (uwsgi_stats_list_open(us)) goto end0; struct uwsgi_tuntap_peer *uttp = uttr->peers_head; while (uttp) { if (uwsgi_stats_object_open(us)) goto end0; if (uwsgi_stats_keyval_comma(us, "addr", uttp->ip)) goto end0; if (uwsgi_stats_keylong_comma(us, "addr_32", uttp->addr)) goto end0; if (uwsgi_stats_keylong_comma(us, "uid", uttp->uid)) goto end0; if (uwsgi_stats_keylong_comma(us, "gid", uttp->gid)) goto end0; if (uwsgi_stats_keylong_comma(us, "pid", uttp->pid)) goto end0; if (uwsgi_stats_keylong_comma(us, "tx", uttp->tx)) goto end0; if (uwsgi_stats_keylong_comma(us, "rx", uttp->rx)) goto end0; if (uwsgi_stats_keylong(us, "dropped", uttp->dropped)) goto end0; if (uwsgi_stats_object_close(us)) goto end0; uttp = uttp->next; if (uttp) { if (uwsgi_stats_comma(us)) goto end0; } } if (uwsgi_stats_list_close(us)) goto end0; if (uwsgi_stats_object_close(us)) goto end0; size_t remains = us->pos; off_t pos = 0; while(remains > 0) { int ret = uwsgi_waitfd_write(client_fd, uwsgi.socket_timeout); if (ret <= 0) { goto end0; } ssize_t res = write(client_fd, us->base + pos, remains); if (res <= 0) { if (res < 0) { uwsgi_error("tuntaprouter_send_stats()/write()"); } goto end0; } pos += res; remains -= res; } end0: free(cwd); end: free(us->base); free(us); close(client_fd); } struct uwsgi_plugin tuntap_plugin = { .name = "tuntap", .options = uwsgi_tuntap_options, .post_jail = uwsgi_tuntap_client, .jail = uwsgi_tuntap_router, }; uwsgi-2.0.29/plugins/tuntap/uwsgiplugin.py000066400000000000000000000001231477626554400207050ustar00rootroot00000000000000NAME='tuntap' CFLAGS=[] LDFLAGS=[] LIBS=[] GCC_LIST=['common','firewall','tuntap'] uwsgi-2.0.29/plugins/ugreen/000077500000000000000000000000001477626554400157345ustar00rootroot00000000000000uwsgi-2.0.29/plugins/ugreen/ugreen.c000066400000000000000000000062151477626554400173710ustar00rootroot00000000000000/* uGreen -> uWSGI green threads */ #include #ifdef __UCLIBC__ struct uwsgi_plugin ugreen_plugin = { .name = "ugreen", }; #else #ifdef __APPLE__ #define _XOPEN_SOURCE #endif #include struct uwsgi_ugreen { int ugreen; int stackpages; ucontext_t main; ucontext_t *contexts; size_t u_stack_size; } ug; #define UGREEN_DEFAULT_STACKSIZE 256*1024 extern struct uwsgi_server uwsgi; static struct uwsgi_option ugreen_options[] = { {"ugreen", no_argument, 0, "enable ugreen coroutine subsystem", uwsgi_opt_true, &ug.ugreen, 0}, {"ugreen-stacksize", required_argument, 0, "set ugreen stack size in pages", uwsgi_opt_set_int, &ug.stackpages, 0}, { 0, 0, 0, 0, 0, 0, 0 } }; static void u_green_schedule_to_req() { int id = uwsgi.wsgi_req->async_id; uint8_t modifier1 = uwsgi.wsgi_req->uh->modifier1; // first round ? if (!uwsgi.wsgi_req->suspended) { ug.contexts[id].uc_link = &ug.main; makecontext(&ug.contexts[id], async_schedule_to_req_green, 0); uwsgi.wsgi_req->suspended = 1; } // call it in the main core if (uwsgi.p[modifier1]->suspend) { uwsgi.p[modifier1]->suspend(NULL); } // save the main stack and switch to the core swapcontext(&ug.main, &ug.contexts[id] ); // call it in the main core if (uwsgi.p[modifier1]->resume) { uwsgi.p[modifier1]->resume(NULL); } } static void u_green_schedule_to_main(struct wsgi_request *wsgi_req) { if (uwsgi.p[wsgi_req->uh->modifier1]->suspend) { uwsgi.p[wsgi_req->uh->modifier1]->suspend(wsgi_req); } // back to main swapcontext(&ug.contexts[wsgi_req->async_id], &ug.main); // back to core if (uwsgi.p[wsgi_req->uh->modifier1]->resume) { uwsgi.p[wsgi_req->uh->modifier1]->resume(wsgi_req); } uwsgi.wsgi_req = wsgi_req; } static int u_green_init() { static int i; if (!ug.ugreen) { return 0; } ug.u_stack_size = UGREEN_DEFAULT_STACKSIZE; if (ug.stackpages > 0) { ug.u_stack_size = ug.stackpages * uwsgi.page_size; } uwsgi_log("initializing %d uGreen threads with stack size of %lu (%lu KB)\n", uwsgi.async, (unsigned long) ug.u_stack_size, (unsigned long) ug.u_stack_size/1024); ug.contexts = uwsgi_malloc( sizeof(ucontext_t) * uwsgi.async); for(i=0;i int uwsgi_v8_init(void); void uwsgi_v8_apps(void); void uwsgi_v8_configurator(char *, char **); uint64_t uwsgi_v8_rpc(void *, uint8_t, char **, uint16_t *, char **); int uwsgi_v8_signal_handler(uint8_t, void *); void uwsgi_v8_init_thread(int); void uwsgi_v8_enable_threads(); int uwsgi_v8_mule(char *); static void uwsgi_v8_register(void) { uwsgi_register_configurator(".js", uwsgi_v8_configurator); } extern struct uwsgi_option uwsgi_v8_options[]; int uwsgi_v8_request(struct wsgi_request *); static void uwsgi_v8_after_request(struct wsgi_request *wsgi_req) { log_request(wsgi_req); } struct uwsgi_plugin v8_plugin = { .name = "v8", .modifier1 = 24, .init = uwsgi_v8_init, .init_apps = uwsgi_v8_apps, .options = uwsgi_v8_options, .on_load = uwsgi_v8_register, .rpc = uwsgi_v8_rpc, .request = uwsgi_v8_request, .after_request = uwsgi_v8_after_request, .signal_handler = uwsgi_v8_signal_handler, .enable_threads = uwsgi_v8_enable_threads, .init_thread = uwsgi_v8_init_thread, .mule = uwsgi_v8_mule, }; uwsgi-2.0.29/plugins/v8/uwsgiplugin.py000066400000000000000000000005061477626554400177340ustar00rootroot00000000000000import os NAME='v8' CFLAGS = ['-Wno-deprecated-declarations'] LDFLAGS = [] LIBS = ['-lstdc++', '-lv8'] engine = os.environ.get('UWSGICONFIG_V8_ENGINE', '') if engine == 'teajs': CFLAGS.append('-DUWSGI_V8_TEAJS -fexceptions') LIBS.append('-lteajs') GCC_LIST = ['plugin', 'v8_uwsgi.cc', 'v8_commonjs.cc', 'v8_jsgi.cc'] uwsgi-2.0.29/plugins/v8/v8_commonjs.cc000066400000000000000000000110151477626554400175530ustar00rootroot00000000000000#include "v8_uwsgi.h" extern struct uwsgi_server uwsgi; #ifdef UWSGI_V8_TEAJS #include "app.h" #include "macros.h" class TeaJS_uWSGI : public TeaJS_App { public: void init() { TeaJS_App::init(); v8::HandleScope handle_scope; this->mainfile = ""; this->create_context(); this->mainModule = v8::Object::New(); this->prepare(uwsgi.environ); } v8::Persistent getContext() { return this->context; } private: const char *instanceType() { return "uWSGI"; } const char *executableName() { return uwsgi.binary_path; } }; static v8::Handle < v8::Value > uwsgi_v8_commonjs_require(const v8::Arguments & args) { if (args.Length() > 0) { try { v8::String::Utf8Value module_name(args[0]->ToString()); return APP_PTR->require(std::string(*module_name), ""); } catch (std::string e) { uwsgi_log("%s\n", e.c_str()); } } return v8::Undefined(); } TeaJS_uWSGI app; #else static v8::Handle < v8::Value > uwsgi_v8_commonjs_require(const v8::Arguments &); static v8::Handle < v8::Value > uwsgi_v8_commonjs_require_do(char *); #endif extern struct uwsgi_v8 uv8; extern struct uwsgi_server uwsgi; v8::Persistent uwsgi_v8_setup_context() { v8::HandleScope handle_scope; #ifdef UWSGI_V8_TEAJS try { app.init(); app.getContext()->Global()->Set(v8::String::New("require"), v8::FunctionTemplate::New(uwsgi_v8_commonjs_require)->GetFunction()); return app.getContext(); } catch (std::string e) { uwsgi_log("%s\n", e.c_str()); exit(1); } } #else // create a new context v8::Persistent context = v8::Context::New(); context->Enter(); v8::Handle global = context->Global(); v8::Handle < v8::Object > system = v8::Object::New(); v8::Handle < v8::Array > args = v8::Array::New(); int i; for (i = 0; i < uwsgi.argc; i++) { args->Set(v8::Integer::New(i), v8::String::New(uwsgi.argv[i])); } system->Set(v8::String::New("args"), args); v8::Handle < v8::Object > env = v8::Object::New(); system->Set(v8::String::New("env"), env); global->Set(v8::String::New("require"), v8::FunctionTemplate::New(uwsgi_v8_commonjs_require)->GetFunction()); global->Set(v8::String::New("system"), system); return context; } /* uWSGI native "require" support */ static v8::Handle < v8::Value > uwsgi_v8_commonjs_require_do(char *filename) { size_t len = 0; char *code = uwsgi_open_and_read(filename, &len, 1, NULL); // we re-create every time an "exports" object to emulate a local object v8::Local < v8::Object > exports = v8::Object::New(); v8::Context::GetCurrent()->Global()->Set(v8::String::New("exports"), exports); // we do not use TryCatch as we directly use stderr and simply exit with error code 1 v8::Handle < v8::Script > script = v8::Script::Compile(v8::String::New(code), v8::String::New(filename)); free(code); if (script.IsEmpty()) { exit(1); } v8::Handle < v8::Value > result = script->Run(); if (result.IsEmpty()) { return v8::Undefined(); } return exports; } static v8::Handle < v8::Value > uwsgi_v8_commonjs_require(const v8::Arguments & args) { if (args.Length() > 0) { v8::String::Utf8Value module_name(args[0]->ToString()); // ok lets start searching the module if (uwsgi_is_file(*module_name)) { return uwsgi_v8_commonjs_require_do(*module_name); } // try appending .js extension if (!uwsgi_endswith(*module_name, (char *) ".js")) { char *tmp_filename = uwsgi_concat2(*module_name, (char *) ".js"); if (uwsgi_is_file(tmp_filename)) { v8::Handle < v8::Value > ret = uwsgi_v8_commonjs_require_do(tmp_filename); free(tmp_filename); return ret; } free(tmp_filename); } // let's start searching in the modules search path struct uwsgi_string_list *usl = uv8.module_paths; while (usl) { char *tmp_filename = uwsgi_concat3(usl->value, (char *) "/", *module_name); if (uwsgi_is_file(tmp_filename)) { v8::Handle < v8::Value > ret = uwsgi_v8_commonjs_require_do(tmp_filename); free(tmp_filename); return ret; } free(tmp_filename); if (!uwsgi_endswith(*module_name, (char *) ".js")) { tmp_filename = uwsgi_concat4(usl->value, (char *) "/", *module_name, (char *) ".js"); if (uwsgi_is_file(tmp_filename)) { v8::Handle < v8::Value > ret = uwsgi_v8_commonjs_require_do(tmp_filename); free(tmp_filename); return ret; } free(tmp_filename); } usl = usl->next; } } return v8::Undefined(); } #endif uwsgi-2.0.29/plugins/v8/v8_jsgi.cc000066400000000000000000000156151477626554400166740ustar00rootroot00000000000000#include "v8_uwsgi.h" extern struct uwsgi_v8 uv8; extern struct uwsgi_server uwsgi; static v8::Handle uwsgi_v8_jsgi_body_chunk(const v8::Arguments& args) { if (args.Length() > 1) { v8::String::Utf8Value chunk(args[0]->ToString()); struct wsgi_request *wsgi_req = current_wsgi_req(); if (uwsgi_response_write_body_do(wsgi_req, *chunk, args[0]->ToString()->Length())) { return v8::ThrowException(v8::Exception::Error(v8::String::New("unable to send JSGI body"))); } } return v8::Undefined(); } static void uwsgi_v8_jsgi_fill_request(struct wsgi_request *wsgi_req, v8::Handle o) { o->Set(v8::String::New("method"), v8::String::New(wsgi_req->method, wsgi_req->method_len)); o->Set(v8::String::New("scriptName"), v8::String::New(wsgi_req->script_name, wsgi_req->script_name_len)); o->Set(v8::String::New("pathInfo"), v8::String::New(wsgi_req->path_info, wsgi_req->path_info_len)); o->Set(v8::String::New("queryString"), v8::String::New(wsgi_req->query_string, wsgi_req->query_string_len)); o->Set(v8::String::New("host"), v8::String::New(wsgi_req->host, wsgi_req->host_len)); if (wsgi_req->scheme_len) { o->Set(v8::String::New("scheme"), v8::String::New(wsgi_req->scheme, wsgi_req->scheme_len)); } else { o->Set(v8::String::New("scheme"), v8::String::New("http")); } o->Set(v8::String::New("remoteAddr"), v8::String::New(wsgi_req->remote_addr, wsgi_req->remote_addr_len)); if (wsgi_req->remote_user_len) { o->Set(v8::String::New("remoteUser"), v8::String::New(wsgi_req->remote_user, wsgi_req->remote_user_len)); } o->Set(v8::String::New("serverSoftware"), v8::String::New("uWSGI " UWSGI_VERSION)); v8::Handle jsgi = v8::Object::New(); if (uwsgi.threads > 1) { jsgi->ToObject()->Set(v8::String::New("multithread"), v8::True()); } else { jsgi->ToObject()->Set(v8::String::New("multithread"), v8::False()); } if (uwsgi.numproc > 1) { jsgi->ToObject()->Set(v8::String::New("multiprocess"), v8::True()); } else { jsgi->ToObject()->Set(v8::String::New("multiprocess"), v8::False()); } o->Set(v8::String::New("jsgi"), jsgi); } extern "C" int uwsgi_v8_request(struct wsgi_request *wsgi_req) { char status_str[11]; uint32_t i,l; v8::Handle status, headers, body; v8::Local props; v8::Local key, value; v8::Handle forEach; /* Standard JSGI 3.0 request */ if (!wsgi_req->uh->pktsize) { uwsgi_log( "Empty JSGI request. skip.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } int core_id = wsgi_req->async_id; uv8.isolates[core_id]->Enter(); uv8.contexts[core_id]->Enter(); v8::HandleScope handle_scope; v8::Handle argj[1]; argj[0] = v8::Object::New(); uwsgi_v8_jsgi_fill_request(wsgi_req, argj[0]->ToObject()); v8::Handle result = uv8.jsgi_func[core_id]->Call(uv8.contexts[core_id]->Global(), 1, argj); if (result.IsEmpty()) goto end; if (!result->IsObject()) goto end; status = result->ToObject()->Get(v8::String::New("status")); if (status.IsEmpty() || !status->IsNumber()) { uwsgi_log("invalid JSGI response status\n"); exit(1); } headers = result->ToObject()->Get(v8::String::New("headers")); if (headers.IsEmpty() || !headers->IsObject()) { uwsgi_log("invalid JSGI response headers\n"); exit(1); } body = result->ToObject()->Get(v8::String::New("body")); if (body.IsEmpty() || !body->IsObject()) { uwsgi_log("invalid JSGI response body\n"); exit(1); } if (uwsgi_num2str2(status->Uint32Value(), status_str) != 3) { goto end; } if (uwsgi_response_prepare_headers(wsgi_req, status_str, 3)) goto end; props = headers->ToObject()->GetPropertyNames(); l = props->Length(); for(i=0;iGet(i); value = headers->ToObject()->Get(key); v8::String::Utf8Value c_key(key->ToString()); if (value->IsArray()) { uint32_t opt_l = value->ToObject()->Get(v8::String::New("length"))->ToObject()->Uint32Value(); uint32_t j; for(j=0;jToObject()->Get(j)->ToString()); if (uwsgi_response_add_header(wsgi_req, *c_key, strlen(*c_key), *c_value, strlen(*c_value))) goto end; } } else { v8::String::Utf8Value c_value(value->ToString()); if (uwsgi_response_add_header(wsgi_req, *c_key, strlen(*c_key), *c_value, strlen(*c_value))) goto end; } } // call forEach forEach = v8::Handle::Cast(body->ToObject()->Get(v8::String::New("forEach"))); argj[0] = uv8.jsgi_writer_func[core_id]; forEach->Call(body->ToObject(), 1, argj); end: while(!v8::V8::IdleNotification()) {}; return UWSGI_OK; } v8::Persistent uwsgi_v8_load_jsgi(int core_id, char *filename) { uv8.isolates[core_id]->Enter(); uv8.contexts[core_id]->Enter(); v8::HandleScope handle_scope; size_t len = 0; char *code = uwsgi_open_and_read(filename, &len, 1, NULL); // we re-create every time an "exports" object to emulate a local object v8::Local exports = v8::Object::New(); v8::Context::GetCurrent()->Global()->Set(v8::String::New("exports"), exports); // we do not use TryCatch as we directly use stderr and simply exit with error code 1 v8::Handle script = v8::Script::Compile( v8::String::New(code), v8::String::New(filename) ); free(code); if (script.IsEmpty()) { exit(1); } v8::Handle result = script->Run(); if (result.IsEmpty()) { exit(1); } uv8.jsgi_writer_func[core_id] = v8::Persistent::New(v8::FunctionTemplate::New(uwsgi_v8_jsgi_body_chunk)->GetFunction()); v8::Handle app = exports->Get(v8::String::New("app")); if (!app.IsEmpty() && !app->IsNull() && !app->IsUndefined()) { if (app->ToObject()->IsFunction()) { if (!uv8.jsgi_announced) { uwsgi_log("JSGI 3.0 application loaded from \"exports.app\" in %s\n", filename); uv8.jsgi_announced = -1; } return v8::Persistent::New(v8::Handle::Cast(app)); } } if (!result->IsNull() && !result->IsUndefined() && result->ToObject()->IsFunction()) { if (!uv8.jsgi_announced) { uwsgi_log("JSGI 3.0 application loaded from return value of %s\n", filename); uv8.jsgi_announced = -1; } return v8::Persistent::New(v8::Handle::Cast(result)); } uwsgi_log("unable to find JSGI 3.0 entry point function\n"); exit(1); } uwsgi-2.0.29/plugins/v8/v8_uwsgi.cc000066400000000000000000000247611477626554400171000ustar00rootroot00000000000000#include "v8_uwsgi.h" struct uwsgi_v8 uv8; extern struct uwsgi_server uwsgi; extern struct uwsgi_plugin v8_plugin; struct uwsgi_option uwsgi_v8_options[] = { {(char *)"v8-load", required_argument, 0, (char *)"load a javascript file", uwsgi_opt_add_string_list, &uv8.load, 0}, {(char *)"v8-preemptive", required_argument, 0, (char *)"put v8 in preemptive move (single isolate) with the specified frequency", uwsgi_opt_set_int, &uv8.preemptive, 0}, {(char *)"v8-gc-freq", required_argument, 0, (char *)"set the v8 garbage collection frequency", uwsgi_opt_set_64bit, &uv8.gc_freq, 0}, {(char *)"v8-module-path", required_argument, 0, (char *)"set the v8 modules search path", uwsgi_opt_add_string_list, &uv8.module_paths, 0}, {(char *)"v8-jsgi", required_argument, 0, (char *)"load the specified JSGI 3.0 application", uwsgi_opt_set_str, &uv8.jsgi, 0}, {0, 0, 0, 0}, }; static v8::Handle uwsgi_v8_api_register_signal(const v8::Arguments& args) { if (args.Length() > 2) { uint8_t uwsgi_signal = args[0]->Uint32Value(); v8::String::Utf8Value signal_kind(args[1]->ToString()); v8::Persistent func = v8::Persistent::New(v8::Handle::Cast(args[2])); int core_id = (long) pthread_getspecific(uv8.current_core); struct uwsgi_v8_signal_table *uvst = &uv8.sigtable[uwsgi_signal]; int need_register = 1; if (uvst->registered == 1) { need_register = 0; } uvst->func[core_id] = func; if (!need_register) { return v8::True(); } if (uwsgi_register_signal(uwsgi_signal, *signal_kind, uvst, v8_plugin.modifier1)) { uwsgi_log("[uwsgi-v8] unable to register signal %d\n", uwsgi_signal); return v8::Undefined(); } uvst->registered = 1 ; return v8::True(); } return v8::Undefined(); } static v8::Handle uwsgi_v8_api_register_rpc(const v8::Arguments& args) { if (args.Length() > 1) { v8::String::Utf8Value name(args[0]->ToString()); uint8_t j_argc = 0; if (args.Length() > 2) { j_argc = args[2]->Uint32Value(); } v8::Persistent func = v8::Persistent::New(v8::Handle::Cast(args[1])); int core_id = (long) pthread_getspecific(uv8.current_core); // get the rpc slot int i; int found = 0; struct uwsgi_v8_rpc_table *uvrt = NULL; for(i=0;i<(int)uwsgi.rpc_max;i++) { uvrt = &uv8.rpctable[i]; if (uvrt->name == NULL) { found = 1; break; } // skip already registered funcs else if (!strcmp(uvrt->name, *name)) { uvrt->func[core_id] = func; return v8::True(); } } if (!found || !uvrt) { uwsgi_log("[uwsgi-v8] unable to register RPC function \"%s\"\n", *name); return v8::Undefined(); } uvrt->name = uwsgi_str(*name); uvrt->func[core_id] = func; // we can safely call register_rpc here as it will check for already registered funcs if (uwsgi_register_rpc(*name, &v8_plugin, j_argc, uvrt)) { uwsgi_log("[uwsgi-v8] unable to register RPC function \"%s\"\n", *name); return v8::Undefined(); } return v8::True(); } return v8::Undefined(); } static void uwsgi_v8_load_file(int core_id, char *filename) { uv8.isolates[core_id]->Enter(); uv8.contexts[core_id]->Enter(); v8::HandleScope handle_scope; size_t len = 0; char *code = uwsgi_open_and_read(filename, &len, 1, NULL); // we do not use TryCatch as we directly use stderr and simply exit with error code 1 v8::Handle script = v8::Script::Compile( v8::String::New(code), v8::String::New(filename) ); free(code); if (script.IsEmpty()) { exit(1); } v8::Handle result = script->Run(); if (result.IsEmpty()) { exit(1); } } static v8::Handle uwsgi_v8_api_log(const v8::Arguments& args) { if (args.Length() > 0) { v8::String::Utf8Value str(args[0]->ToString()); size_t slen = strlen(*str); if ((*str)[slen-1] == '\n') { uwsgi_log("%s", *str); } else { uwsgi_log("%s\n", *str); } } return v8::Undefined(); } v8::Persistent uwsgi_v8_setup_context(); static v8::Persistent uwsgi_v8_new_isolate(int core_id) { // create a new isolate v8::Isolate *isolate = v8::Isolate::New(); // set as the current isolate isolate->Enter(); uv8.isolates[core_id] = v8::Isolate::GetCurrent(); v8::Persistent context = uwsgi_v8_setup_context(); context->Enter(); v8::HandleScope handle_scope; // uWSGI api v8::Handle uwsgi_api = v8::Object::New(); uwsgi_api->Set(v8::String::New("log"), v8::FunctionTemplate::New(uwsgi_v8_api_log)->GetFunction()); uwsgi_api->Set(v8::String::New("register_rpc"), v8::FunctionTemplate::New(uwsgi_v8_api_register_rpc)->GetFunction()); uwsgi_api->Set(v8::String::New("register_signal"), v8::FunctionTemplate::New(uwsgi_v8_api_register_signal)->GetFunction()); context->Global()->Set(v8::String::New("uwsgi"), uwsgi_api); return context; } extern "C" int uwsgi_v8_init(){ int i; uwsgi_log("Initializing V8 %s environment... (%d Isolates)\n", v8::V8::GetVersion(), uwsgi.cores); uv8.isolates = (v8::Isolate **) uwsgi_malloc( sizeof(v8::Isolate *) * uwsgi.cores ); uv8.contexts = (v8::Persistent *) uwsgi_malloc( sizeof(v8::Persistent) * uwsgi.cores ); // allocates rpc and signal tables uv8.rpctable = (struct uwsgi_v8_rpc_table *) uwsgi_calloc(sizeof(struct uwsgi_v8_rpc_table) * uwsgi.rpc_max); for(i=0;i<(int)uwsgi.rpc_max;i++) { uv8.rpctable[i].func = (v8::Persistent*) uwsgi_calloc(sizeof(v8::Persistent) * uwsgi.cores); } uv8.sigtable = (struct uwsgi_v8_signal_table *) uwsgi_calloc(sizeof(struct uwsgi_v8_signal_table) * 256); for(i=0;i<256;i++) { uv8.sigtable[i].func = (v8::Persistent*) uwsgi_calloc(sizeof(v8::Persistent) * uwsgi.cores); } uv8.jsgi_func = (v8::Persistent *) uwsgi_calloc( sizeof(v8::Persistent) * uwsgi.cores ); uv8.jsgi_writer_func = (v8::Persistent *) uwsgi_calloc( sizeof(v8::Persistent) * uwsgi.cores ); pthread_key_create(&uv8.current_core, NULL); pthread_setspecific(uv8.current_core, (void *) 0); uv8.contexts[0] = uwsgi_v8_new_isolate(0); return 0; } static void uwsgi_v8_apps_do(int core_id) { struct uwsgi_string_list *usl = uv8.load; while(usl) { uwsgi_v8_load_file(core_id, usl->value); usl = usl->next; } if (uv8.jsgi) { uv8.jsgi_func[core_id] = uwsgi_v8_load_jsgi(core_id, uv8.jsgi); } } extern "C" void uwsgi_v8_apps() { uwsgi_v8_apps_do(0); } extern "C" void uwsgi_v8_configurator(char *filename, char *magic_table[]) { v8::HandleScope handle_scope; uwsgi_log_initial("[uWSGI] getting javascript (V8) configuration from %s\n", filename); size_t len = 0; char *code = uwsgi_open_and_read(filename, &len, 1, NULL); v8::Handle context = v8::Context::New(); v8::Context::Scope context_scope(context); // we do not use TryCatch as we directly use stderr and simply exit with error code 1 v8::Handle script = v8::Script::Compile( v8::String::New(code), v8::String::New(filename) ); if (script.IsEmpty()) { exit(1); } free(code); v8::Handle result = script->Run(); if (result.IsEmpty()) { exit(1); } if (!result->IsArray() && !result->IsObject()) { uwsgi_log("javascript return value must be an object or an array !!!\n"); exit(1); } uint32_t i; const v8::Local props = result->ToObject()->GetPropertyNames(); const uint32_t l = props->Length(); for(i=0;i key = props->Get(i); const v8::Local value = result->ToObject()->Get(key); v8::String::Utf8Value c_key(key->ToString()); if (value->IsArray()) { uint32_t opt_l = value->ToObject()->Get(v8::String::New("length"))->ToObject()->Uint32Value(); uint32_t j; for(j=0;jToObject()->Get(j)->ToString()); add_exported_option(uwsgi_str(*c_key), uwsgi_str(*c_value), 0); } } else { v8::String::Utf8Value c_value(value->ToString()); add_exported_option(uwsgi_str(*c_key), uwsgi_str(*c_value), 0); } } } extern "C" uint64_t uwsgi_v8_rpc(void * func, uint8_t argc, char **argv, uint16_t argvs[], char **buffer) { int core_id = (long) pthread_getspecific(uv8.current_core); uv8.isolates[core_id]->Enter(); uv8.contexts[core_id]->Enter(); v8::HandleScope handle_scope; v8::Handle argj[256]; struct uwsgi_v8_rpc_table *uvrt = (struct uwsgi_v8_rpc_table *) func; uint8_t i; for(i=0;i l_func = uvrt->func[core_id]; v8::Handle result = l_func->Call(uv8.contexts[core_id]->Global(), argc, argj); if (result.IsEmpty()) { return 0; } v8::Handle robj = result->ToString(); v8::String::Utf8Value r_value(robj); if (!*robj) { return 0; } uint64_t rlen = (uint64_t) robj->Length(); if (rlen > 0) { *buffer = (char *)uwsgi_malloc(rlen); memcpy(*buffer, *r_value, rlen); } // call GC every time, could be overkill, we should allow to tune that choice while(!v8::V8::IdleNotification()) {}; return rlen; } extern "C" void uwsgi_v8_init_thread(int core_id) { pthread_setspecific(uv8.current_core, (void *) ((long)core_id)); uv8.contexts[core_id] = uwsgi_v8_new_isolate(core_id); uwsgi_v8_apps_do(core_id); } extern "C" void uwsgi_v8_enable_threads() { } extern "C" int uwsgi_v8_signal_handler(uint8_t sig, void *handler) { int ret = 0; int core_id = (long) pthread_getspecific(uv8.current_core); uv8.isolates[core_id]->Enter(); uv8.contexts[core_id]->Enter(); v8::HandleScope handle_scope; v8::Handle argj[1]; argj[0] = v8::Number::New(sig); struct uwsgi_v8_signal_table *uvst = (struct uwsgi_v8_signal_table *) handler; v8::Persistent l_func = uvst->func[core_id]; v8::Handle result = l_func->Call(uv8.contexts[core_id]->Global(), 1, argj); if (result.IsEmpty()) ret = -1; while(!v8::V8::IdleNotification()) {}; return ret; } extern "C" int uwsgi_v8_mule(char *opt) { if (uwsgi_endswith(opt, (char *)".js")) { uwsgi_v8_load_file(0, opt); return 1; } return 0; } uwsgi-2.0.29/plugins/v8/v8_uwsgi.h000066400000000000000000000016511477626554400167330ustar00rootroot00000000000000#include #include // as we have isolates in multithread modes, we need to maintain // special tables for the handlers (mules and spooler just run on the core 0) struct uwsgi_v8_signal_table { v8::Persistent *func; uint8_t registered; }; struct uwsgi_v8_rpc_table { char *name; v8::Persistent *func; }; struct uwsgi_v8 { v8::Persistent *contexts; v8::Isolate **isolates; char *jsgi; v8::Persistent *jsgi_func; v8::Persistent *jsgi_writer_func; int jsgi_announced; struct uwsgi_string_list *load; struct uwsgi_v8_signal_table *sigtable; struct uwsgi_v8_rpc_table *rpctable; pthread_key_t current_core; int preemptive; uint64_t gc_freq; struct uwsgi_string_list *module_paths; }; v8::Persistent uwsgi_v8_load_jsgi(int, char *); uwsgi-2.0.29/plugins/webdav/000077500000000000000000000000001477626554400157175ustar00rootroot00000000000000uwsgi-2.0.29/plugins/webdav/uwsgiplugin.py000066400000000000000000000003531477626554400206470ustar00rootroot00000000000000import os NAME = 'webdav' CFLAGS = ['-Wno-deprecated-declarations'] CFLAGS += os.popen('xml2-config --cflags').read().rstrip().split() LDFLAGS = [] LIBS = os.popen('xml2-config --libs').read().rstrip().split() GCC_LIST = ['webdav'] uwsgi-2.0.29/plugins/webdav/webdav.c000066400000000000000000001436111477626554400173410ustar00rootroot00000000000000#include #include #include #if defined(__linux__) || defined(__APPLE__) #include #endif /* rfc4918 implementation (WebDAV) requires libxml2 --webdav-mount [mountpoint=] or --webdav-use-docroot[=VAR] steps to build a path: 1) get the mountpoint 2) concat the base with the path_info 3) realpath() on it step 3 could be a non-existent file (for example on MKCOL or PUT). In such a case: 4) find the last / in the path_info, and try realpath() on it, if success the resource can be created ALL MUST BE BOTH THREAD SAFE AND ASYNC SAFE !!! Locking requires a cache (local or remote) when a lock request is made, an item is added to the cache (directly using cache_set to avoid duplicates). The item key is the full url of the request (host + path_info, in such a way we have virtualhosting for locks). The value is a uuid. if a lock_token is passed the url is checked in the cache and uuid compared - Resource properties are stored as filesystem xattr (warning, not all operating system support them) - */ extern struct uwsgi_server uwsgi; struct uwsgi_plugin webdav_plugin; struct uwsgi_webdav { struct uwsgi_string_list *mountpoints; struct uwsgi_string_list *css; struct uwsgi_string_list *javascript; char *class_directory; char *div; char *lock_cache; char *principal_base; struct uwsgi_string_list *add_option; struct uwsgi_string_list *add_prop; struct uwsgi_string_list *add_collection_prop; struct uwsgi_string_list *add_object_prop; struct uwsgi_string_list *add_prop_href; struct uwsgi_string_list *add_collection_prop_href; struct uwsgi_string_list *add_object_prop_href; struct uwsgi_string_list *add_prop_comp; struct uwsgi_string_list *add_collection_prop_comp; struct uwsgi_string_list *add_object_prop_comp; struct uwsgi_string_list *add_rtype_prop; struct uwsgi_string_list *add_rtype_collection_prop; struct uwsgi_string_list *add_rtype_object_prop; struct uwsgi_string_list *skip_prop; } udav; struct uwsgi_option uwsgi_webdav_options[] = { { "webdav-mount", required_argument, 0, "map a filesystem directory as a webdav store", uwsgi_opt_add_string_list, &udav.mountpoints, UWSGI_OPT_MIME}, { "webdav-css", required_argument, 0, "add a css url for automatic webdav directory listing", uwsgi_opt_add_string_list, &udav.css, UWSGI_OPT_MIME}, { "webdav-javascript", required_argument, 0, "add a javascript url for automatic webdav directory listing", uwsgi_opt_add_string_list, &udav.javascript, UWSGI_OPT_MIME}, { "webdav-js", required_argument, 0, "add a javascript url for automatic webdav directory listing", uwsgi_opt_add_string_list, &udav.javascript, UWSGI_OPT_MIME}, { "webdav-class-directory", required_argument, 0, "set the css directory class for automatic webdav directory listing", uwsgi_opt_set_str, &udav.class_directory, UWSGI_OPT_MIME}, { "webdav-div", required_argument, 0, "set the div id for automatic webdav directory listing", uwsgi_opt_set_str, &udav.div, UWSGI_OPT_MIME}, { "webdav-lock-cache", required_argument, 0, "set the cache to use for webdav locking", uwsgi_opt_set_str, &udav.lock_cache, UWSGI_OPT_MIME}, { "webdav-principal-base", required_argument, 0, "enable WebDAV Current Principal Extension using the specified base", uwsgi_opt_set_str, &udav.principal_base, UWSGI_OPT_MIME}, { "webdav-add-option", required_argument, 0, "add a WebDAV standard to the OPTIONS response", uwsgi_opt_add_string_list, &udav.add_option, UWSGI_OPT_MIME}, { "webdav-add-prop", required_argument, 0, "add a WebDAV property to all resources", uwsgi_opt_add_string_list, &udav.add_prop, UWSGI_OPT_MIME}, { "webdav-add-collection-prop", required_argument, 0, "add a WebDAV property to all collections", uwsgi_opt_add_string_list, &udav.add_collection_prop, UWSGI_OPT_MIME}, { "webdav-add-object-prop", required_argument, 0, "add a WebDAV property to all objects", uwsgi_opt_add_string_list, &udav.add_object_prop, UWSGI_OPT_MIME}, { "webdav-add-prop-href", required_argument, 0, "add a WebDAV property to all resources (href value)", uwsgi_opt_add_string_list, &udav.add_prop_href, UWSGI_OPT_MIME}, { "webdav-add-collection-prop-href", required_argument, 0, "add a WebDAV property to all collections (href value)", uwsgi_opt_add_string_list, &udav.add_collection_prop_href, UWSGI_OPT_MIME}, { "webdav-add-object-prop-href", required_argument, 0, "add a WebDAV property to all objects (href value)", uwsgi_opt_add_string_list, &udav.add_object_prop_href, UWSGI_OPT_MIME}, { "webdav-add-prop-comp", required_argument, 0, "add a WebDAV property to all resources (xml value)", uwsgi_opt_add_string_list, &udav.add_prop_comp, UWSGI_OPT_MIME}, { "webdav-add-collection-prop-comp", required_argument, 0, "add a WebDAV property to all collections (xml value)", uwsgi_opt_add_string_list, &udav.add_collection_prop_comp, UWSGI_OPT_MIME}, { "webdav-add-object-prop-comp", required_argument, 0, "add a WebDAV property to all objects (xml value)", uwsgi_opt_add_string_list, &udav.add_object_prop_comp, UWSGI_OPT_MIME}, { "webdav-add-rtype-prop", required_argument, 0, "add a WebDAV resourcetype property to all resources", uwsgi_opt_add_string_list, &udav.add_rtype_prop, UWSGI_OPT_MIME}, { "webdav-add-rtype-collection-prop", required_argument, 0, "add a WebDAV resourcetype property to all collections", uwsgi_opt_add_string_list, &udav.add_rtype_collection_prop, UWSGI_OPT_MIME}, { "webdav-add-rtype-object-prop", required_argument, 0, "add a WebDAV resourcetype property to all objects", uwsgi_opt_add_string_list, &udav.add_rtype_object_prop, UWSGI_OPT_MIME}, { "webdav-skip-prop", required_argument, 0, "do not add the specified prop if available in resource xattr", uwsgi_opt_add_string_list, &udav.skip_prop, UWSGI_OPT_MIME}, { 0, 0, 0, 0, 0, 0, 0 }, }; static int uwsgi_webdav_prop_requested(xmlNode *req_prop, char *ns, char *name) { if (!req_prop) return 1; xmlNode *node; for (node = req_prop->children; node; node = node->next) { if (node->type == XML_ELEMENT_NODE) { if (ns) { if (node->ns && !strcmp((char *) node->ns->href, ns)) { if (!strcmp((char *) node->name, name)) return 1; } } else { if (!strcmp((char *) node->name, name)) return 1; } } } return 0; } static void uwsgi_webdav_add_a_prop(xmlNode *node, char *opt, xmlNode *req_prop, int type, char *force_name) { char *first_space = strchr(opt, ' '); if (!first_space) return; *first_space = 0; char *second_space = strchr(first_space + 1, ' '); xmlNode *new_node = NULL; char *ns = opt; if (!force_name) force_name = first_space + 1; else { ns = "DAV:"; } if (second_space) { *second_space = 0; if (!uwsgi_webdav_prop_requested(req_prop, ns, force_name)) { *first_space = ' '; *second_space = ' '; return; } // href if (type == 1) { new_node = xmlNewChild(node, NULL, BAD_CAST first_space + 1, NULL); xmlNewTextChild(new_node, NULL, BAD_CAST "href", BAD_CAST second_space + 1); } // comp else if (type == 2) { new_node = xmlNewChild(node, NULL, BAD_CAST first_space + 1, NULL); char *comps = uwsgi_str(second_space + 1); char *p, *ctx = NULL; uwsgi_foreach_token(comps, ",", p, ctx) { xmlNode *comp = xmlNewChild(new_node, NULL, BAD_CAST "comp", NULL); xmlNewProp(comp, BAD_CAST "name", BAD_CAST p); } free(comps); } else { if (!uwsgi_webdav_prop_requested(req_prop, ns, first_space + 1)) { *first_space = ' '; *second_space = ' '; return; } new_node = xmlNewTextChild(node, NULL, BAD_CAST first_space + 1, BAD_CAST second_space + 1); } *second_space = ' '; } else { if (!uwsgi_webdav_prop_requested(req_prop, ns, force_name)) { *first_space = ' '; return; } new_node = xmlNewChild(node, NULL, BAD_CAST first_space + 1, NULL); } xmlNsPtr x_ns = xmlNewNs(new_node, BAD_CAST opt, NULL); xmlSetNs(new_node, x_ns); *first_space = ' '; } static void uwsgi_webdav_foreach_prop(struct uwsgi_string_list *usl, xmlNode *req_prop, xmlNode *node, int type, char *force_name) { if (!usl) return; while(usl) { uwsgi_webdav_add_a_prop(node, usl->value, req_prop, type, force_name); usl = usl->next; } } /* OPTIONS: if it is a valid webdav resource add Dav: to the response header */ static int uwsgi_wevdav_manage_options(struct wsgi_request *wsgi_req) { uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6); if (udav.add_option) { struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); if (uwsgi_buffer_append(ub, "1, 2, 3", 7)) goto end; struct uwsgi_string_list *usl = udav.add_option; while(usl) { if (uwsgi_buffer_append(ub, ", ", 2)) goto end; if (uwsgi_buffer_append(ub, usl->value, usl->len)) goto end; usl = usl->next; } uwsgi_response_add_header(wsgi_req, "Dav", 3, ub->buf, ub->pos); end: uwsgi_buffer_destroy(ub); } else { uwsgi_response_add_header(wsgi_req, "Dav", 3, "1, 2, 3", 7); } return UWSGI_OK; } static char *uwsgi_webdav_new_date(uint64_t t) { // 30+1 char d[31]; int len = uwsgi_http_date((time_t) t, d); if (!len) { return NULL; } return uwsgi_concat2n(d, len, "", 0); } static int uwsgi_webdav_add_props(struct wsgi_request *wsgi_req, xmlNode *req_prop, xmlNode * multistatus, xmlNsPtr dav_ns, char *uri, char *filename, int with_values) { struct stat st; if (stat(filename, &st)) { uwsgi_error("uwsgi_webdav_add_props()/stat()"); return -1; } int is_collection = 0; xmlNode *response = xmlNewChild(multistatus, dav_ns, BAD_CAST "response", NULL); uint16_t uri_len = strlen(uri) ; char *encoded_uri = uwsgi_malloc( (uri_len * 3) + 1); http_url_encode(uri, &uri_len, encoded_uri); encoded_uri[uri_len] = 0; xmlNewChild(response, dav_ns, BAD_CAST "href", BAD_CAST encoded_uri); free(encoded_uri); xmlNode *r_propstat = xmlNewChild(response, dav_ns, BAD_CAST "propstat", NULL); char *r_status = uwsgi_concat2n(wsgi_req->protocol, wsgi_req->protocol_len, " 200 OK", 7); xmlNewChild(r_propstat, dav_ns, BAD_CAST "status", BAD_CAST r_status); free(r_status); xmlNode *r_prop = xmlNewChild(r_propstat, dav_ns, BAD_CAST "prop", NULL); if (with_values) { if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "displayname")) { char *base_uri = uwsgi_get_last_char(uri, '/'); if (base_uri) { xmlNewChild(r_prop, dav_ns, BAD_CAST "displayname", BAD_CAST base_uri+1); } else { xmlNewChild(r_prop, dav_ns, BAD_CAST "displayname", BAD_CAST uri); } } if (S_ISDIR(st.st_mode)) is_collection = 1; xmlNode *r_type = NULL; if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "resourcetype")) { r_type = xmlNewChild(r_prop, dav_ns, BAD_CAST "resourcetype", NULL); if (is_collection) { xmlNewChild(r_type, dav_ns, BAD_CAST "collection", NULL); is_collection = 1; } } if (!is_collection) { if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "getcontentlength")) { char *r_contentlength = uwsgi_num2str(st.st_size); xmlNewChild(r_prop, dav_ns, BAD_CAST "getcontentlength", BAD_CAST r_contentlength); free(r_contentlength); } if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "getcontenttype")) { size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(filename, strlen(filename), &mime_type_len); if (mime_type) { char *r_ctype = uwsgi_concat2n(mime_type, mime_type_len, "", 0); xmlNewTextChild(r_prop, dav_ns, BAD_CAST "getcontenttype", BAD_CAST r_ctype); free(r_ctype); } } } if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "creationdate")) { // there is no creation date on UNIX/POSIX, ctime is the nearest thing... char *cdate = uwsgi_webdav_new_date(st.st_ctime); if (cdate) { xmlNewTextChild(r_prop, dav_ns, BAD_CAST "creationdate", BAD_CAST cdate); free(cdate); } } if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "getlastmodified")) { char *mdate = uwsgi_webdav_new_date(st.st_mtime); if (mdate) { xmlNewTextChild(r_prop, dav_ns, BAD_CAST "getlastmodified", BAD_CAST mdate); free(mdate); } } if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "getetag")) { char *etag = uwsgi_num2str(st.st_mtime); xmlNewTextChild(r_prop, dav_ns, BAD_CAST "getetag", BAD_CAST etag); free(etag); } if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "executable")) { xmlNewChild(r_prop, dav_ns, BAD_CAST "executable", NULL); } if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "owner")) { xmlNewTextChild(r_prop, dav_ns, BAD_CAST "owner", NULL); } if (wsgi_req->remote_user_len > 0) { if (udav.principal_base) { if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "current-user-principal")) { char *current_user_principal = uwsgi_concat2n(udav.principal_base, strlen(udav.principal_base), wsgi_req->remote_user, wsgi_req->remote_user_len); xmlNode *cup = xmlNewChild(r_prop, dav_ns, BAD_CAST "current-user-principal", NULL); xmlNewTextChild(cup, dav_ns, BAD_CAST "href", BAD_CAST current_user_principal); if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "resourcetype")) { if (!strcmp(current_user_principal, uri)) { xmlNewChild(r_type, dav_ns, BAD_CAST "principal", NULL); } } free(current_user_principal); } } if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "current-user-privilege-set")) { xmlNode *cups = xmlNewChild(r_prop, dav_ns, BAD_CAST "current-user-privilege-set", NULL); xmlNode *privilege = xmlNewChild(cups, dav_ns, BAD_CAST "privilege", NULL); xmlNewChild(privilege, dav_ns, BAD_CAST "all", NULL); xmlNewChild(privilege, dav_ns, BAD_CAST "read", NULL); xmlNewChild(privilege, dav_ns, BAD_CAST "write", NULL); xmlNewChild(privilege, dav_ns, BAD_CAST "write-content", NULL); xmlNewChild(privilege, dav_ns, BAD_CAST "write-properties", NULL); } } if (uwsgi_webdav_prop_requested(req_prop, "DAV:", "supported-report-set")) { xmlNode *report_set = xmlNewChild(r_prop, dav_ns, BAD_CAST "supported-report-set", NULL); xmlNode *supported_report = xmlNewChild(report_set, dav_ns, BAD_CAST "supported-report", NULL); xmlNewChild(supported_report, dav_ns, BAD_CAST "report", BAD_CAST "principal-property-search"); supported_report = xmlNewChild(report_set, dav_ns, BAD_CAST "supported-report", NULL); xmlNewChild(supported_report, dav_ns, BAD_CAST "report", BAD_CAST "sync-collection"); supported_report = xmlNewChild(report_set, dav_ns, BAD_CAST "supported-report", NULL); xmlNewChild(supported_report, dav_ns, BAD_CAST "report", BAD_CAST "expand-property"); supported_report = xmlNewChild(report_set, dav_ns, BAD_CAST "supported-report", NULL); xmlNewChild(supported_report, dav_ns, BAD_CAST "report", BAD_CAST "principal-search-property-set"); } uwsgi_webdav_foreach_prop(udav.add_prop, req_prop, r_prop, 0, NULL ); uwsgi_webdav_foreach_prop(udav.add_prop_href, req_prop, r_prop, 1, NULL); uwsgi_webdav_foreach_prop(udav.add_prop_comp,req_prop, r_prop, 2 , NULL); uwsgi_webdav_foreach_prop(udav.add_rtype_prop,req_prop, r_type, 0, "resourcetype"); if (is_collection) { uwsgi_webdav_foreach_prop(udav.add_rtype_collection_prop,req_prop, r_type, 0, "resourcetype"); uwsgi_webdav_foreach_prop(udav.add_collection_prop,req_prop, r_prop, 0, NULL); uwsgi_webdav_foreach_prop(udav.add_collection_prop_href,req_prop, r_prop, 1, NULL); uwsgi_webdav_foreach_prop(udav.add_collection_prop_comp,req_prop, r_prop, 2, NULL); } else { uwsgi_webdav_foreach_prop(udav.add_rtype_object_prop,req_prop, r_type, 0, "resourcetype"); uwsgi_webdav_foreach_prop(udav.add_object_prop,req_prop, r_prop, 0, NULL); uwsgi_webdav_foreach_prop(udav.add_object_prop_href,req_prop, r_prop, 1, NULL); uwsgi_webdav_foreach_prop(udav.add_object_prop_comp,req_prop, r_prop, 2, NULL); } } else { xmlNewChild(r_prop, dav_ns, BAD_CAST "displayname", NULL); xmlNewChild(r_prop, dav_ns, BAD_CAST "resourcetype", NULL); if (!S_ISDIR(st.st_mode)) { xmlNewChild(r_prop, dav_ns, BAD_CAST "getcontentlength", NULL); xmlNewChild(r_prop, dav_ns, BAD_CAST "getcontenttype", NULL); } xmlNewChild(r_prop, dav_ns, BAD_CAST "creationdate", NULL); xmlNewChild(r_prop, dav_ns, BAD_CAST "getlastmodified", NULL); xmlNewChild(r_prop, dav_ns, BAD_CAST "supported-report-set", NULL); if (wsgi_req->remote_user_len > 0) { xmlNewChild(r_prop, dav_ns, BAD_CAST "current-user-privilege-set", NULL); if (udav.principal_base) { xmlNewChild(r_prop, dav_ns, BAD_CAST "current-user-principal", NULL); } } } #if defined(__linux__) || defined(__APPLE__) // get xattr for user.uwsgi.webdav. #if defined(__linux__) ssize_t rlen = listxattr(filename, NULL, 0); #elif defined(__APPLE__) ssize_t rlen = listxattr(filename, NULL, 0, 0); #endif // do not return -1 as the previous xml is valid !!! if (rlen <= 0) return 0; // use calloc to avoid races char *xattrs = uwsgi_calloc(rlen); #if defined(__linux__) if (listxattr(filename, xattrs, rlen) <= 0) { #elif defined(__APPLE__) if (listxattr(filename, xattrs, rlen, 0) <= 0) { #endif free(xattrs); return 0; } // parse the name list ssize_t i; char *key = NULL; for(i=0;i 0) { // leave space for final 0 char *xvalue = uwsgi_calloc(rlen2 + 1); #if defined(__linux__) if (getxattr(filename, key, xvalue, rlen2) > 0) { #elif defined(__APPLE__) if (getxattr(filename, key, xvalue, rlen2, 0 ,0) > 0) { #endif xattr_item = xmlNewTextChild(r_prop, NULL, BAD_CAST xattr_key, BAD_CAST xvalue); } free(xvalue); } else if (rlen == 0) { xattr_item = xmlNewTextChild(r_prop, NULL, BAD_CAST xattr_key, NULL); } } else { xattr_item = xmlNewTextChild(r_prop, NULL, BAD_CAST xattr_key, NULL); } if (separator && xattr_item) { xattr_ns = xmlNewNs(xattr_item, BAD_CAST (key + 18), NULL); *separator = '|'; xmlSetNs(xattr_item, xattr_ns); } } key = NULL; } else if (key == NULL) { key = &xattrs[i]; } } free(xattrs); #endif return 0; } static size_t uwsgi_webdav_expand_path(struct wsgi_request *wsgi_req, char *item, uint16_t item_len, char *filename) { struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id]; char *docroot = ua->interpreter; size_t docroot_len = strlen(docroot); // merge docroot with path_info char *tmp_filename = uwsgi_concat3n(docroot, docroot_len, "/", 1, item, item_len); // try expanding the path if (!realpath(tmp_filename, filename)) { free(tmp_filename); return 0; } free(tmp_filename); return strlen(filename); } static size_t uwsgi_webdav_expand_fake_path(struct wsgi_request *wsgi_req, char *item, uint16_t item_len, char *filename) { char *last_slash = uwsgi_get_last_charn(item, item_len, '/'); if (!last_slash) return 0; size_t filename_len = uwsgi_webdav_expand_path(wsgi_req, item, last_slash - item, filename); if (!filename_len) return 0; // check for overflow if (filename_len + (item_len - (last_slash - item)) >= PATH_MAX) return 0; memcpy(filename + filename_len, last_slash, (item_len - (last_slash - item))); filename_len += (item_len - (last_slash - item)); filename[(int)filename_len] = 0; return filename_len; } static xmlDoc *uwsgi_webdav_manage_prop(struct wsgi_request *wsgi_req, xmlNode *req_prop, char *filename, size_t filename_len, int with_values) { // default 1 depth int depth = 1; uint16_t http_depth_len = 0; char *http_depth = uwsgi_get_var(wsgi_req, "HTTP_DEPTH", 10, &http_depth_len); if (http_depth) { depth = uwsgi_str_num(http_depth, http_depth_len); } xmlDoc *rdoc = xmlNewDoc(BAD_CAST "1.0"); xmlNode *multistatus = xmlNewNode(NULL, BAD_CAST "multistatus"); xmlDocSetRootElement(rdoc, multistatus); xmlNsPtr dav_ns = xmlNewNs(multistatus, BAD_CAST "DAV:", BAD_CAST "D"); xmlSetNs(multistatus, dav_ns); if (depth == 0) { char *uri = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "", 0); uwsgi_webdav_add_props(wsgi_req, req_prop, multistatus, dav_ns, uri, filename, with_values); free(uri); } else { DIR *collection = opendir(filename); struct dirent de; for (;;) { struct dirent *de_r = NULL; if (readdir_r(collection, &de, &de_r)) { uwsgi_error("uwsgi_wevdav_manage_propfind()/readdir_r()"); break; } if (de_r == NULL) { break; } char *uri = NULL; char *direntry = NULL; if (!strcmp(de.d_name, "..")) { // skip .. continue; } else if (!strcmp(de.d_name, ".")) { uri = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "", 0); direntry = uwsgi_concat2n(filename, filename_len, "", 0); } else if (wsgi_req->path_info[wsgi_req->path_info_len - 1] == '/') { uri = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, de.d_name, strlen(de.d_name)); direntry = uwsgi_concat3n(filename, filename_len, "/", 1, de.d_name, strlen(de.d_name)); } else { uri = uwsgi_concat3n(wsgi_req->path_info, wsgi_req->path_info_len, "/", 1, de.d_name, strlen(de.d_name)); direntry = uwsgi_concat3n(filename, filename_len, "/", 1, de.d_name, strlen(de.d_name)); } uwsgi_webdav_add_props(wsgi_req, req_prop, multistatus, dav_ns, uri, direntry, with_values); free(uri); free(direntry); } closedir(collection); } return rdoc; } static int uwsgi_wevdav_manage_propfind(struct wsgi_request *wsgi_req, xmlDoc * doc) { char filename[PATH_MAX]; size_t filename_len = uwsgi_webdav_expand_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename); if (filename_len == 0) { uwsgi_404(wsgi_req); return UWSGI_OK; } xmlDoc *rdoc = NULL; xmlNode *element = NULL; if (doc) { element = xmlDocGetRootElement(doc); if (!element) return -1; if (!element || strcmp((char *) element->name, "propfind")) return -1; } if (uwsgi_response_prepare_headers(wsgi_req, "207 Multi-Status", 16)) return -1; if (uwsgi_response_add_content_type(wsgi_req, "application/xml; charset=\"utf-8\"", 32)) return -1; if (doc) { // propfind must have a child (scan them until you find a valid one) xmlNode *node; for (node = element->children; node; node = node->next) { if (node->type == XML_ELEMENT_NODE) { if (node->ns && !strcmp((char *) node->ns->href, "DAV:")) { if (!strcmp((char *) node->name, "prop")) { rdoc = uwsgi_webdav_manage_prop(wsgi_req, node, filename, filename_len, 1); break; } if (!strcmp((char *) node->name, "allprop")) { rdoc = uwsgi_webdav_manage_prop(wsgi_req, NULL, filename, filename_len, 1); break; } if (!strcmp((char *) node->name, "propname")) { rdoc = uwsgi_webdav_manage_prop(wsgi_req, node, filename, filename_len, 0); break; } } } } } else { rdoc = uwsgi_webdav_manage_prop(wsgi_req, NULL, filename, filename_len, 1); } if (!rdoc) return UWSGI_OK; xmlChar *xmlbuf; int xlen = 0; xmlDocDumpFormatMemory(rdoc, &xmlbuf, &xlen, 1); uwsgi_response_add_content_length(wsgi_req, xlen); uwsgi_response_write_body_do(wsgi_req, (char *) xmlbuf, xlen); #ifdef UWSGI_DEBUG uwsgi_log("\n%.*s\n", xlen, xmlbuf); #endif xmlFreeDoc(rdoc); xmlFree(xmlbuf); return UWSGI_OK; } static int uwsgi_webdav_prop_set(char *filename, char *attr, char *ns, char *body) { int ret = 0; #if defined(__linux__) || defined(__APPLE__) char *xattr_name = NULL; if (ns) { xattr_name = uwsgi_concat4("user.uwsgi.webdav.", ns, "|", attr); } else { xattr_name = uwsgi_concat2("user.uwsgi.webdav.", attr); } #if defined(__linux__) ret = setxattr(filename, xattr_name, body, strlen(body), 0); #elif defined(__APPLE__) ret = setxattr(filename, xattr_name, body, strlen(body), 0, 0); #endif free(xattr_name); #endif return ret; } static int uwsgi_webdav_prop_del(char *filename, char *attr, char *ns) { int ret = 0; #if defined(__linux__) || defined(__APPLE__) char *xattr_name = NULL; if (ns) { xattr_name = uwsgi_concat4("user.uwsgi.webdav.", ns, "|", attr); } else { xattr_name = uwsgi_concat2("user.uwsgi.webdav.", attr); } #if defined(__linux__) ret = removexattr(filename, xattr_name); #elif defined(__APPLE__) ret = removexattr(filename, xattr_name, 0); #endif free(xattr_name); #endif return ret; } static void uwsgi_webdav_do_prop_update(struct wsgi_request *wsgi_req, xmlNode *prop, xmlNode *response, char *filename, uint8_t action) { xmlNode *node; // search for "prop" for (node = prop->children; node; node = node->next) { if (node->type == XML_ELEMENT_NODE) { xmlNode *propstat = xmlNewChild(response, NULL, BAD_CAST "propstat", NULL); xmlNode *r_prop = xmlNewChild(propstat, NULL, BAD_CAST "prop" , NULL); xmlNode *new_prop = xmlNewChild(r_prop, NULL, node->name, NULL); if (node->ns) { xmlNsPtr xattr_ns = xmlNewNs(new_prop, node->ns->href, NULL); xmlSetNs(new_prop, xattr_ns); } if (action == 0) { if (uwsgi_webdav_prop_set(filename, (char *) node->name, node->ns ? (char *) node->ns->href : NULL, node->children ? (char *) node->children->content : "")) { char *r_status = uwsgi_concat2n(wsgi_req->protocol, wsgi_req->protocol_len, " 403 Forbidden", 14); xmlNewChild(r_prop, NULL, BAD_CAST "status", BAD_CAST r_status); free(r_status); } else { char *r_status = uwsgi_concat2n(wsgi_req->protocol, wsgi_req->protocol_len, " 200 OK", 7); xmlNewChild(r_prop, NULL, BAD_CAST "status", BAD_CAST r_status); free(r_status); } } else if (action == 1) { if (uwsgi_webdav_prop_del(filename, (char *) node->name, node->ns ? (char *) node->ns->href : NULL)) { char *r_status = uwsgi_concat2n(wsgi_req->protocol, wsgi_req->protocol_len, " 403 Forbidden", 14); xmlNewChild(r_prop, NULL, BAD_CAST "status", BAD_CAST r_status); free(r_status); } else { char *r_status = uwsgi_concat2n(wsgi_req->protocol, wsgi_req->protocol_len, " 200 OK", 7); xmlNewChild(r_prop, NULL, BAD_CAST "status", BAD_CAST r_status); free(r_status); } } } } } // action 0 is set, 1 is remove static void uwsgi_webdav_manage_prop_update(struct wsgi_request *wsgi_req, xmlNode *parent, xmlNode *response, char *filename, uint8_t action) { xmlNode *node; // search for "prop" for (node = parent->children; node; node = node->next) { if (node->type == XML_ELEMENT_NODE) { if (node->ns && !strcmp((char *) node->ns->href, "DAV:")) { if (!strcmp((char *) node->name, "prop")) { uwsgi_webdav_do_prop_update(wsgi_req, node, response, filename, action); } } } } } static int uwsgi_wevdav_manage_proppatch(struct wsgi_request *wsgi_req, xmlDoc * doc) { char filename[PATH_MAX]; size_t filename_len = uwsgi_webdav_expand_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename); if (filename_len == 0) { uwsgi_404(wsgi_req); return UWSGI_OK; } xmlNode *element = xmlDocGetRootElement(doc); if (!element) return -1; if (!element || (strcmp((char *) element->name, "propertyupdate"))) return -1; if (uwsgi_response_prepare_headers(wsgi_req, "207 Multi-Status", 16)) return -1; if (uwsgi_response_add_content_type(wsgi_req, "application/xml; charset=\"utf-8\"", 32)) return -1; xmlDoc *rdoc = xmlNewDoc(BAD_CAST "1.0"); xmlNode *multistatus = xmlNewNode(NULL, BAD_CAST "multistatus"); xmlDocSetRootElement(rdoc, multistatus); xmlNsPtr dav_ns = xmlNewNs(multistatus, BAD_CAST "DAV:", BAD_CAST "D"); xmlSetNs(multistatus, dav_ns); xmlNode *response = xmlNewChild(multistatus, dav_ns, BAD_CAST "response", NULL); char *uri = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "", 0); uint16_t uri_len = strlen(uri) ; char *encoded_uri = uwsgi_malloc( (uri_len * 3) + 1); http_url_encode(uri, &uri_len, encoded_uri); encoded_uri[uri_len] = 0; xmlNewChild(response, dav_ns, BAD_CAST "href", BAD_CAST encoded_uri); free(encoded_uri); // propfind can be "set" or "remove" xmlNode *node; for (node = element->children; node; node = node->next) { if (node->type == XML_ELEMENT_NODE) { if (node->ns && !strcmp((char *) node->ns->href, "DAV:")) { if (!strcmp((char *) node->name, "set")) { uwsgi_webdav_manage_prop_update(wsgi_req, node, response, filename, 0); } else if (!strcmp((char *) node->name, "remove")) { uwsgi_webdav_manage_prop_update(wsgi_req, node, response, filename, 1); } } } } if (!rdoc) return UWSGI_OK; xmlChar *xmlbuf; int xlen = 0; xmlDocDumpFormatMemory(rdoc, &xmlbuf, &xlen, 1); uwsgi_response_add_content_length(wsgi_req, xlen); uwsgi_response_write_body_do(wsgi_req, (char *) xmlbuf, xlen); #ifdef UWSGI_DEBUG uwsgi_log("\n%.*s\n", xlen, xmlbuf); #endif xmlFreeDoc(rdoc); xmlFree(xmlbuf); return UWSGI_OK; } static int uwsgi_wevdav_manage_put(struct wsgi_request *wsgi_req) { char filename[PATH_MAX]; size_t filename_len = uwsgi_webdav_expand_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename); // the collection does not exist, search for the last / if (!filename_len) { filename_len = uwsgi_webdav_expand_fake_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename); if (!filename_len) { uwsgi_response_prepare_headers(wsgi_req, "409 Conflict", 12); return UWSGI_OK; } } int fd = open(filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd < 0) { uwsgi_403(wsgi_req); return UWSGI_OK; } if (uwsgi_response_prepare_headers(wsgi_req, "201 Created", 11)) goto end; size_t remains = wsgi_req->post_cl; while(remains > 0) { ssize_t body_len = 0; char *body = uwsgi_request_body_read(wsgi_req, UMIN(remains, 32768) , &body_len); if (!body || body == uwsgi.empty) break; if (write(fd, body, body_len) != body_len) goto end; } end: close(fd); return UWSGI_OK; } static int uwsgi_webdav_massive_delete(char *dir) { int ret = 0; DIR *d = opendir(dir); for (;;) { struct dirent *de_r = NULL; struct dirent de; if (readdir_r(d, &de, &de_r)) { ret = -1; goto end; } if (de_r == NULL) break; // skip myself and parent if (!strcmp(de.d_name, ".") || !strcmp(de.d_name, "..")) continue; char *item = uwsgi_concat3(dir, "/", de.d_name); if (de.d_type == DT_DIR) { if (uwsgi_webdav_massive_delete(item)) { free(item); ret = -1; goto end; } } else { if (unlink(item)) { free(item); ret = -1; goto end; } } free(item); } if (rmdir(dir)) ret = -1; end: closedir(d); return ret; } static int uwsgi_wevdav_manage_delete(struct wsgi_request *wsgi_req) { char filename[PATH_MAX]; size_t filename_len = uwsgi_webdav_expand_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename); // the collection does not exists if (!filename_len) { uwsgi_404(wsgi_req); return UWSGI_OK; } if (uwsgi_is_dir(filename)) { int ret = rmdir(filename); if (ret < 0) { if (errno == ENOTEMPTY) { if (uwsgi_webdav_massive_delete(filename)) { uwsgi_403(wsgi_req); return UWSGI_OK; } } else { uwsgi_403(wsgi_req); return UWSGI_OK; } } } else { if (unlink(filename)) { uwsgi_403(wsgi_req); return UWSGI_OK; } } uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6); return UWSGI_OK; } static int uwsgi_webdav_dirlist_add_item(struct uwsgi_buffer *ub, char *item, size_t item_len, uint8_t is_dir) { if (is_dir) { if (udav.class_directory) { if (uwsgi_buffer_append(ub, "
  • ", 3)) return -1; if (uwsgi_buffer_append(ub, item, item_len)) return -1; if (uwsgi_buffer_append(ub, "/", 1)) return -1; } else { if (uwsgi_buffer_append(ub, "\">", 2)) return -1; if (uwsgi_buffer_append(ub, item, item_len)) return -1; } if (uwsgi_buffer_append(ub, "
  • ", 9)) return -1; return 0; } static void uwsgi_webdav_dirlist(struct wsgi_request *wsgi_req, char *dir) { struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); if (uwsgi_buffer_append(ub, "", 19)) goto end; if (uwsgi_buffer_append(ub, dir, strlen(dir))) goto end; if (uwsgi_buffer_append(ub, "", 8)) goto end; struct uwsgi_string_list *usl = udav.css; while(usl) { if (uwsgi_buffer_append(ub, "value, usl->len)) goto end; if (uwsgi_buffer_append(ub, "\" type=\"text/css\">", 18)) goto end; usl = usl->next; } usl = udav.javascript; while(usl) { if (uwsgi_buffer_append(ub, "", 11)) goto end; usl = usl->next; } if (uwsgi_buffer_append(ub, "", 13)) goto end; if (udav.div) { if (uwsgi_buffer_append(ub, "
    ", 2)) goto end; } else { if (uwsgi_buffer_append(ub, "
    ", 5)) goto end; } if (uwsgi_webdav_dirlist_add_item(ub, "..", 2, 1)) goto end; #ifdef __linux__ struct dirent **tasklist; int n = scandir(dir, &tasklist, 0, versionsort); if (n < 0) goto end; int i; for(i=0;id_name[0] == '.') goto next; if (uwsgi_webdav_dirlist_add_item(ub, tasklist[i]->d_name, strlen(tasklist[i]->d_name), tasklist[i]->d_type == DT_DIR ? 1 : 0)) { free(tasklist[i]); free(tasklist); goto end; } next: free(tasklist[i]); } free(tasklist); #else DIR *d = opendir(dir); for (;;) { struct dirent *de_r = NULL; struct dirent de; if (readdir_r(d, &de, &de_r)) goto end; if (de_r == NULL) break; // skip items startign with a dot if (de.d_name[0] == '.') continue; if (uwsgi_webdav_dirlist_add_item(ub, de.d_name, strlen(de.d_name), de.d_type == DT_DIR ? 1 : 0)) goto end; } closedir(d); #endif if (uwsgi_buffer_append(ub, "
    ", 25)) goto end; if (uwsgi_response_add_content_type(wsgi_req, "text/html", 9)) goto end; if (uwsgi_response_add_content_length(wsgi_req, ub->pos)) goto end; uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); end: uwsgi_buffer_destroy(ub); } static int uwsgi_wevdav_manage_get(struct wsgi_request *wsgi_req, int send_body) { char filename[PATH_MAX]; size_t filename_len = uwsgi_webdav_expand_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename); if (!filename_len) { uwsgi_404(wsgi_req); return UWSGI_OK; } if (uwsgi_is_dir(filename)) { uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6); if (send_body) { uwsgi_webdav_dirlist(wsgi_req, filename); } return UWSGI_OK; } int fd = open(filename, O_RDONLY); if (fd < 0) { uwsgi_403(wsgi_req); return UWSGI_OK; } struct stat st; if (fstat(fd, &st)) { close(fd); uwsgi_403(wsgi_req); return UWSGI_OK; } if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end; // add content_length if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end; // add last-modified if (uwsgi_response_add_last_modified(wsgi_req, st.st_mtime)) goto end; // add mime_type size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(filename, filename_len, &mime_type_len); if (mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end; } // add ETag (based on file mtime, not rock-solid, but good enough) char *etag = uwsgi_num2str(st.st_mtime); if (uwsgi_response_add_header(wsgi_req, "ETag", 4, etag, strlen(etag))) { free(etag); goto end; } free(etag); // start sending the file (note: we do not use sendfile() api, for being able to use caching and transformations) if (!send_body) goto end; // use a pretty big buffer (for performance reasons) char buf[32768]; size_t remains = st.st_size; while (remains > 0) { ssize_t rlen = read(fd, buf, UMIN(32768, remains)); if (rlen <= 0) { uwsgi_error("uwsgi_wevdav_manage_get/read()"); break; } remains -= rlen; if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) { break; } } end: close(fd); return UWSGI_OK; } static int uwsgi_wevdav_manage_copy(struct wsgi_request *wsgi_req) { uint16_t destination_len = 0; char *destination = uwsgi_get_var(wsgi_req, "HTTP_DESTINATION", 16, &destination_len); uwsgi_log("Destination: %.*s\n", destination_len, destination); return -1; } static int uwsgi_wevdav_manage_move(struct wsgi_request *wsgi_req) { char filename[PATH_MAX]; char d_filename[PATH_MAX]; size_t filename_len = uwsgi_webdav_expand_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename); if (filename_len == 0) { uwsgi_404(wsgi_req); return UWSGI_OK; } uint16_t destination_len = 0; char *destination = uwsgi_get_var(wsgi_req, "HTTP_DESTINATION", 16, &destination_len); if (destination_len == 0) { uwsgi_403(wsgi_req); return UWSGI_OK; } uint16_t overwrite_len = 0; int can_overwrite = 1; char *overwrite = uwsgi_get_var(wsgi_req, "HTTP_OVERWRITE", 14, &overwrite_len); if (overwrite) { if (overwrite[0] == 'F') { can_overwrite = 0; } } uint16_t scheme_len = wsgi_req->scheme_len; if (wsgi_req->scheme_len == 0) { // http scheme_len = 4; } uint16_t skip = scheme_len + 3 + wsgi_req->host_len; int already_exists = 0; size_t d_filename_len = uwsgi_webdav_expand_path(wsgi_req, destination + skip, destination_len - skip, d_filename); if (d_filename_len > 0) { already_exists = 1; if (!can_overwrite) { uwsgi_response_prepare_headers(wsgi_req, "412 Precondition Failed", 23); return UWSGI_OK; } } else { d_filename_len = uwsgi_webdav_expand_fake_path(wsgi_req, destination + skip, destination_len - skip, d_filename); } if (d_filename_len == 0) { uwsgi_response_prepare_headers(wsgi_req, "409 Conflict", 12); return UWSGI_OK; } if (rename(filename, d_filename)) { uwsgi_403(wsgi_req); return UWSGI_OK; } if (already_exists) { uwsgi_response_prepare_headers(wsgi_req, "204 No Content", 14); } else { uwsgi_response_prepare_headers(wsgi_req, "201 Created", 11); } return UWSGI_OK; } static int uwsgi_wevdav_manage_mkcol(struct wsgi_request *wsgi_req) { if (wsgi_req->post_cl > 0) { uwsgi_response_prepare_headers(wsgi_req, "415 Unsupported Media Type", 26); return UWSGI_OK; } char filename[PATH_MAX]; size_t filename_len = uwsgi_webdav_expand_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename); // the collection already exists if (filename_len > 0) { uwsgi_response_prepare_headers(wsgi_req, "405 Method Not Allowed", 22); return UWSGI_OK; } // remove the last slash (if needed) if (wsgi_req->path_info_len > 1 && wsgi_req->path_info[wsgi_req->path_info_len-1] == '/') { wsgi_req->path_info_len--; } filename_len = uwsgi_webdav_expand_fake_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename); if (!filename_len) { uwsgi_response_prepare_headers(wsgi_req, "409 Conflict", 12); return UWSGI_OK; } // mkdir, if it fails, return a 409 (Conflict) if (mkdir(filename, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { uwsgi_response_prepare_headers(wsgi_req, "409 Conflict", 12); } uwsgi_response_prepare_headers(wsgi_req, "201 Created", 11); return UWSGI_OK; } static int uwsgi_wevdav_manage_mkcalendar(struct wsgi_request *wsgi_req, xmlDoc *doc) { char filename[PATH_MAX]; size_t filename_len = uwsgi_webdav_expand_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename); // the collection already exists if (filename_len > 0) { uwsgi_response_prepare_headers(wsgi_req, "405 Method Not Allowed", 22); return UWSGI_OK; } // remove the last slash (if needed) if (wsgi_req->path_info_len > 1 && wsgi_req->path_info[wsgi_req->path_info_len-1] == '/') { wsgi_req->path_info_len--; } filename_len = uwsgi_webdav_expand_fake_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename); if (!filename_len) { uwsgi_response_prepare_headers(wsgi_req, "409 Conflict", 12); return UWSGI_OK; } // mkdir, if it fails, return a 409 (Conflict) if (mkdir(filename, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { uwsgi_response_prepare_headers(wsgi_req, "409 Conflict", 12); return UWSGI_OK; } xmlNode *element = xmlDocGetRootElement(doc); if (!element) return -1; if (!element || (strcmp((char *) element->name, "mkcalendar"))) return -1; xmlDoc *rdoc = xmlNewDoc(BAD_CAST "1.0"); xmlNode *foobar = xmlNewNode(NULL, BAD_CAST "foobar"); xmlDocSetRootElement(rdoc, foobar); // propfind can be "set" or "remove" xmlNode *node; for (node = element->children; node; node = node->next) { if (node->type == XML_ELEMENT_NODE) { if (node->ns && !strcmp((char *) node->ns->href, "DAV:")) { if (!strcmp((char *) node->name, "set")) { uwsgi_webdav_manage_prop_update(wsgi_req, node, foobar, filename, 0); } } } } uwsgi_response_prepare_headers(wsgi_req, "201 Created", 11); xmlFreeDoc(rdoc); return UWSGI_OK; } static int uwsgi_wevdav_manage_lock(struct wsgi_request *wsgi_req) { uwsgi_response_prepare_headers(wsgi_req, "201 Created", 11); return UWSGI_OK; } static int uwsgi_webdav_request(struct wsgi_request *wsgi_req) { if (!udav.mountpoints) { uwsgi_500(wsgi_req); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } if (wsgi_req->path_info_len == 0) { uwsgi_403(wsgi_req); return UWSGI_OK; } wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, webdav_plugin.modifier1); if (wsgi_req->app_id == -1) { uwsgi_403(wsgi_req); return UWSGI_OK; } // non lockables methods... if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "OPTIONS", 7)) { return uwsgi_wevdav_manage_options(wsgi_req); } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "GET", 3)) { return uwsgi_wevdav_manage_get(wsgi_req, 1); } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) { return uwsgi_wevdav_manage_get(wsgi_req, 0); } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PROPFIND", 8)) { if (wsgi_req->post_cl > 0) { ssize_t body_len = 0; char *body = uwsgi_request_body_read(wsgi_req, wsgi_req->post_cl, &body_len); #ifdef UWSGI_DEBUG uwsgi_log("%.*s\n", body_len, body); #endif xmlDoc *doc = xmlReadMemory(body, body_len, NULL, NULL, 0); if (!doc) goto end; uwsgi_wevdav_manage_propfind(wsgi_req, doc); xmlFreeDoc(doc); } else { uwsgi_wevdav_manage_propfind(wsgi_req, NULL); } } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "REPORT", 6)) { if (wsgi_req->post_cl > 0) { ssize_t body_len = 0; char *body = uwsgi_request_body_read(wsgi_req, wsgi_req->post_cl, &body_len); #ifdef UWSGI_DEBUG uwsgi_log("%.*s\n", body_len, body); #endif xmlDoc *doc = xmlReadMemory(body, body_len, NULL, NULL, 0); if (!doc) goto end; xmlFreeDoc(doc); } } // lockable methods ... // check for locking if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PUT", 3)) { return uwsgi_wevdav_manage_put(wsgi_req); } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "DELETE", 6)) { return uwsgi_wevdav_manage_delete(wsgi_req); } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "MKCOL", 5)) { return uwsgi_wevdav_manage_mkcol(wsgi_req); } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "MKCALENDAR", 10)) { if (wsgi_req->post_cl == 0) goto end; ssize_t body_len = 0; char *body = uwsgi_request_body_read(wsgi_req, wsgi_req->post_cl, &body_len); #ifdef UWSGI_DEBUG uwsgi_log("%.*s\n", body_len, body); #endif xmlDoc *doc = xmlReadMemory(body, body_len, NULL, NULL, 0); if (!doc) goto end; uwsgi_wevdav_manage_mkcalendar(wsgi_req, doc); xmlFreeDoc(doc); } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "COPY", 4)) { return uwsgi_wevdav_manage_copy(wsgi_req); } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "MOVE", 4)) { return uwsgi_wevdav_manage_move(wsgi_req); } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "LOCK", 4)) { if (wsgi_req->post_cl > 0) { ssize_t body_len = 0; char *body = uwsgi_request_body_read(wsgi_req, wsgi_req->post_cl, &body_len); #ifdef UWSGI_DEBUG uwsgi_log("%.*s\n", body_len, body); #endif xmlDoc *doc = xmlReadMemory(body, body_len, NULL, NULL, 0); if (!doc) goto end; xmlFreeDoc(doc); } return uwsgi_wevdav_manage_lock(wsgi_req); } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PROPPATCH", 9)) { if (wsgi_req->post_cl == 0) goto end; ssize_t body_len = 0; char *body = uwsgi_request_body_read(wsgi_req, wsgi_req->post_cl, &body_len); #ifdef UWSGI_DEBUG uwsgi_log("%.*s\n", body_len, body); #endif xmlDoc *doc = xmlReadMemory(body, body_len, NULL, NULL, 0); if (!doc) goto end; uwsgi_wevdav_manage_proppatch(wsgi_req, doc); xmlFreeDoc(doc); } end: return UWSGI_OK; } static void uwsgi_webdav_mount() { struct uwsgi_string_list *usl = udav.mountpoints; while(usl) { if (uwsgi_apps_cnt >= uwsgi.max_apps) { uwsgi_log("ERROR: you cannot load more than %d apps in a worker\n", uwsgi.max_apps); exit(1); } int id = uwsgi_apps_cnt; char *mountpoint = ""; int mountpoint_len = 0; char *docroot = usl->value; char *equal = strchr(usl->value, '='); if (equal) { *equal = 0; docroot = equal+1; mountpoint = usl->value; mountpoint_len = strlen(mountpoint); } char *wd_docroot = uwsgi_calloc(PATH_MAX); if (!realpath(docroot, wd_docroot)) { uwsgi_error("uwsgi_webdav_mount()/realpath()"); exit(1); } if (equal) { *equal = '='; } struct uwsgi_app *ua = uwsgi_add_app(id, webdav_plugin.modifier1, mountpoint, mountpoint_len, wd_docroot, wd_docroot); uwsgi_emulate_cow_for_apps(id); uwsgi_log("WebDAV mountpoint \"%.*s\" (%d) added: docroot=%s\n", ua->mountpoint_len, ua->mountpoint, id, wd_docroot ); usl = usl->next; } } static void uwsgi_webdav_after_request(struct wsgi_request *wsgi_req) { if (!udav.mountpoints) return; log_request(wsgi_req); } struct uwsgi_plugin webdav_plugin = { .modifier1 = 35, .name = "webdav", .options = uwsgi_webdav_options, .init_apps = uwsgi_webdav_mount, .request = uwsgi_webdav_request, .after_request = uwsgi_webdav_after_request, }; uwsgi-2.0.29/plugins/xattr/000077500000000000000000000000001477626554400156115ustar00rootroot00000000000000uwsgi-2.0.29/plugins/xattr/uwsgiplugin.py000066400000000000000000000000771477626554400205440ustar00rootroot00000000000000NAME='xattr' CFLAGS=[] LDFLAGS=[] LIBS=[] GCC_LIST = ['xattr'] uwsgi-2.0.29/plugins/xattr/xattr.c000066400000000000000000000047421477626554400171260ustar00rootroot00000000000000#include /* xattr-related plugin exposes two routing vars: file is a var, key is a string ${xattr[PATH_INFO:user.uwsgi.webdav.foobar]} file is a var, key is a var ${xattr2[PATH_INFO:MYKEY]} */ #ifdef __linux__ #include #endif static char *uwsgi_route_var_xattr(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) { char *colon = memchr(key, ':', keylen); if (!colon) return NULL; uint16_t var_vallen = 0; char *var_value = uwsgi_get_var(wsgi_req, key, colon-key, &var_vallen); if (var_value) { char *filename = uwsgi_concat2n(var_value, var_vallen, "", 0); char *name = uwsgi_concat2n(colon+1, (keylen-1) - (colon-key), "", 0); ssize_t rlen = getxattr(filename, name, NULL, 0); if (rlen > 0) { char *value = uwsgi_calloc(rlen); getxattr(filename, name, value, rlen); *vallen = rlen; free(filename); free(name); return value; } free(filename); free(name); } return NULL; } static char *uwsgi_route_var_xattr2(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, uint16_t *vallen) { char *colon = memchr(key, ':', keylen); if (!colon) return NULL; uint16_t var_vallen = 0; char *var_value = uwsgi_get_var(wsgi_req, key, colon-key, &var_vallen); if (var_value) { uint16_t var2_vallen = 0; char *var2_value = uwsgi_get_var(wsgi_req, colon+1, (keylen-1) - (colon-key), &var2_vallen); if (var2_value) { char *filename = uwsgi_concat2n(var_value, var_vallen, "", 0); char *name = uwsgi_concat2n(var2_value, var2_vallen, "", 0); ssize_t rlen = getxattr(filename, name, NULL, 0); if (rlen > 0) { char *value = uwsgi_calloc(rlen); getxattr(filename, name, value, rlen); *vallen = rlen; free(filename); free(name); return value; } free(filename); free(name); } } return NULL; } static void register_route_vars_xattr() { struct uwsgi_route_var *urv = uwsgi_register_route_var("xattr", uwsgi_route_var_xattr); urv->need_free = 1; urv = uwsgi_register_route_var("xattr2", uwsgi_route_var_xattr2); urv->need_free = 1; } struct uwsgi_plugin xattr_plugin = { .name = "xattr", .on_load = register_route_vars_xattr, }; uwsgi-2.0.29/plugins/xslt/000077500000000000000000000000001477626554400154415ustar00rootroot00000000000000uwsgi-2.0.29/plugins/xslt/uwsgiplugin.py000066400000000000000000000002711477626554400203700ustar00rootroot00000000000000import os NAME='xslt' CFLAGS = os.popen('xslt-config --cflags').read().rstrip().split() LDFLAGS = [] LIBS = os.popen('xslt-config --libs').read().rstrip().split() GCC_LIST = ['xslt'] uwsgi-2.0.29/plugins/xslt/xslt.c000066400000000000000000000353271477626554400166110ustar00rootroot00000000000000#include #include #include /* XSLT request plugin it takes an XML file as input (taken from DOCUMENT_ROOT + PATH_INFO by default) it search for an XSLT stylesheet (by default in DOCUMENT_ROOT + PATH_INFO - ext + .xsl|.xslt) it applies params (by default taken from the QUERY_STRING) XSLT routing instruction xslt:doc=,stylesheet=,params= As transformation toxslt:stylesheet=,params= */ struct uwsgi_xslt_config { struct uwsgi_string_list *docroot; struct uwsgi_string_list *ext; struct uwsgi_string_list *var; struct uwsgi_string_list *stylesheet; char *content_type; uint16_t content_type_len; } uxslt; struct uwsgi_router_xslt_conf { char *doc; uint16_t doc_len; char *stylesheet; uint16_t stylesheet_len; char *params; uint16_t params_len; char *content_type; uint16_t content_type_len; }; struct uwsgi_transformation_xslt_conf { struct uwsgi_buffer *stylesheet; struct uwsgi_buffer *params; struct uwsgi_buffer *content_type; }; struct uwsgi_option uwsgi_xslt_options[] = { {"xslt-docroot", required_argument, 0, "add a document_root for xslt processing", uwsgi_opt_add_string_list, &uxslt.docroot, 0}, {"xslt-ext", required_argument, 0, "search for xslt stylesheets with the specified extension", uwsgi_opt_add_string_list, &uxslt.ext, 0}, {"xslt-var", required_argument, 0, "get the xslt stylesheet path from the specified request var", uwsgi_opt_add_string_list, &uxslt.var, 0}, {"xslt-stylesheet", required_argument, 0, "if no xslt stylesheet file can be found, use the specified one", uwsgi_opt_add_string_list, &uxslt.stylesheet, 0}, {"xslt-content-type", required_argument, 0, "set the content-type for the xslt rsult (default: text/html)", uwsgi_opt_set_str, &uxslt.content_type, 0}, {NULL, 0, 0, NULL, NULL, NULL, 0}, }; static char *uwsgi_xslt_apply(xmlDoc *doc, char *xsltfile, char *params, int *rlen) { char **vparams = NULL; char *tmp_params = NULL; uint16_t count = 0; if (params) { // first count the number of items size_t i; size_t params_len = strlen(params); for(i=0;ivalue, usl->len, "/", 1, wsgi_req->path_info, wsgi_req->path_info_len); if (uwsgi_is_file(xmlfile)) { break; } free(xmlfile); xmlfile = NULL; usl = usl->next; } } // fallback to DOCUMENT_ROOT else { if (wsgi_req->document_root_len == 0) { uwsgi_403(wsgi_req); return UWSGI_OK; } xmlfile = uwsgi_concat3n(wsgi_req->document_root, wsgi_req->document_root_len, "/", 1, wsgi_req->path_info, wsgi_req->path_info_len); } if (!xmlfile) { uwsgi_404(wsgi_req); return UWSGI_OK; } // we have the full path, check if it is valid if (!uwsgi_expand_path(xmlfile, strlen(xmlfile), filename)) { free(xmlfile); uwsgi_404(wsgi_req); return UWSGI_OK; } if (!uwsgi_is_file(filename)) { uwsgi_403(wsgi_req); free(xmlfile); return UWSGI_OK; } filename_len = strlen(filename); // now search for the xslt file int found = 0; // first check for specific vars usl = uxslt.var; while(usl) { uint16_t rlen; char *value = uwsgi_get_var(wsgi_req, usl->value, usl->len, &rlen); if (value) { memcpy(stylesheet, value, rlen); stylesheet[rlen] = 0; stylesheet_len = rlen; found = 1; break; } usl = usl->next; } if (found) goto apply; // then check for custom extensions if (uxslt.ext) { usl = uxslt.ext; while(usl) { char *tmp_path = uwsgi_concat2n(filename, filename_len, usl->value, usl->len); if (uwsgi_is_file(tmp_path)) { stylesheet_len = filename_len + usl->len; memcpy(stylesheet, tmp_path, stylesheet_len); stylesheet[stylesheet_len] = 0; free(tmp_path); found = 1; break; } free(tmp_path); usl = usl->next; } } // use default extensions .xsl/.xslt else { char *tmp_path = uwsgi_concat2n(filename, filename_len, ".xsl", 4); if (uwsgi_is_file(tmp_path)) { stylesheet_len = filename_len + 4; memcpy(stylesheet, tmp_path, stylesheet_len); stylesheet[stylesheet_len] = 0; free(tmp_path); goto apply; } free(tmp_path); tmp_path = uwsgi_concat2n(filename, filename_len, ".xslt", 5); if (uwsgi_is_file(tmp_path)) { stylesheet_len = filename_len + 5; memcpy(stylesheet, tmp_path, stylesheet_len); stylesheet[stylesheet_len] = 0; found = 1; } free(tmp_path); } if (found) goto apply; // finally check for static stylesheets usl = uxslt.stylesheet; while(usl) { if (uwsgi_is_file(usl->value)) { memcpy(stylesheet, usl->value, usl->len); stylesheet_len = usl->len; stylesheet[stylesheet_len] = 0; found = 1; break; } usl = usl->next; } if (found) goto apply; uwsgi_404(wsgi_req); free(xmlfile); return UWSGI_OK; apply: // we have both the file and the stylesheet, let's run the engine doc = xmlParseFile(xmlfile); free(xmlfile); if (!doc) { uwsgi_500(wsgi_req); return UWSGI_OK; } if (wsgi_req->query_string_len > 0) { params = uwsgi_concat2n(wsgi_req->query_string, wsgi_req->query_string_len, "", 0); } output = uwsgi_xslt_apply(doc, stylesheet, params, &output_rlen); xmlFreeDoc(doc); if (params) free(params); if (!output) { uwsgi_500(wsgi_req); return UWSGI_OK; } // prepare headers if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) { uwsgi_500(wsgi_req); goto end; } // content_length if (uwsgi_response_add_content_length(wsgi_req, output_rlen)) { uwsgi_500(wsgi_req); goto end; } // content_type if (uwsgi_response_add_content_type(wsgi_req, uxslt.content_type, uxslt.content_type_len)) { uwsgi_500(wsgi_req); goto end; } uwsgi_response_write_body_do(wsgi_req, output, output_rlen); end: xmlFree(output); return UWSGI_OK; } static void uwsgi_xslt_log(struct wsgi_request *wsgi_req) { log_request(wsgi_req); } static int transform_toxslt(struct wsgi_request *wsgi_req, struct uwsgi_transformation *ut) { int ret = -1; struct uwsgi_transformation_xslt_conf *utxc = (struct uwsgi_transformation_xslt_conf *) ut->data; struct uwsgi_buffer *ub = ut->chunk; xmlDoc *doc = xmlReadMemory(ub->buf, ub->pos, NULL, NULL, 0); if (!doc) goto end; int rlen; char *output = uwsgi_xslt_apply( doc, utxc->stylesheet->buf, utxc->params ? utxc->params->buf : NULL, &rlen); if (!output) goto end; // do not check for errors !!! if (ut->round == 1) { uwsgi_response_add_content_type(wsgi_req, utxc->content_type->buf, utxc->content_type->pos); } uwsgi_buffer_map(ub, output, rlen); ret = 0; end: if (doc) xmlFreeDoc(doc); if (utxc->stylesheet) uwsgi_buffer_destroy(utxc->stylesheet); if (utxc->params) uwsgi_buffer_destroy(utxc->params); if (utxc->content_type) uwsgi_buffer_destroy(utxc->content_type); free(utxc); return ret; } static int uwsgi_routing_func_toxslt(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_router_xslt_conf *urxc = (struct uwsgi_router_xslt_conf *) ur->data2; struct uwsgi_transformation_xslt_conf *utxc = uwsgi_calloc(sizeof(struct uwsgi_transformation_xslt_conf)); char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); utxc->stylesheet = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->stylesheet, urxc->stylesheet_len); if (!utxc->stylesheet) goto end; if (urxc->params) { utxc->params = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->params, urxc->params_len); if (!utxc->params) goto end; } if (urxc->content_type) { utxc->content_type = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->content_type, urxc->content_type_len); if (!utxc->content_type) goto end; } uwsgi_add_transformation(wsgi_req, transform_toxslt, utxc); return UWSGI_ROUTE_NEXT; end: if (utxc->stylesheet) uwsgi_buffer_destroy(utxc->stylesheet); if (utxc->params) uwsgi_buffer_destroy(utxc->params); if (utxc->content_type) uwsgi_buffer_destroy(utxc->content_type); free(utxc); return UWSGI_ROUTE_BREAK; } static int uwsgi_routing_func_xslt(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_router_xslt_conf *urxc = (struct uwsgi_router_xslt_conf *) ur->data2; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub_doc = NULL; struct uwsgi_buffer *ub_stylesheet = NULL; struct uwsgi_buffer *ub_params = NULL; struct uwsgi_buffer *ub_content_type = NULL; ub_doc = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->doc, urxc->doc_len); if (!ub_doc) goto end; ub_stylesheet = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->stylesheet, urxc->stylesheet_len); if (!ub_stylesheet) goto end; if (urxc->params) { ub_params = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->params, urxc->params_len); if (!ub_params) goto end; } if (!urxc->content_type) goto end; ub_content_type = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->content_type, urxc->content_type_len); if (!ub_content_type) goto end; int rlen; xmlDoc *doc = xmlParseFile(ub_doc->buf) ; if (!doc) goto end; char *output = uwsgi_xslt_apply(doc, ub_stylesheet->buf, ub_params ? ub_params->buf : NULL, &rlen); xmlFreeDoc(doc); if (!output) goto end; if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end; if (uwsgi_response_add_content_length(wsgi_req, rlen)) goto end; if (uwsgi_response_add_content_type(wsgi_req, urxc->content_type, urxc->content_type_len)) goto end; uwsgi_response_write_body_do(wsgi_req, output, rlen); xmlFree(output); end: if (ub_doc) uwsgi_buffer_destroy(ub_doc); if (ub_stylesheet) uwsgi_buffer_destroy(ub_stylesheet); if (ub_params) uwsgi_buffer_destroy(ub_params); if (ub_content_type) uwsgi_buffer_destroy(ub_content_type); return UWSGI_ROUTE_BREAK; } static int uwsgi_router_xslt(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_xslt; ur->data = args; ur->data_len = strlen(args); struct uwsgi_router_xslt_conf *urxc = uwsgi_calloc(sizeof(struct uwsgi_router_xslt_conf)); if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=', "doc", &urxc->doc, "stylesheet", &urxc->stylesheet, "content_type", &urxc->content_type, "params", &urxc->params, NULL)) { uwsgi_log("invalid route syntax: %s\n", args); exit(1); } if (!urxc->doc || !urxc->stylesheet) { uwsgi_log("invalid route syntax: you need to specify a doc and a stylesheet\n"); exit(1); } urxc->doc_len = strlen(urxc->doc); urxc->stylesheet_len = strlen(urxc->stylesheet); if (urxc->params) urxc->params_len = strlen(urxc->params); if (!urxc->content_type) urxc->content_type = "text/html"; urxc->content_type_len = strlen(urxc->content_type); ur->data2 = urxc; return 0; } static int uwsgi_router_toxslt(struct uwsgi_route *ur, char *args) { ur->func = uwsgi_routing_func_toxslt; ur->data = args; ur->data_len = strlen(args); struct uwsgi_router_xslt_conf *urxc = uwsgi_calloc(sizeof(struct uwsgi_router_xslt_conf)); if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=', "stylesheet", &urxc->stylesheet, "content_type", &urxc->content_type, "params", &urxc->params, NULL)) { uwsgi_log("invalid route syntax: %s\n", args); exit(1); } if (!urxc->stylesheet) { uwsgi_log("invalid route/transformation syntax: you need to specify a stylesheet\n"); exit(1); } urxc->stylesheet_len = strlen(urxc->stylesheet); if (urxc->params) urxc->params_len = strlen(urxc->params); if (!urxc->content_type) urxc->content_type = "text/html"; urxc->content_type_len = strlen(urxc->content_type); ur->data2 = urxc; return 0; } static void router_xslt_register() { uwsgi_register_router("xslt", uwsgi_router_xslt); uwsgi_register_router("toxslt", uwsgi_router_toxslt); } struct uwsgi_plugin xslt_plugin = { .name = "xslt", .modifier1 = 23, .options = uwsgi_xslt_options, .request = uwsgi_request_xslt, .after_request = uwsgi_xslt_log, .on_load = router_xslt_register, }; uwsgi-2.0.29/plugins/zabbix/000077500000000000000000000000001477626554400157265ustar00rootroot00000000000000uwsgi-2.0.29/plugins/zabbix/plugin.c000066400000000000000000000141571477626554400174000ustar00rootroot00000000000000#include /* this is a stats pusher plugin for the zabbix server: --stats-push zabbix:address[,prefix] example: --stats-push zabbix:127.0.0.1:10051,myinstance it exports values exposed by the metric subsystem */ extern struct uwsgi_server uwsgi; static char *zabbix_template = NULL; static void uwsgi_opt_zabbix_template(char *opt, char *value, void *none) { if (value) { zabbix_template = value; } else { zabbix_template = ""; } } static struct uwsgi_option zabbix_options[] = { {"zabbix-template", optional_argument, 0, "print (or store to a file) the zabbix template for the current metrics setup", uwsgi_opt_zabbix_template, NULL, UWSGI_OPT_METRICS}, {0, 0, 0, 0, 0, 0, 0}, }; // configuration of a zabbix node struct zabbix_node { char *addr; char *prefix; uint16_t prefix_len; // we reuse the same buffer struct uwsgi_buffer *ub; }; /* { "request":"sender data", "data": [ {"host":uwsgi.hostname, "key":"foo", "value":"bar"}, ... ] } */ static void stats_pusher_zabbix(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) { if (!uspi->configured) { struct zabbix_node *zn = uwsgi_calloc(sizeof(struct zabbix_node)); if (!uspi->arg || strlen(uspi->arg) == 0) { zn->addr = uwsgi_str("127.0.0.1:10051"); } else { zn->addr = uwsgi_str(uspi->arg); } char *comma = strchr(zn->addr, ','); if (comma) { zn->prefix = comma+1; zn->prefix_len = strlen(zn->prefix); *comma = 0; } else { zn->prefix = "uwsgi"; zn->prefix_len = 5; } zn->ub = uwsgi_buffer_new(uwsgi.page_size); uwsgi_buffer_append(zn->ub, "ZBXD\1\0\0\0\0\0\0\0\0{\"request\":\"sender data\",\"data\":[", 46); uspi->data = zn; uspi->configured = 1; } struct zabbix_node *zn = (struct zabbix_node *) uspi->data ; // we use the same buffer for all of the packets zn->ub->pos = 46; struct uwsgi_metric *um = uwsgi.metrics; int error = 0; uwsgi_rlock(uwsgi.metrics_lock); while(um) { if (uwsgi_buffer_append(zn->ub, "{\"host\":\"", 9)) { error = 1; goto end;} if (uwsgi_buffer_append(zn->ub, uwsgi.hostname, uwsgi.hostname_len)) { error = 1; goto end;} if (uwsgi_buffer_append(zn->ub, "\",\"key\":\"", 9)) { error = 1; goto end;} if (uwsgi_buffer_append(zn->ub, zn->prefix, zn->prefix_len)) { error = 1; goto end;} if (uwsgi_buffer_append(zn->ub, ".", 1)) { error = 1; goto end;} if (uwsgi_buffer_append(zn->ub, um->name, um->name_len)) { error = 1; goto end;} if (uwsgi_buffer_append(zn->ub, "\",\"value\":\"", 11)) { error = 1; goto end;} if (uwsgi_buffer_num64(zn->ub, *um->value)) { error = 1; goto end;} if (uwsgi_buffer_append(zn->ub, "\"}", 2)) { error = 1; goto end;} if (um->reset_after_push){ uwsgi_rwunlock(uwsgi.metrics_lock); uwsgi_wlock(uwsgi.metrics_lock); *um->value = um->initial_value; uwsgi_rwunlock(uwsgi.metrics_lock); uwsgi_rlock(uwsgi.metrics_lock); } um = um->next; if (um) { if (uwsgi_buffer_append(zn->ub, ",", 1)) { error = 1; goto end;} } } if (uwsgi_buffer_append(zn->ub, "]}", 2)) error = 1; end: uwsgi_rwunlock(uwsgi.metrics_lock); if (error) return; uint64_t pktsize = zn->ub->pos - 13; zn->ub->pos = 5; if (uwsgi_buffer_u64le(zn->ub, pktsize)) error = 1; if (error) return; int fd = uwsgi_connect(zn->addr, uwsgi.socket_timeout, 0); if (fd < 0) { uwsgi_error("stats_pusher_zabbix()/connect()"); return; } if (write(fd, zn->ub->buf, pktsize + 13) != (ssize_t) (pktsize + 13)) { uwsgi_error("stats_pusher_zabbix()/write()"); } // fake read for simplify debug with strace char buf[4096]; if (read(fd, buf, 4096) <= 0) { uwsgi_error("stats_pusher_zabbix()/read()"); } close(fd); } static void stats_pusher_zabbix_init(void) { struct uwsgi_stats_pusher *usp = uwsgi_register_stats_pusher("zabbix", stats_pusher_zabbix); // we use a custom format not the JSON one usp->raw = 1; } static void zabbix_template_print() { if (!zabbix_template) return; int fd = 1 ; if (zabbix_template[0] != 0) { fd = open(zabbix_template, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP); if (fd < 0) { uwsgi_error_open(zabbix_template); exit(1); } } struct uwsgi_metric *um = uwsgi.metrics; struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); if (uwsgi_buffer_append(ub,"\n", 39)) goto error; if (uwsgi_buffer_append(ub,"\n", 16)) goto error; if (uwsgi_buffer_append(ub,"2.0uWSGI\n", 73)) goto error; if (uwsgi_buffer_append(ub,"\t\n", 33)) goto error; if (uwsgi_buffer_append(ub,"\n", 17)) goto error; if (write(fd, ub->buf, ub->pos) != (ssize_t) ub->pos) { uwsgi_error("zabbix_template_print()/wrtie()"); exit(1); } uwsgi_buffer_destroy(ub); if (zabbix_template[0] != 0) { uwsgi_log("zabbix template written to %s\n", zabbix_template); close(fd); } return; error: uwsgi_buffer_destroy(ub); uwsgi_log("error generating zabbix template\n"); exit(1); } struct uwsgi_plugin zabbix_plugin = { .name = "zabbix", .options = zabbix_options, .on_load = stats_pusher_zabbix_init, .preinit_apps = zabbix_template_print, }; uwsgi-2.0.29/plugins/zabbix/uwsgiplugin.py000066400000000000000000000001111477626554400206460ustar00rootroot00000000000000NAME='zabbix' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['plugin'] uwsgi-2.0.29/plugins/zergpool/000077500000000000000000000000001477626554400163105ustar00rootroot00000000000000uwsgi-2.0.29/plugins/zergpool/uwsgiplugin.py000066400000000000000000000001151477626554400212340ustar00rootroot00000000000000 NAME='zergpool' CFLAGS = [] LDFLAGS = [] LIBS = [] GCC_LIST = ['zergpool'] uwsgi-2.0.29/plugins/zergpool/zergpool.c000066400000000000000000000072301477626554400203170ustar00rootroot00000000000000/* uWSGI zergpool */ #include "../../uwsgi.h" extern struct uwsgi_server uwsgi; struct uwsgi_string_list *zergpool_socket_names; #define ZERGPOOL_EVENTS 64 struct uwsgi_option zergpool_options[] = { { "zergpool", required_argument, 0, "start a zergpool on specified address for specified address", uwsgi_opt_add_string_list, &zergpool_socket_names, 0}, { "zerg-pool", required_argument, 0, "start a zergpool on specified address for specified address", uwsgi_opt_add_string_list, &zergpool_socket_names, 0}, {0, 0, 0, 0, 0, 0, 0}, }; struct zergpool_socket { int fd; int *sockets; int num_sockets; struct zergpool_socket *next; }; struct zergpool_socket *zergpool_sockets; void zergpool_loop(int id, void *foobar) { int i; int zergpool_queue = event_queue_init(); void *events = event_queue_alloc(ZERGPOOL_EVENTS); struct zergpool_socket *zps = zergpool_sockets; while(zps) { event_queue_add_fd_read(zergpool_queue, zps->fd); zps = zps->next; } for(;;) { int nevents = event_queue_wait_multi(zergpool_queue, -1, events, ZERGPOOL_EVENTS); for(i=0;ifd == interesting_fd) { uwsgi_manage_zerg(zps->fd, zps->num_sockets, zps->sockets); } zps = zps->next; } } } } struct zergpool_socket *add_zergpool_socket(char *name, char *sockets) { struct zergpool_socket *z_sock,*zps = zergpool_sockets; if (!zps) { z_sock = uwsgi_calloc(sizeof(struct zergpool_socket)); zergpool_sockets = z_sock; } else { while(zps) { if (!zps->next) { z_sock= uwsgi_calloc(sizeof(struct zergpool_socket)); zps->next = z_sock; break; } zps = zps->next; } } // do not defer accept for zergpools if (uwsgi.no_defer_accept) { uwsgi.no_defer_accept = 0; z_sock->fd = bind_to_unix(name, uwsgi.listen_queue, uwsgi.chmod_socket, 0); uwsgi.no_defer_accept = 1; } else { z_sock->fd = bind_to_unix(name, uwsgi.listen_queue, uwsgi.chmod_socket, 0); } char *sock_list = uwsgi_str(sockets); char *p, *ctx = NULL; uwsgi_foreach_token(sock_list, ",", p, ctx) { z_sock->num_sockets++; } free(sock_list); z_sock->sockets = uwsgi_calloc(sizeof(int) * (z_sock->num_sockets + 1)); sock_list = uwsgi_str(sockets); int pos = 0; ctx = NULL; uwsgi_foreach_token(sock_list, ",", p, ctx) { char *port = strchr(p, ':'); char *sockname; if (!port) { z_sock->sockets[pos] = bind_to_unix(p, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); sockname = uwsgi_getsockname(z_sock->sockets[pos]); uwsgi_log("zergpool %s bound to UNIX socket %s (fd: %d)\n", name, sockname, z_sock->sockets[pos]); } else { char *gsn = generate_socket_name(p); z_sock->sockets[pos] = bind_to_tcp(gsn, uwsgi.listen_queue, strchr(gsn, ':')); sockname = uwsgi_getsockname(z_sock->sockets[pos]); uwsgi_log("zergpool %s bound to TCP socket %s (fd: %d)\n", name, sockname, z_sock->sockets[pos]); } pos++; free(sockname); } free(sock_list); return z_sock; } int zergpool_init() { if (!zergpool_socket_names) return 0; struct uwsgi_string_list *zpsn = zergpool_socket_names; while(zpsn) { char *colon = strchr(zpsn->value, ':'); if (!colon) { uwsgi_log("invalid zergpool syntax: %s\n", zpsn->value); exit(1); } *colon = 0; add_zergpool_socket(zpsn->value, colon+1); *colon = ':'; zpsn = zpsn->next; } if (register_gateway("uWSGI zergpool", zergpool_loop, NULL) == NULL) { uwsgi_log("unable to register the zergpool gateway\n"); exit(1); } return 0; } struct uwsgi_plugin zergpool_plugin = { .name = "zergpool", .options = zergpool_options, .init = zergpool_init, }; uwsgi-2.0.29/proto/000077500000000000000000000000001477626554400141315ustar00rootroot00000000000000uwsgi-2.0.29/proto/BUILD000066400000000000000000000000351477626554400147110ustar00rootroot00000000000000exports_files(glob(["*.c"])) uwsgi-2.0.29/proto/base.c000066400000000000000000000310131477626554400152050ustar00rootroot00000000000000#include "uwsgi.h" extern struct uwsgi_server uwsgi; int uwsgi_proto_raw_parser(struct wsgi_request *wsgi_req) { wsgi_req->is_raw = 1; wsgi_req->uh->modifier1 = uwsgi.raw_modifier1; wsgi_req->uh->modifier2 = uwsgi.raw_modifier2; return UWSGI_OK; } uint16_t proto_base_add_uwsgi_header(struct wsgi_request *wsgi_req, char *key, uint16_t keylen, char *val, uint16_t vallen) { int i; char *buffer = wsgi_req->buffer + wsgi_req->uh->pktsize; char *watermark = wsgi_req->buffer + uwsgi.buffer_size; char *ptr = buffer; for (i = 0; i < keylen; i++) { if (key[i] == '-') { key[i] = '_'; } else { key[i] = toupper((int)key[i]); } } if (uwsgi_strncmp("CONTENT_TYPE", 12, key, keylen) && uwsgi_strncmp("CONTENT_LENGTH", 14, key, keylen)) { if (buffer + keylen + vallen + 2 + 2 + 5 >= watermark) { uwsgi_log("[WARNING] unable to add %.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, key, vallen, val); return 0; } *ptr++ = (uint8_t) ((keylen + 5) & 0xff); *ptr++ = (uint8_t) (((keylen + 5) >> 8) & 0xff); memcpy(ptr, "HTTP_", 5); ptr += 5; memcpy(ptr, key, keylen); ptr += keylen; keylen += 5; } else { if (buffer + keylen + vallen + 2 + 2 >= watermark) { uwsgi_log("[WARNING] unable to add %.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, key, vallen, val); return 0; } *ptr++ = (uint8_t) (keylen & 0xff); *ptr++ = (uint8_t) ((keylen >> 8) & 0xff); memcpy(ptr, key, keylen); ptr += keylen; } *ptr++ = (uint8_t) (vallen & 0xff); *ptr++ = (uint8_t) ((vallen >> 8) & 0xff); memcpy(ptr, val, vallen); #ifdef UWSGI_DEBUG uwsgi_log("add uwsgi var: %.*s = %.*s\n", keylen, key, vallen, val); #endif return keylen + vallen + 2 + 2; } uint16_t proto_base_add_uwsgi_var(struct wsgi_request * wsgi_req, char *key, uint16_t keylen, char *val, uint16_t vallen) { char *buffer = wsgi_req->buffer + wsgi_req->uh->pktsize; char *watermark = wsgi_req->buffer + uwsgi.buffer_size; char *ptr = buffer; if (buffer + keylen + vallen + 2 + 2 >= watermark) { uwsgi_log("[WARNING] unable to add %.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, key, vallen, val); return 0; } *ptr++ = (uint8_t) (keylen & 0xff); *ptr++ = (uint8_t) ((keylen >> 8) & 0xff); memcpy(ptr, key, keylen); ptr += keylen; *ptr++ = (uint8_t) (vallen & 0xff); *ptr++ = (uint8_t) ((vallen >> 8) & 0xff); memcpy(ptr, val, vallen); #ifdef UWSGI_DEBUG uwsgi_log("add uwsgi var: %.*s = %.*s\n", keylen, key, vallen, val); #endif return keylen + vallen + 2 + 2; } int uwsgi_proto_base_accept(struct wsgi_request *wsgi_req, int fd) { wsgi_req->c_len = sizeof(struct sockaddr_un); #if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL) return accept4(fd, (struct sockaddr *) &wsgi_req->client_addr, (socklen_t *) & wsgi_req->c_len, SOCK_NONBLOCK); #elif defined(__linux__) int client_fd = accept(fd, (struct sockaddr *) &wsgi_req->client_addr, (socklen_t *) & wsgi_req->c_len); if (client_fd >= 0) { uwsgi_socket_nb(client_fd); } return client_fd; #else return accept(fd, (struct sockaddr *) &wsgi_req->client_addr, (socklen_t *) & wsgi_req->c_len); #endif } void uwsgi_proto_base_close(struct wsgi_request *wsgi_req) { close(wsgi_req->fd); } #ifdef UWSGI_SSL int uwsgi_proto_ssl_accept(struct wsgi_request *wsgi_req, int server_fd) { int fd = uwsgi_proto_base_accept(wsgi_req, server_fd); if (fd >= 0) { wsgi_req->ssl = SSL_new(wsgi_req->socket->ssl_ctx); SSL_set_fd(wsgi_req->ssl, fd); SSL_set_accept_state(wsgi_req->ssl); } return fd; } void uwsgi_proto_ssl_close(struct wsgi_request *wsgi_req) { uwsgi_proto_base_close(wsgi_req); // clear the errors (otherwise they could be propagated) ERR_clear_error(); SSL_free(wsgi_req->ssl); } #endif struct uwsgi_buffer *uwsgi_proto_base_add_header(struct wsgi_request *wsgi_req, char *k, uint16_t kl, char *v, uint16_t vl) { struct uwsgi_buffer *ub = NULL; if (kl > 0) { ub = uwsgi_buffer_new(kl + 2 + vl + 2); if (uwsgi_buffer_append(ub, k, kl)) goto end; if (uwsgi_buffer_append(ub, ": ", 2)) goto end; if (uwsgi_buffer_append(ub, v, vl)) goto end; if (uwsgi_buffer_append(ub, "\r\n", 2)) goto end; } else { ub = uwsgi_buffer_new(vl + 2); if (uwsgi_buffer_append(ub, v, vl)) goto end; if (uwsgi_buffer_append(ub, "\r\n", 2)) goto end; } return ub; end: uwsgi_buffer_destroy(ub); return NULL; } struct uwsgi_buffer *uwsgi_proto_base_prepare_headers(struct wsgi_request *wsgi_req, char *s, uint16_t sl) { struct uwsgi_buffer *ub = NULL; if (uwsgi.cgi_mode == 0) { if (wsgi_req->protocol_len) { ub = uwsgi_buffer_new(wsgi_req->protocol_len + 1 + sl + 2); if (uwsgi_buffer_append(ub, wsgi_req->protocol, wsgi_req->protocol_len)) goto end; if (uwsgi_buffer_append(ub, " ", 1)) goto end; } else { ub = uwsgi_buffer_new(9 + sl + 2); if (uwsgi_buffer_append(ub, "HTTP/1.0 ", 9)) goto end; } } else { ub = uwsgi_buffer_new(8 + sl + 2); if (uwsgi_buffer_append(ub, "Status: ", 8)) goto end; } if (uwsgi_buffer_append(ub, s, sl)) goto end; if (uwsgi_buffer_append(ub, "\r\n", 2)) goto end; return ub; end: uwsgi_buffer_destroy(ub); return NULL; } struct uwsgi_buffer *uwsgi_proto_base_cgi_prepare_headers(struct wsgi_request *wsgi_req, char *s, uint16_t sl) { struct uwsgi_buffer *ub = uwsgi_buffer_new(8 + sl + 2); if (uwsgi_buffer_append(ub, "Status: ", 8)) goto end; if (uwsgi_buffer_append(ub, s, sl)) goto end; if (uwsgi_buffer_append(ub, "\r\n", 2)) goto end; return ub; end: uwsgi_buffer_destroy(ub); return NULL; } int uwsgi_proto_base_write(struct wsgi_request * wsgi_req, char *buf, size_t len) { ssize_t wlen = write(wsgi_req->fd, buf+wsgi_req->write_pos, len-wsgi_req->write_pos); if (wlen > 0) { wsgi_req->write_pos += wlen; if (wsgi_req->write_pos == len) { return UWSGI_OK; } return UWSGI_AGAIN; } if (wlen < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) { return UWSGI_AGAIN; } } return -1; } /* NOTE: len is a pointer as it could be changed on the fly */ int uwsgi_proto_base_writev(struct wsgi_request * wsgi_req, struct iovec *iov, size_t *len) { size_t i,needed = 0; // count the number of bytes to write for(i=0;i<*len;i++) needed += iov[i].iov_len; ssize_t wlen = writev(wsgi_req->fd, iov, *len); if (wlen > 0) { wsgi_req->write_pos += wlen; if ((size_t)wlen == needed) { return UWSGI_OK; } // now the complex part, we need to rebuild iovec and len... size_t orig_len = *len; size_t new_len = orig_len; // first remove the consumed items size_t first_iov = 0; size_t skip_bytes = 0; for(i=0;issl, buf, len); if (ret > 0) { wsgi_req->write_pos += ret; if (wsgi_req->write_pos == len) { return UWSGI_OK; } return UWSGI_AGAIN; } int err = SSL_get_error(wsgi_req->ssl, ret); if (err == SSL_ERROR_WANT_WRITE) { ret = uwsgi_wait_write_req(wsgi_req); if (ret <= 0) return -1; goto retry; } else if (err == SSL_ERROR_WANT_READ) { ret = uwsgi_wait_read_req(wsgi_req); if (ret <= 0) return -1; goto retry; } else if (err == SSL_ERROR_SYSCALL) { if (errno != 0) uwsgi_error("uwsgi_proto_ssl_write()/SSL_write()"); } return -1; } #endif int uwsgi_proto_base_sendfile(struct wsgi_request * wsgi_req, int fd, size_t pos, size_t len) { ssize_t wlen = uwsgi_sendfile_do(wsgi_req->fd, fd, pos+wsgi_req->write_pos, len-wsgi_req->write_pos); if (wlen > 0) { wsgi_req->write_pos += wlen; if (wsgi_req->write_pos == len) { return UWSGI_OK; } return UWSGI_AGAIN; } if (wlen < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) { return UWSGI_AGAIN; } } return -1; } #ifdef UWSGI_SSL int uwsgi_proto_ssl_sendfile(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) { char buf[32768]; if (lseek(fd, pos+wsgi_req->write_pos, SEEK_SET) < 0) { uwsgi_error("lseek()"); return -1; } ssize_t rlen = read(fd, buf, UMIN(len-wsgi_req->write_pos, 32768)); if (rlen <= 0) return -1; char *rbuf = buf; while(rlen > 0) { size_t current_write_pos = wsgi_req->write_pos; int ret = uwsgi_proto_ssl_write(wsgi_req, rbuf, rlen); if (ret == UWSGI_OK) { break; } if (ret == UWSGI_AGAIN) { rbuf += (wsgi_req->write_pos - current_write_pos); rlen -= (wsgi_req->write_pos - current_write_pos); continue; } return -1; } if (wsgi_req->write_pos == len) { return UWSGI_OK; } return UWSGI_AGAIN; } #endif int uwsgi_proto_base_fix_headers(struct wsgi_request * wsgi_req) { return uwsgi_buffer_append(wsgi_req->headers, "\r\n", 2); } ssize_t uwsgi_proto_base_read_body(struct wsgi_request *wsgi_req, char *buf, size_t len) { if (wsgi_req->proto_parser_remains > 0) { size_t remains = UMIN(wsgi_req->proto_parser_remains, len); memcpy(buf, wsgi_req->proto_parser_remains_buf, remains); wsgi_req->proto_parser_remains -= remains; wsgi_req->proto_parser_remains_buf += remains; return remains; } return read(wsgi_req->fd, buf, len); } #ifdef UWSGI_SSL ssize_t uwsgi_proto_ssl_read_body(struct wsgi_request *wsgi_req, char *buf, size_t len) { int ret = -1; if (wsgi_req->proto_parser_remains > 0) { size_t remains = UMIN(wsgi_req->proto_parser_remains, len); memcpy(buf, wsgi_req->proto_parser_remains_buf, remains); wsgi_req->proto_parser_remains -= remains; wsgi_req->proto_parser_remains_buf += remains; return remains; } retry: ret = SSL_read(wsgi_req->ssl, buf, len); if (ret > 0) return ret; int err = SSL_get_error(wsgi_req->ssl, ret); if (err == SSL_ERROR_WANT_READ) { errno = EAGAIN; return -1; } else if (err == SSL_ERROR_WANT_WRITE) { ret = uwsgi_wait_write_req(wsgi_req); if (ret <= 0) return -1; goto retry; } else if (err == SSL_ERROR_SYSCALL) { if (errno != 0) uwsgi_error("uwsgi_proto_ssl_read_body()/SSL_read()"); } return -1; } #endif ssize_t uwsgi_proto_noop_read_body(struct wsgi_request *wsgi_req, char *buf, size_t len) { uwsgi_log_verbose("!!! the current protocol does not support request body !!!\n"); return -1; } void uwsgi_proto_raw_setup(struct uwsgi_socket *uwsgi_sock) { uwsgi_sock->proto = uwsgi_proto_raw_parser; uwsgi_sock->proto_accept = uwsgi_proto_base_accept; uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers; uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header; uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers; uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body; uwsgi_sock->proto_write = uwsgi_proto_base_write; uwsgi_sock->proto_write_headers = uwsgi_proto_base_write; uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile; uwsgi_sock->proto_close = uwsgi_proto_base_close; if (uwsgi.offload_threads > 0) uwsgi_sock->can_offload = 1; } uwsgi-2.0.29/proto/fastcgi.c000066400000000000000000000273221477626554400157230ustar00rootroot00000000000000/* async fastcgi protocol parser */ #include "uwsgi.h" extern struct uwsgi_server uwsgi; #define FCGI_END_REQUEST "\1\x06\0\1\0\0\0\0\1\3\0\1\0\x08\0\0\0\0\0\0\0\0\0\0" struct fcgi_record { uint8_t version; uint8_t type; uint8_t req1; uint8_t req0; uint8_t cl1; uint8_t cl0; uint8_t pad; uint8_t reserved; } __attribute__ ((__packed__)); // convert fastcgi params to uwsgi key/val int fastcgi_to_uwsgi(struct wsgi_request *wsgi_req, char *buf, size_t len) { size_t j; uint8_t octet; uint32_t keylen, vallen; for (j = 0; j < len; j++) { octet = (uint8_t) buf[j]; if (octet > 127) { if (j + 4 >= len) return -1; keylen = uwsgi_be32(&buf[j]) ^ 0x80000000; j += 4; } else { if (j + 1 >= len) return -1; keylen = octet; j++; } octet = (uint8_t) buf[j]; if (octet > 127) { if (j + 4 >= len) return -1; vallen = uwsgi_be32(&buf[j]) ^ 0x80000000; j += 4; } else { if (j + 1 >= len) return -1; vallen = octet; j++; } if (j + (keylen + vallen) > len) { return -1; } if (keylen > 0xffff || vallen > 0xffff) return -1; uint16_t pktsize = proto_base_add_uwsgi_var(wsgi_req, buf + j, keylen, buf + j + keylen, vallen); if (pktsize == 0) return -1; wsgi_req->uh->pktsize += pktsize; // -1 here as the for() will increment j again j += (keylen + vallen) - 1; } return 0; } /* each fastcgi packet is composed by a header and a body the parser rebuild a whole packet until it finds a 0 STDIN */ int uwsgi_proto_fastcgi_parser(struct wsgi_request *wsgi_req) { // allocate space for a fastcgi record if (!wsgi_req->proto_parser_buf) { wsgi_req->proto_parser_buf = uwsgi_malloc(uwsgi.buffer_size); wsgi_req->proto_parser_buf_size = uwsgi.buffer_size; } ssize_t len = read(wsgi_req->fd, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos, wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos); if (len > 0) { goto parse; } if (len < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) { return UWSGI_AGAIN; } uwsgi_error("uwsgi_proto_fastcgi_parser()"); return -1; } // mute on 0 len... if (wsgi_req->proto_parser_pos > 0) { uwsgi_error("uwsgi_proto_fastcgi_parser()"); } return -1; parse: wsgi_req->proto_parser_pos += len; // ok let's see what we need to do for (;;) { if (wsgi_req->proto_parser_pos >= sizeof(struct fcgi_record)) { struct fcgi_record *fr = (struct fcgi_record *) wsgi_req->proto_parser_buf; uint16_t fcgi_len = uwsgi_be16((char *) &fr->cl1); uint32_t fcgi_all_len = sizeof(struct fcgi_record) + fcgi_len + fr->pad; uint8_t fcgi_type = fr->type; uint8_t *sid = (uint8_t *) & wsgi_req->stream_id; sid[0] = fr->req0; sid[1] = fr->req1; // if STDIN, end of the loop if (fcgi_type == 5) { wsgi_req->uh->modifier1 = uwsgi.fastcgi_modifier1; wsgi_req->uh->modifier2 = uwsgi.fastcgi_modifier2; // does the request stream ended ? if (fcgi_len == 0) wsgi_req->proto_parser_eof = 1; return UWSGI_OK; } // if we have a full packet, parse it and reset the memory if (wsgi_req->proto_parser_pos >= fcgi_all_len) { // PARAMS ? (ignore other types) if (fcgi_type == 4) { if (fastcgi_to_uwsgi(wsgi_req, wsgi_req->proto_parser_buf + sizeof(struct fcgi_record), fcgi_len)) { return -1; } } memmove(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf + fcgi_all_len, wsgi_req->proto_parser_pos - fcgi_all_len); wsgi_req->proto_parser_pos -= fcgi_all_len; } else if (fcgi_all_len > wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos) { char *tmp_buf = realloc(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf_size + fcgi_all_len - (wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos)); if (!tmp_buf) { uwsgi_error("uwsgi_proto_fastcgi_parser()/realloc()"); return -1; } wsgi_req->proto_parser_buf = tmp_buf; wsgi_req->proto_parser_buf_size += (fcgi_all_len - (wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos)); break; } else { break; } } else { break; } } return UWSGI_AGAIN; } ssize_t uwsgi_proto_fastcgi_read_body(struct wsgi_request * wsgi_req, char *buf, size_t len) { int has_read = 0; if (wsgi_req->proto_parser_remains > 0) { size_t remains = UMIN(wsgi_req->proto_parser_remains, len); memcpy(buf, wsgi_req->proto_parser_remains_buf, remains); wsgi_req->proto_parser_remains -= remains; wsgi_req->proto_parser_remains_buf += remains; // we consumed all of the body, we can safely move the memory if (wsgi_req->proto_parser_remains == 0 && wsgi_req->proto_parser_move) { memmove(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_move, wsgi_req->proto_parser_pos); wsgi_req->proto_parser_move = 0; } return remains; } // if we already have seen eof, return 0 if (wsgi_req->proto_parser_eof) return 0; ssize_t rlen; for (;;) { if (wsgi_req->proto_parser_pos >= sizeof(struct fcgi_record)) { struct fcgi_record *fr = (struct fcgi_record *) wsgi_req->proto_parser_buf; uint16_t fcgi_len = uwsgi_be16((char *) &fr->cl1); uint32_t fcgi_all_len = sizeof(struct fcgi_record) + fcgi_len + fr->pad; uint8_t fcgi_type = fr->type; // if we have a full packet, parse it and reset the memory if (wsgi_req->proto_parser_pos >= fcgi_all_len) { // STDIN ? (ignore other types) if (fcgi_type == 5) { // EOF ? if (fcgi_len == 0) { wsgi_req->proto_parser_eof = 1; return 0; } // copy data to the buf size_t remains = UMIN(fcgi_len, len); memcpy(buf, wsgi_req->proto_parser_buf + sizeof(struct fcgi_record), remains); // copy remaining wsgi_req->proto_parser_remains = fcgi_len - remains; wsgi_req->proto_parser_remains_buf = wsgi_req->proto_parser_buf + sizeof(struct fcgi_record) + remains; // we consumed all of the body, we can safely move the memory if (wsgi_req->proto_parser_remains == 0) { memmove(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf + fcgi_all_len, wsgi_req->proto_parser_pos - fcgi_all_len); } else { // postpone memory move wsgi_req->proto_parser_move = fcgi_all_len; } wsgi_req->proto_parser_pos -= fcgi_all_len; return remains; } memmove(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf + fcgi_all_len, wsgi_req->proto_parser_pos - fcgi_all_len); wsgi_req->proto_parser_pos -= fcgi_all_len; } else if (fcgi_all_len > wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos) { char *tmp_buf = realloc(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf_size + fcgi_all_len - (wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos)); if (!tmp_buf) { uwsgi_error("uwsgi_proto_fastcgi_read_body()/realloc()"); return -1; } wsgi_req->proto_parser_buf = tmp_buf; wsgi_req->proto_parser_buf_size += fcgi_all_len - (wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos); } if (!has_read) goto gather; errno = EAGAIN; return -1; } else { gather: rlen = read(wsgi_req->fd, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos, wsgi_req->proto_parser_buf_size - wsgi_req->proto_parser_pos); if (rlen > 0) { has_read = 1; wsgi_req->proto_parser_pos += rlen; continue; } return rlen; } } return -1; } // write a STDOUT packet int uwsgi_proto_fastcgi_write(struct wsgi_request *wsgi_req, char *buf, size_t len) { // fastcgi packets are limited to 64k if (wsgi_req->proto_parser_status == 0) { uint16_t fcgi_len = UMIN(len - wsgi_req->write_pos, 0xffff); wsgi_req->proto_parser_status = fcgi_len; struct fcgi_record fr; fr.version = 1; fr.type = 6; uint8_t *sid = (uint8_t *) & wsgi_req->stream_id; fr.req1 = sid[1]; fr.req0 = sid[0]; fr.pad = 0; fr.reserved = 0; fr.cl0 = (uint8_t) (fcgi_len & 0xff); fr.cl1 = (uint8_t) ((fcgi_len >> 8) & 0xff); if (uwsgi_write_true_nb(wsgi_req->fd, (char *) &fr, sizeof(struct fcgi_record), uwsgi.socket_timeout)) { return -1; } } ssize_t wlen = write(wsgi_req->fd, buf + wsgi_req->write_pos, wsgi_req->proto_parser_status); if (wlen > 0) { wsgi_req->write_pos += wlen; wsgi_req->proto_parser_status -= wlen; if (wsgi_req->write_pos == len) { return UWSGI_OK; } return UWSGI_AGAIN; } if (wlen < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) { return UWSGI_AGAIN; } } return -1; } void uwsgi_proto_fastcgi_close(struct wsgi_request *wsgi_req) { // before sending the END_REQUEST and closing the connection we need to check for EOF if (!wsgi_req->proto_parser_eof) { // we use a custom tiny buffer, all the data will be discarded... char buf[4096]; for(;;) { ssize_t rlen = uwsgi_proto_fastcgi_read_body(wsgi_req, buf, 4096); if (rlen < 0) { if (uwsgi_is_again()) { int ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.socket_timeout); if (ret <= 0) goto end; continue; } goto end; } if (rlen == 0) break; } } // special case here, we run in void context, so we need to wait directly here char end_request[24]; memcpy(end_request, FCGI_END_REQUEST, 24); char *sid = (char *) &wsgi_req->stream_id; // update with request id end_request[2] = sid[1]; end_request[3] = sid[0]; end_request[10] = sid[1]; end_request[11] = sid[0]; (void) uwsgi_write_true_nb(wsgi_req->fd, end_request, 24, uwsgi.socket_timeout); end: uwsgi_proto_base_close(wsgi_req); } int uwsgi_proto_fastcgi_sendfile(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) { // fastcgi packets are limited to 64k if (wsgi_req->proto_parser_status == 0) { uint16_t fcgi_len = (uint16_t) UMIN(len - wsgi_req->write_pos, 0xffff); wsgi_req->proto_parser_status = fcgi_len; struct fcgi_record fr; fr.version = 1; fr.type = 6; uint8_t *sid = (uint8_t *) & wsgi_req->stream_id; fr.req1 = sid[1]; fr.req0 = sid[0]; fr.pad = 0; fr.reserved = 0; fr.cl0 = (uint8_t) (fcgi_len & 0xff); fr.cl1 = (uint8_t) ((fcgi_len >> 8) & 0xff); if (uwsgi_write_true_nb(wsgi_req->fd, (char *) &fr, sizeof(struct fcgi_record), uwsgi.socket_timeout)) { return -1; } } ssize_t wlen = uwsgi_sendfile_do(wsgi_req->fd, fd, pos + wsgi_req->write_pos, wsgi_req->proto_parser_status); if (wlen > 0) { wsgi_req->write_pos += wlen; wsgi_req->proto_parser_status -= wlen; if (wsgi_req->write_pos == len) { return UWSGI_OK; } return UWSGI_AGAIN; } if (wlen < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) { return UWSGI_AGAIN; } } return -1; } void uwsgi_proto_fastcgi_setup(struct uwsgi_socket *uwsgi_sock) { uwsgi_sock->proto = uwsgi_proto_fastcgi_parser; uwsgi_sock->proto_accept = uwsgi_proto_base_accept; uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_cgi_prepare_headers; uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header; uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers; uwsgi_sock->proto_read_body = uwsgi_proto_fastcgi_read_body; uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write; uwsgi_sock->proto_write_headers = uwsgi_proto_fastcgi_write; uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile; uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close; } void uwsgi_proto_fastcgi_nph_setup(struct uwsgi_socket *uwsgi_sock) { uwsgi_sock->proto = uwsgi_proto_fastcgi_parser; uwsgi_sock->proto_accept = uwsgi_proto_base_accept; uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers; uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header; uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers; uwsgi_sock->proto_read_body = uwsgi_proto_fastcgi_read_body; uwsgi_sock->proto_write = uwsgi_proto_fastcgi_write; uwsgi_sock->proto_write_headers = uwsgi_proto_fastcgi_write; uwsgi_sock->proto_sendfile = uwsgi_proto_fastcgi_sendfile; uwsgi_sock->proto_close = uwsgi_proto_fastcgi_close; } uwsgi-2.0.29/proto/http.c000066400000000000000000000710411477626554400152570ustar00rootroot00000000000000/* async http protocol parser */ #include "uwsgi.h" extern struct uwsgi_server uwsgi; static char * http_header_to_cgi(char *hh, size_t hhlen, size_t *keylen, size_t *vallen, int *has_prefix) { size_t i; char *val = hh; int status = 0; for (i = 0; i < hhlen; i++) { if (!status) { hh[i] = toupper((int) hh[i]); if (hh[i] == '-') hh[i] = '_'; if (hh[i] == ':') { status = 1; *keylen = i; } } else if (status == 1 && hh[i] != ' ') { status = 2; val += i; *vallen+=1; } else if (status == 2) { *vallen+=1; } } if (!(*keylen)) return NULL; if (uwsgi_strncmp("CONTENT_LENGTH", 14, hh, *keylen) && uwsgi_strncmp("CONTENT_TYPE", 12, hh, *keylen)) { *has_prefix = 0x02; } return val; } static uint16_t http_add_uwsgi_header(struct wsgi_request *wsgi_req, char *hh, size_t hhlen, char *hv, size_t hvlen, int has_prefix) { char *buffer = wsgi_req->buffer + wsgi_req->uh->pktsize; char *watermark = wsgi_req->buffer + uwsgi.buffer_size; char *ptr = buffer; size_t keylen = hhlen; if (has_prefix) keylen += 5; if (buffer + keylen + hvlen + 2 + 2 >= watermark) { if (has_prefix) { uwsgi_log("[WARNING] unable to add HTTP_%.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen-5, hh, hvlen, hv); } else { uwsgi_log("[WARNING] unable to add %.*s=%.*s to uwsgi packet, consider increasing buffer size\n", keylen, hh, hvlen, hv); } return 0; } *ptr++ = (uint8_t) (keylen & 0xff); *ptr++ = (uint8_t) ((keylen >> 8) & 0xff); if (has_prefix) { memcpy(ptr, "HTTP_", 5); ptr += 5; memcpy(ptr, hh, keylen - 5); ptr += (keylen - 5); } else { memcpy(ptr, hh, keylen); ptr += keylen; } *ptr++ = (uint8_t) (hvlen & 0xff); *ptr++ = (uint8_t) ((hvlen >> 8) & 0xff); memcpy(ptr, hv, hvlen); return 2 + keylen + 2 + hvlen; } char *proxy1_parse(char *ptr, char *watermark, char **src, uint16_t *src_len, char **dst, uint16_t *dst_len, char **src_port, uint16_t *src_port_len, char **dst_port, uint16_t *dst_port_len) { // check for PROXY header if (watermark - ptr > 6) { if (memcmp(ptr, "PROXY ", 6)) return ptr; } else { return ptr; } ptr+= 6; char *base = ptr; while (ptr < watermark) { if (*ptr == ' ') { ptr++; break; } else if (*ptr == '\n') { return ptr+1; } ptr++; } // SRC address base = ptr; while (ptr < watermark) { if (*ptr == ' ') { *src = base; *src_len = ptr - base; ptr++; break; } else if (*ptr == '\n') { return ptr+1; } ptr++; } // DST address base = ptr; while (ptr < watermark) { if (*ptr == ' ') { *dst = base; *dst_len = ptr - base; ptr++; break; } else if (*ptr == '\n') { return ptr+1; } ptr++; } // SRC port base = ptr; while (ptr < watermark) { if (*ptr == ' ') { *src_port = base; *src_port_len = ptr - base; ptr++; break; } else if (*ptr == '\n') { return ptr+1; } ptr++; } // DST port base = ptr; while (ptr < watermark) { if (*ptr == '\r') { *dst_port = base; *dst_port_len = ptr - base; ptr++; break; } else if (*ptr == '\n') { return ptr+1; } ptr++; } // check for \n while (ptr < watermark) { if (*ptr == '\n') return ptr+1; ptr++; } return ptr; } static int http_parse(struct wsgi_request *wsgi_req, char *watermark) { char *ptr = wsgi_req->proto_parser_buf; char *base = ptr; char *query_string = NULL; char ip[INET6_ADDRSTRLEN+1]; struct sockaddr *http_sa = (struct sockaddr *) &wsgi_req->client_addr; char *proxy_src = NULL; char *proxy_dst = NULL; char *proxy_src_port = NULL; char *proxy_dst_port = NULL; uint16_t proxy_src_len = 0; uint16_t proxy_dst_len = 0; uint16_t proxy_src_port_len = 0; uint16_t proxy_dst_port_len = 0; if (uwsgi.enable_proxy_protocol) { ptr = proxy1_parse(ptr, watermark, &proxy_src, &proxy_src_len, &proxy_dst, &proxy_dst_len, &proxy_src_port, &proxy_src_port_len, &proxy_dst_port, &proxy_dst_port_len); base = ptr; } // REQUEST_METHOD while (ptr < watermark) { if (*ptr == ' ') { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_METHOD", 14, base, ptr - base); ptr++; break; } ptr++; } // REQUEST_URI / PATH_INFO / QUERY_STRING base = ptr; while (ptr < watermark) { if (*ptr == '?' && !query_string) { if (watermark + (ptr - base) < (char *)(wsgi_req->proto_parser_buf + uwsgi.buffer_size)) { uint16_t path_info_len = ptr - base; char *path_info = uwsgi_malloc(path_info_len); http_url_decode(base, &path_info_len, path_info); wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "PATH_INFO", 9, path_info, path_info_len); free(path_info); } else { uwsgi_log("not enough space in wsgi_req http proto_parser_buf to decode PATH_INFO, consider tuning it with --buffer-size\n"); return -1; } query_string = ptr + 1; } else if (*ptr == ' ') { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, base, ptr - base); if (!query_string) { if (watermark + (ptr - base) < (char *)(wsgi_req->proto_parser_buf + uwsgi.buffer_size)) { uint16_t path_info_len = ptr - base; char *path_info = uwsgi_malloc(path_info_len); http_url_decode(base, &path_info_len, path_info); wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "PATH_INFO", 9, path_info, path_info_len); free(path_info); } else { uwsgi_log("not enough space in wsgi_req http proto_parser_buf to decode PATH_INFO, consider tuning it with --buffer-size\n"); return -1; } wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, "", 0); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, query_string, ptr - query_string); } ptr++; break; } ptr++; } // SERVER_PROTOCOL base = ptr; while (ptr < watermark) { if (*ptr == '\r') { if (ptr + 1 >= watermark) return -1 ; if (*(ptr + 1) != '\n') return -1; wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PROTOCOL", 15, base, ptr - base); ptr += 2; break; } ptr++; } // SCRIPT_NAME if (!uwsgi.manage_script_name) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SCRIPT_NAME", 11, "", 0); } // SERVER_NAME wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len); // SERVER_PORT / SERVER_ADDR if (proxy_dst) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_ADDR", 11, proxy_dst, proxy_dst_len); if (proxy_dst_port) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, proxy_dst_port, proxy_dst_port_len); } } else { char *server_port = strrchr(wsgi_req->socket->name, ':'); if (server_port) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, server_port+1, strlen(server_port+1)); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, "80", 2); } } // REMOTE_ADDR if (proxy_src) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, proxy_src, proxy_src_len); if (proxy_src_port) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_PORT", 11, proxy_src_port, proxy_src_port_len); } } else { // TODO log something useful for AF_UNIX sockets switch(http_sa->sa_family) { case AF_INET6: { struct sockaddr_in6* http_sin = &wsgi_req->client_addr.sin6; memset(ip, 0, sizeof(ip)); /* check if it's an IPv6-mapped-IPv4 address and, if so, * represent it as an IPv4 address * * these IPv6 macros are defined in POSIX.1-2001. */ if (IN6_IS_ADDR_V4MAPPED(&http_sin->sin6_addr)) { /* just grab the last 4 bytes and pretend they're * IPv4. None of the word/half-word convenience * functions are in POSIX, so just stick to .s6_addr */ union { unsigned char s6[4]; uint32_t s4; } addr_parts; memcpy(addr_parts.s6, &http_sin->sin6_addr.s6_addr[12], 4); uint32_t in4_addr = addr_parts.s4; if (inet_ntop(AF_INET, (void*)&in4_addr, ip, INET_ADDRSTRLEN)) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, ip, strlen(ip)); } else { uwsgi_error("inet_ntop()"); return -1; } } else { if (inet_ntop(AF_INET6, (void *) &http_sin->sin6_addr, ip, INET6_ADDRSTRLEN)) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, ip, strlen(ip)); } else { uwsgi_error("inet_ntop()"); return -1; } } break; } case AF_INET: default: { struct sockaddr_in* http_sin = &wsgi_req->client_addr.sin; memset(ip, 0, sizeof(ip)); if (inet_ntop(AF_INET, (void *) &http_sin->sin_addr, ip, INET_ADDRSTRLEN)) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, ip, strlen(ip)); } else { uwsgi_error("inet_ntop()"); return -1; } } break; } } if (wsgi_req->https_len > 0) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "HTTPS", 5, wsgi_req->https, wsgi_req->https_len); } //HEADERS base = ptr; struct uwsgi_string_list *headers = NULL, *usl = NULL; while (ptr < watermark) { if (*ptr == '\r') { if (ptr + 1 >= watermark) return -1; if (*(ptr + 1) != '\n') return -1; // multiline header ? if (ptr + 2 < watermark) { if (*(ptr + 2) == ' ' || *(ptr + 2) == '\t') { ptr += 2; continue; } } size_t key_len = 0, value_len = 0; int has_prefix = 0; // last line, do not waste time if (ptr - base == 0) break; char *value = http_header_to_cgi(base, ptr - base, &key_len, &value_len, &has_prefix); if (!value) { uwsgi_log_verbose("invalid HTTP request\n"); goto clear; } usl = uwsgi_string_list_has_item(headers, base, key_len); // there is already a HTTP header with the same name, let's merge them if (usl) { char *old_value = usl->custom_ptr; usl->custom_ptr = uwsgi_concat3n(old_value, (size_t) usl->custom, ", ", 2, value, value_len); usl->custom += 2 + value_len; if (usl->custom2 & 0x01) free(old_value); usl->custom2 |= 0x01; } else { // add an entry usl = uwsgi_string_new_list(&headers, NULL); usl->value = base; usl->len = key_len; usl->custom_ptr = value; usl->custom = value_len; usl->custom2 = has_prefix; } ptr++; base = ptr + 1; } ptr++; } usl = headers; int broken = 0; while(usl) { if (!broken) { uint16_t old_pktsize = wsgi_req->uh->pktsize; wsgi_req->uh->pktsize += http_add_uwsgi_header(wsgi_req, usl->value, usl->len, usl->custom_ptr, (size_t) usl->custom, usl->custom2 & 0x02); // if the packet remains unchanged, the buffer is full, mark the request as broken if (old_pktsize == wsgi_req->uh->pktsize) { broken = 1; } } if (usl->custom2 & 0x01) { free(usl->custom_ptr); } struct uwsgi_string_list *tmp_usl = usl; usl = usl->next; free(tmp_usl); } return broken; clear: usl = headers; while(usl) { if (usl->custom2 & 0x01) { free(usl->custom_ptr); } struct uwsgi_string_list *tmp_usl = usl; usl = usl->next; free(tmp_usl); } return -1; } static int uwsgi_proto_http_parser(struct wsgi_request *wsgi_req) { ssize_t j; char *ptr; // first round ? (wsgi_req->proto_parser_buf is freed at the end of the request) if (!wsgi_req->proto_parser_buf) { wsgi_req->proto_parser_buf = uwsgi_malloc(uwsgi.buffer_size); } if (uwsgi.buffer_size - wsgi_req->proto_parser_pos == 0) { uwsgi_log("invalid HTTP request size (max %u)...skip\n", uwsgi.buffer_size); return -1; } ssize_t len = read(wsgi_req->fd, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos, uwsgi.buffer_size - wsgi_req->proto_parser_pos); if (len > 0) { goto parse; } if (len < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) { return UWSGI_AGAIN; } uwsgi_error("uwsgi_proto_http_parser()"); return -1; } // mute on 0 len... if (wsgi_req->proto_parser_pos > 0) { uwsgi_log("uwsgi_proto_http_parser() -> client closed connection\n"); } return -1; parse: ptr = wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos; wsgi_req->proto_parser_pos += len; for (j = 0; j < len; j++) { if (*ptr == '\r' && (wsgi_req->proto_parser_status == 0 || wsgi_req->proto_parser_status == 2)) { wsgi_req->proto_parser_status++; } else if (*ptr == '\r') { wsgi_req->proto_parser_status = 1; } else if (*ptr == '\n' && wsgi_req->proto_parser_status == 1) { wsgi_req->proto_parser_status = 2; } else if (*ptr == '\n' && wsgi_req->proto_parser_status == 3) { ptr++; wsgi_req->proto_parser_remains = len - (j + 1); if (wsgi_req->proto_parser_remains > 0) { wsgi_req->proto_parser_remains_buf = (wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos) - wsgi_req->proto_parser_remains; } if (http_parse(wsgi_req, ptr)) return -1; wsgi_req->uh->modifier1 = uwsgi.http_modifier1; wsgi_req->uh->modifier2 = uwsgi.http_modifier2; return UWSGI_OK; } else { wsgi_req->proto_parser_status = 0; } ptr++; } return UWSGI_AGAIN; } static void uwsgi_httpize_var(char *buf, size_t len) { size_t i; int upper = 1; for(i=0;imethod, wsgi_req->method_len)) goto clear; if (uwsgi_buffer_append(ub, " ", 1)) goto clear; if (uri_len && uri) { if (uwsgi_buffer_append(ub, uri, uri_len)) goto clear; } else { if (uwsgi_buffer_append(ub, wsgi_req->uri, wsgi_req->uri_len)) goto clear; } if (uwsgi_buffer_append(ub, " ", 1)) goto clear; if (uwsgi_buffer_append(ub, wsgi_req->protocol, wsgi_req->protocol_len)) goto clear; if (uwsgi_buffer_append(ub, "\r\n", 2)) goto clear; int i; char *x_forwarded_for = NULL; size_t x_forwarded_for_len = 0; // start adding headers for(i=0;ivar_cnt;i++) { if (!uwsgi_starts_with(wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, "HTTP_", 5)) { char *header = wsgi_req->hvec[i].iov_base+5; size_t header_len = wsgi_req->hvec[i].iov_len-5; if (host && !uwsgi_strncmp(header, header_len, "HOST", 4)) goto next; if (!uwsgi_strncmp(header, header_len, "X_FORWARDED_FOR", 15)) { x_forwarded_for = wsgi_req->hvec[i+1].iov_base; x_forwarded_for_len = wsgi_req->hvec[i+1].iov_len; goto next; } if (uwsgi_buffer_append(ub, header, header_len)) goto clear; // transofmr uwsgi var to http header uwsgi_httpize_var((ub->buf+ub->pos) - header_len, header_len); if (uwsgi_buffer_append(ub, ": ", 2)) goto clear; if (uwsgi_buffer_append(ub, wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len)) goto clear; if (uwsgi_buffer_append(ub, "\r\n", 2)) goto clear; } next: i++; } // append custom Host (if needed) if (host) { if (uwsgi_buffer_append(ub, "Host: ", 6)) goto clear; if (uwsgi_buffer_append(ub, host, host_len)) goto clear; if (uwsgi_buffer_append(ub, "\r\n", 2)) goto clear; } if (wsgi_req->content_type_len > 0) { if (uwsgi_buffer_append(ub, "Content-Type: ", 14)) goto clear; if (uwsgi_buffer_append(ub, wsgi_req->content_type, wsgi_req->content_type_len)) goto clear; if (uwsgi_buffer_append(ub, "\r\n", 2)) goto clear; } if (wsgi_req->post_cl > 0) { if (uwsgi_buffer_append(ub, "Content-Length: ", 16)) goto clear; if (uwsgi_buffer_num64(ub, (int64_t) wsgi_req->post_cl)) goto clear; if (uwsgi_buffer_append(ub, "\r\n", 2)) goto clear; } // append required headers if (uwsgi_buffer_append(ub, "X-Forwarded-For: ", 17)) goto clear; if (x_forwarded_for_len > 0) { if (uwsgi_buffer_append(ub, x_forwarded_for, x_forwarded_for_len)) goto clear; if (uwsgi_buffer_append(ub, ", ", 2)) goto clear; } if (uwsgi_buffer_append(ub, wsgi_req->remote_addr, wsgi_req->remote_addr_len)) goto clear; if (uwsgi_buffer_append(ub, "\r\n\r\n", 4)) goto clear; return ub; clear: uwsgi_buffer_destroy(ub); return NULL; } struct uwsgi_buffer *uwsgi_to_http(struct wsgi_request *wsgi_req, char *host, uint16_t host_len, char *uri, uint16_t uri_len) { struct uwsgi_buffer *ub = uwsgi_buffer_new(4096); if (uwsgi_buffer_append(ub, wsgi_req->method, wsgi_req->method_len)) goto clear; if (uwsgi_buffer_append(ub, " ", 1)) goto clear; if (uri_len && uri) { if (uwsgi_buffer_append(ub, uri, uri_len)) goto clear; } else { if (uwsgi_buffer_append(ub, wsgi_req->uri, wsgi_req->uri_len)) goto clear; } // force HTTP/1.0 if (uwsgi_buffer_append(ub, " HTTP/1.0\r\n", 11)) goto clear; int i; char *x_forwarded_for = NULL; size_t x_forwarded_for_len = 0; // start adding headers for(i=0;ivar_cnt;i++) { if (!uwsgi_starts_with(wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len, "HTTP_", 5)) { char *header = wsgi_req->hvec[i].iov_base+5; size_t header_len = wsgi_req->hvec[i].iov_len-5; if (host && !uwsgi_strncmp(header, header_len, "HOST", 4)) goto next; // remove dangerous headers if (!uwsgi_strncmp(header, header_len, "CONNECTION", 10)) goto next; if (!uwsgi_strncmp(header, header_len, "KEEP_ALIVE", 10)) goto next; if (!uwsgi_strncmp(header, header_len, "TE", 2)) goto next; if (!uwsgi_strncmp(header, header_len, "TRAILER", 7)) goto next; if (!uwsgi_strncmp(header, header_len, "X_FORWARDED_FOR", 15)) { x_forwarded_for = wsgi_req->hvec[i+1].iov_base; x_forwarded_for_len = wsgi_req->hvec[i+1].iov_len; goto next; } if (uwsgi_buffer_append(ub, header, header_len)) goto clear; // transofmr uwsgi var to http header uwsgi_httpize_var((ub->buf+ub->pos) - header_len, header_len); if (uwsgi_buffer_append(ub, ": ", 2)) goto clear; if (uwsgi_buffer_append(ub, wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len)) goto clear; if (uwsgi_buffer_append(ub, "\r\n", 2)) goto clear; } next: i++; } // append custom Host (if needed) if (host) { if (uwsgi_buffer_append(ub, "Host: ", 6)) goto clear; if (uwsgi_buffer_append(ub, host, host_len)) goto clear; if (uwsgi_buffer_append(ub, "\r\n", 2)) goto clear; } if (wsgi_req->content_type_len > 0) { if (uwsgi_buffer_append(ub, "Content-Type: ", 14)) goto clear; if (uwsgi_buffer_append(ub, wsgi_req->content_type, wsgi_req->content_type_len)) goto clear; if (uwsgi_buffer_append(ub, "\r\n", 2)) goto clear; } if (wsgi_req->post_cl > 0) { if (uwsgi_buffer_append(ub, "Content-Length: ", 16)) goto clear; if (uwsgi_buffer_num64(ub, (int64_t) wsgi_req->post_cl)) goto clear; if (uwsgi_buffer_append(ub, "\r\n", 2)) goto clear; } // append required headers if (uwsgi_buffer_append(ub, "Connection: close\r\n", 19)) goto clear; if (uwsgi_buffer_append(ub, "X-Forwarded-For: ", 17)) goto clear; if (x_forwarded_for_len > 0) { if (uwsgi_buffer_append(ub, x_forwarded_for, x_forwarded_for_len)) goto clear; if (uwsgi_buffer_append(ub, ", ", 2)) goto clear; } if (uwsgi_buffer_append(ub, wsgi_req->remote_addr, wsgi_req->remote_addr_len)) goto clear; if (uwsgi_buffer_append(ub, "\r\n\r\n", 4)) goto clear; return ub; clear: uwsgi_buffer_destroy(ub); return NULL; } int uwsgi_is_full_http(struct uwsgi_buffer *ub) { size_t i; int status = 0; for(i=0;ipos;i++) { switch(status) { // \r case 0: if (ub->buf[i] == '\r') status = 1; break; // \r\n case 1: if (ub->buf[i] == '\n') { status = 2; break; } status = 0; break; // \r\n\r case 2: if (ub->buf[i] == '\r') { status = 3; break; } status = 0; break; // \r\n\r\n case 3: if (ub->buf[i] == '\n') { return 1; } status = 0; break; default: status = 0; break; } } return 0; } void uwsgi_proto_http_setup(struct uwsgi_socket *uwsgi_sock) { uwsgi_sock->proto = uwsgi_proto_http_parser; uwsgi_sock->proto_accept = uwsgi_proto_base_accept; uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers; uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header; uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers; uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body; uwsgi_sock->proto_write = uwsgi_proto_base_write; uwsgi_sock->proto_writev = uwsgi_proto_base_writev; uwsgi_sock->proto_write_headers = uwsgi_proto_base_write; uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile; uwsgi_sock->proto_close = uwsgi_proto_base_close; if (uwsgi.offload_threads > 0) uwsgi_sock->can_offload = 1; } /* close the connection on errors, incomplete parsing, HTTP/1.0, pipelined or offloaded requests NOTE: Connection: close is not honoured */ void uwsgi_proto_http11_close(struct wsgi_request *wsgi_req) { // check for errors or incomplete packets if (wsgi_req->write_errors || wsgi_req->proto_parser_status != 3 || wsgi_req->proto_parser_remains > 0 || wsgi_req->post_pos < wsgi_req->post_cl || wsgi_req->via == UWSGI_VIA_OFFLOAD || !uwsgi_strncmp("HTTP/1.0", 8, wsgi_req->protocol, wsgi_req->protocol_len)) { close(wsgi_req->fd); wsgi_req->socket->retry[wsgi_req->async_id] = 0; wsgi_req->socket->fd_threads[wsgi_req->async_id] = -1; } else { wsgi_req->socket->retry[wsgi_req->async_id] = 1; wsgi_req->socket->fd_threads[wsgi_req->async_id] = wsgi_req->fd; } } int uwsgi_proto_http11_accept(struct wsgi_request *wsgi_req, int fd) { if (wsgi_req->socket->retry[wsgi_req->async_id]) { wsgi_req->fd = wsgi_req->socket->fd_threads[wsgi_req->async_id]; int ret = uwsgi_wait_read_req(wsgi_req); if (ret <= 0) { close(wsgi_req->fd); wsgi_req->socket->retry[wsgi_req->async_id] = 0; wsgi_req->socket->fd_threads[wsgi_req->async_id] = -1; return -1; } return wsgi_req->socket->fd_threads[wsgi_req->async_id]; } return uwsgi_proto_base_accept(wsgi_req, fd); } void uwsgi_proto_http11_setup(struct uwsgi_socket *uwsgi_sock) { uwsgi_sock->proto = uwsgi_proto_http_parser; uwsgi_sock->proto_accept = uwsgi_proto_http11_accept; uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers; uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header; uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers; uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body; uwsgi_sock->proto_write = uwsgi_proto_base_write; uwsgi_sock->proto_writev = uwsgi_proto_base_writev; uwsgi_sock->proto_write_headers = uwsgi_proto_base_write; uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile; uwsgi_sock->proto_close = uwsgi_proto_http11_close; if (uwsgi.offload_threads > 0) uwsgi_sock->can_offload = 1; uwsgi_sock->fd_threads = uwsgi_malloc(sizeof(int) * uwsgi.cores); memset(uwsgi_sock->fd_threads, -1, sizeof(int) * uwsgi.cores); uwsgi_sock->retry = uwsgi_calloc(sizeof(int) * uwsgi.cores); uwsgi.is_et = 1; } #ifdef UWSGI_SSL static int uwsgi_proto_https_parser(struct wsgi_request *wsgi_req) { ssize_t j; char *ptr; int len = -1; // first round ? (wsgi_req->proto_parser_buf is freed at the end of the request) if (!wsgi_req->proto_parser_buf) { wsgi_req->proto_parser_buf = uwsgi_malloc(uwsgi.buffer_size); } if (uwsgi.buffer_size - wsgi_req->proto_parser_pos == 0) { uwsgi_log("invalid HTTPS request size (max %u)...skip\n", uwsgi.buffer_size); return -1; } retry: len = SSL_read(wsgi_req->ssl, wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos, uwsgi.buffer_size - wsgi_req->proto_parser_pos); if (len > 0) { goto parse; } if (len == 0) goto empty; int err = SSL_get_error(wsgi_req->ssl, len); if (err == SSL_ERROR_WANT_READ) { return UWSGI_AGAIN; } else if (err == SSL_ERROR_WANT_WRITE) { int ret = uwsgi_wait_write_req(wsgi_req); if (ret <= 0) return -1; goto retry; } else if (err == SSL_ERROR_SYSCALL) { if (errno != 0) uwsgi_error("uwsgi_proto_https_parser()/SSL_read()"); } return -1; empty: // mute on 0 len... if (wsgi_req->proto_parser_pos > 0) { uwsgi_log("uwsgi_proto_https_parser() -> client closed connection"); } return -1; parse: ptr = wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos; wsgi_req->proto_parser_pos += len; for (j = 0; j < len; j++) { if (*ptr == '\r' && (wsgi_req->proto_parser_status == 0 || wsgi_req->proto_parser_status == 2)) { wsgi_req->proto_parser_status++; } else if (*ptr == '\r') { wsgi_req->proto_parser_status = 1; } else if (*ptr == '\n' && wsgi_req->proto_parser_status == 1) { wsgi_req->proto_parser_status = 2; } else if (*ptr == '\n' && wsgi_req->proto_parser_status == 3) { ptr++; wsgi_req->proto_parser_remains = len - (j + 1); if (wsgi_req->proto_parser_remains > 0) { wsgi_req->proto_parser_remains_buf = (wsgi_req->proto_parser_buf + wsgi_req->proto_parser_pos) - wsgi_req->proto_parser_remains; } wsgi_req->https = "on"; wsgi_req->https_len = 2; if (http_parse(wsgi_req, ptr)) return -1; wsgi_req->uh->modifier1 = uwsgi.https_modifier1; wsgi_req->uh->modifier2 = uwsgi.https_modifier2; return UWSGI_OK; } else { wsgi_req->proto_parser_status = 0; } ptr++; } return UWSGI_AGAIN; } void uwsgi_proto_https_setup(struct uwsgi_socket *uwsgi_sock) { uwsgi_sock->proto = uwsgi_proto_https_parser; uwsgi_sock->proto_accept = uwsgi_proto_ssl_accept; uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers; uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header; uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers; uwsgi_sock->proto_read_body = uwsgi_proto_ssl_read_body; uwsgi_sock->proto_write = uwsgi_proto_ssl_write; uwsgi_sock->proto_write_headers = uwsgi_proto_ssl_write; uwsgi_sock->proto_sendfile = uwsgi_proto_ssl_sendfile; uwsgi_sock->proto_close = uwsgi_proto_ssl_close; } #endif uwsgi-2.0.29/proto/puwsgi.c000066400000000000000000000077721477626554400156300ustar00rootroot00000000000000/* async uwsgi protocol parser */ #include "uwsgi.h" extern struct uwsgi_server uwsgi; /* perfect framing is required in persistent mode, so we need at least 2 syscall to assemble a uwsgi header: 4 bytes header + payload increase write_errors on error to force socket close */ int uwsgi_proto_puwsgi_parser(struct wsgi_request *wsgi_req) { ssize_t len; char *ptr = (char *) wsgi_req->uh; if (wsgi_req->proto_parser_pos < 4) { len = read(wsgi_req->fd, ptr + wsgi_req->proto_parser_pos, 4 - wsgi_req->proto_parser_pos); if (len > 0) { wsgi_req->proto_parser_pos += len; if (wsgi_req->proto_parser_pos == 4) { #ifdef __BIG_ENDIAN__ wsgi_req->uh->pktsize = uwsgi_swap16(wsgi_req->uh->pktsize); #endif if (wsgi_req->uh->pktsize > uwsgi.buffer_size) { uwsgi_log("invalid request block size: %u (max %u)...skip\n", wsgi_req->uh->pktsize, uwsgi.buffer_size); wsgi_req->write_errors++; return -1; } } return UWSGI_AGAIN; } goto negative; } len = read(wsgi_req->fd, ptr + wsgi_req->proto_parser_pos, wsgi_req->uh->pktsize - (wsgi_req->proto_parser_pos-4)); if (len > 0) { wsgi_req->proto_parser_pos += len; if ((wsgi_req->proto_parser_pos-4) == wsgi_req->uh->pktsize) { return UWSGI_OK; } return UWSGI_AGAIN; } negative: if (len < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) { return UWSGI_AGAIN; } uwsgi_error("uwsgi_proto_uwsgi_parser()"); wsgi_req->write_errors++; return -1; } // 0 len if (wsgi_req->proto_parser_pos > 0) { uwsgi_error("uwsgi_proto_uwsgi_parser()"); } wsgi_req->write_errors++; return -1; } /* close the connection on errors, otherwise force edge triggering */ void uwsgi_proto_puwsgi_close(struct wsgi_request *wsgi_req) { // check for errors or incomplete packets if (wsgi_req->write_errors || (size_t) (wsgi_req->uh->pktsize + 4) != wsgi_req->proto_parser_pos) { close(wsgi_req->fd); wsgi_req->socket->retry[wsgi_req->async_id] = 0; wsgi_req->socket->fd_threads[wsgi_req->async_id] = -1; } else { wsgi_req->socket->retry[wsgi_req->async_id] = 1; wsgi_req->socket->fd_threads[wsgi_req->async_id] = wsgi_req->fd; } } int uwsgi_proto_puwsgi_accept(struct wsgi_request *wsgi_req, int fd) { if (wsgi_req->socket->retry[wsgi_req->async_id]) { wsgi_req->fd = wsgi_req->socket->fd_threads[wsgi_req->async_id]; int ret = uwsgi_wait_read_req(wsgi_req); if (ret <= 0) { close(wsgi_req->fd); wsgi_req->socket->retry[wsgi_req->async_id] = 0; wsgi_req->socket->fd_threads[wsgi_req->async_id] = -1; return -1; } return wsgi_req->socket->fd_threads[wsgi_req->async_id]; } return uwsgi_proto_base_accept(wsgi_req, fd); } void uwsgi_proto_puwsgi_setup(struct uwsgi_socket *uwsgi_sock) { uwsgi_sock->proto = uwsgi_proto_puwsgi_parser; uwsgi_sock->proto_accept = uwsgi_proto_puwsgi_accept; uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers; uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header; uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers; uwsgi_sock->proto_read_body = uwsgi_proto_noop_read_body; uwsgi_sock->proto_write = uwsgi_proto_base_write; uwsgi_sock->proto_writev = uwsgi_proto_base_writev; uwsgi_sock->proto_write_headers = uwsgi_proto_base_write; uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile; uwsgi_sock->proto_close = uwsgi_proto_puwsgi_close; uwsgi_sock->fd_threads = uwsgi_malloc(sizeof(int) * uwsgi.cores); memset(uwsgi_sock->fd_threads, -1, sizeof(int) * uwsgi.cores); uwsgi_sock->retry = uwsgi_calloc(sizeof(int) * uwsgi.cores); uwsgi.is_et = 1; } uwsgi-2.0.29/proto/scgi.c000066400000000000000000000105071477626554400152250ustar00rootroot00000000000000/* async SCGI protocol parser */ #include "uwsgi.h" extern struct uwsgi_server uwsgi; static int scgi_parse(struct wsgi_request *wsgi_req) { char *buf = wsgi_req->proto_parser_buf; size_t len = wsgi_req->proto_parser_pos; size_t i; size_t scgi_len = 0; for(i=0;i len) { return 0; } i++; size_t vars = i; char *key = buf + i; size_t keylen = 0; char *value = NULL; size_t vallen = 0; for(i=vars;i 0 && value == NULL) { value = buf + i; } if (buf[i] == 0) { if (value) { vallen = (buf+i) - value; uint16_t pktsize = proto_base_add_uwsgi_var(wsgi_req, key, keylen, value, vallen); if (pktsize == 0) return -1; wsgi_req->uh->pktsize += pktsize; key = NULL; value = NULL; keylen = 0; vallen = 0; } else { keylen = (buf+i) - key; value = NULL; } } } if (buf[i] == ',') { if (len > i+1) { wsgi_req->proto_parser_remains = len-(i+1); wsgi_req->proto_parser_remains_buf = buf + i + 1; } return 1; } return -1; } int uwsgi_proto_scgi_parser(struct wsgi_request *wsgi_req) { // first round ? (wsgi_req->proto_parser_buf is freed at the end of the request) if (!wsgi_req->proto_parser_buf) { wsgi_req->proto_parser_buf = uwsgi_malloc(uwsgi.buffer_size); } if (uwsgi.buffer_size - wsgi_req->proto_parser_pos == 0) { uwsgi_log("invalid SCGI request size (max %u)...skip\n", uwsgi.buffer_size); return -1; } char *ptr = wsgi_req->proto_parser_buf; ssize_t len = read(wsgi_req->fd, ptr + wsgi_req->proto_parser_pos, uwsgi.buffer_size - wsgi_req->proto_parser_pos); if (len > 0) { wsgi_req->proto_parser_pos += len; int ret = scgi_parse(wsgi_req); if (ret > 0) { wsgi_req->uh->modifier1 = uwsgi.scgi_modifier1; wsgi_req->uh->modifier2 = uwsgi.scgi_modifier2; return UWSGI_OK; } if (ret == 0) return UWSGI_AGAIN; return -1; } if (len < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) { return UWSGI_AGAIN; } uwsgi_error("uwsgi_proto_scgi_parser()"); return -1; } // 0 len if (wsgi_req->proto_parser_pos > 0) { uwsgi_error("uwsgi_proto_scgi_parser()"); } return -1; } void uwsgi_proto_scgi_setup(struct uwsgi_socket *uwsgi_sock) { uwsgi_sock->proto = uwsgi_proto_scgi_parser; uwsgi_sock->proto_accept = uwsgi_proto_base_accept; uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_cgi_prepare_headers; uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header; uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers; uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body; uwsgi_sock->proto_write = uwsgi_proto_base_write; uwsgi_sock->proto_writev = uwsgi_proto_base_writev; uwsgi_sock->proto_write_headers = uwsgi_proto_base_write; uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile; uwsgi_sock->proto_close = uwsgi_proto_base_close; } void uwsgi_proto_scgi_nph_setup(struct uwsgi_socket *uwsgi_sock) { uwsgi_sock->proto = uwsgi_proto_scgi_parser; uwsgi_sock->proto_accept = uwsgi_proto_base_accept; uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers; uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header; uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers; uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body; uwsgi_sock->proto_write = uwsgi_proto_base_write; uwsgi_sock->proto_writev = uwsgi_proto_base_writev; uwsgi_sock->proto_write_headers = uwsgi_proto_base_write; uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile; uwsgi_sock->proto_close = uwsgi_proto_base_close; } uwsgi-2.0.29/proto/uwsgi.c000066400000000000000000000174321477626554400154420ustar00rootroot00000000000000/* async uwsgi protocol parser */ #include "uwsgi.h" extern struct uwsgi_server uwsgi; static int uwsgi_proto_uwsgi_parser(struct wsgi_request *wsgi_req) { char *ptr = (char *) wsgi_req->uh; ssize_t len = read(wsgi_req->fd, ptr + wsgi_req->proto_parser_pos, (uwsgi.buffer_size + 4) - wsgi_req->proto_parser_pos); if (len > 0) { wsgi_req->proto_parser_pos += len; if (wsgi_req->proto_parser_pos >= 4) { #ifdef __BIG_ENDIAN__ wsgi_req->uh->pktsize = uwsgi_swap16(wsgi_req->uh->pktsize); #endif if ((wsgi_req->proto_parser_pos - 4) == wsgi_req->uh->pktsize) { return UWSGI_OK; } if ((wsgi_req->proto_parser_pos - 4) > wsgi_req->uh->pktsize) { wsgi_req->proto_parser_remains = wsgi_req->proto_parser_pos - (4 + wsgi_req->uh->pktsize); wsgi_req->proto_parser_remains_buf = wsgi_req->buffer + wsgi_req->uh->pktsize; return UWSGI_OK; } if (wsgi_req->uh->pktsize > uwsgi.buffer_size) { uwsgi_log("invalid request block size: %u (max %u)...skip\n", wsgi_req->uh->pktsize, uwsgi.buffer_size); return -1; } } return UWSGI_AGAIN; } if (len < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) { return UWSGI_AGAIN; } uwsgi_error("uwsgi_proto_uwsgi_parser()"); return -1; } // 0 len if (wsgi_req->proto_parser_pos > 0) { uwsgi_error("uwsgi_proto_uwsgi_parser()"); } return -1; } #ifdef UWSGI_SSL static int uwsgi_proto_suwsgi_parser(struct wsgi_request *wsgi_req) { char *ptr = (char *) wsgi_req->uh; int len = -1; retry: len = SSL_read(wsgi_req->ssl, ptr + wsgi_req->proto_parser_pos, (uwsgi.buffer_size + 4) - wsgi_req->proto_parser_pos); if (len > 0) { wsgi_req->proto_parser_pos += len; if (wsgi_req->proto_parser_pos >= 4) { #ifdef __BIG_ENDIAN__ wsgi_req->uh->pktsize = uwsgi_swap16(wsgi_req->uh->pktsize); #endif if ((wsgi_req->proto_parser_pos - 4) == wsgi_req->uh->pktsize) { return UWSGI_OK; } if ((wsgi_req->proto_parser_pos - 4) > wsgi_req->uh->pktsize) { wsgi_req->proto_parser_remains = wsgi_req->proto_parser_pos - (4 + wsgi_req->uh->pktsize); wsgi_req->proto_parser_remains_buf = wsgi_req->buffer + wsgi_req->uh->pktsize; return UWSGI_OK; } if (wsgi_req->uh->pktsize > uwsgi.buffer_size) { uwsgi_log("invalid request block size: %u (max %u)...skip\n", wsgi_req->uh->pktsize, uwsgi.buffer_size); return -1; } } return UWSGI_AGAIN; } else if (len == 0) goto empty; int err = SSL_get_error(wsgi_req->ssl, len); if (err == SSL_ERROR_WANT_READ) { return UWSGI_AGAIN; } else if (err == SSL_ERROR_WANT_WRITE) { int ret = uwsgi_wait_write_req(wsgi_req); if (ret <= 0) return -1; goto retry; } else if (err == SSL_ERROR_SYSCALL) { if (errno != 0) uwsgi_error("uwsgi_proto_suwsgi_parser()/SSL_read()"); } return -1; empty: // 0 len if (wsgi_req->proto_parser_pos > 0) { uwsgi_error("uwsgi_proto_uwsgi_parser()"); } return -1; } #endif /* int uwsgi_proto_uwsgi_parser_unix(struct wsgi_request *wsgi_req) { uint8_t *hdr_buf = (uint8_t *) & wsgi_req->uh; ssize_t len; struct iovec iov[1]; struct cmsghdr *cmsg; if (wsgi_req->proto_parser_status == PROTO_STATUS_RECV_HDR) { if (wsgi_req->proto_parser_pos > 0) { len = read(wsgi_req->fd, hdr_buf + wsgi_req->proto_parser_pos, 4 - wsgi_req->proto_parser_pos); } else { iov[0].iov_base = hdr_buf; iov[0].iov_len = 4; wsgi_req->msg.msg_name = NULL; wsgi_req->msg.msg_namelen = 0; wsgi_req->msg.msg_iov = iov; wsgi_req->msg.msg_iovlen = 1; wsgi_req->msg.msg_control = &wsgi_req->msg_control; wsgi_req->msg.msg_controllen = sizeof(wsgi_req->msg_control); wsgi_req->msg.msg_flags = 0; len = recvmsg(wsgi_req->fd, &wsgi_req->msg, 0); } if (len <= 0) { if (len < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) { return UWSGI_AGAIN; } } // ignore empty packets if (len == 0 && wsgi_req->proto_parser_pos == 0) return -3; uwsgi_error(wsgi_req->proto_parser_pos > 0 ? "read()" : "recvmsg()"); return -1; } wsgi_req->proto_parser_pos += len; // header ready ? if (wsgi_req->proto_parser_pos == 4) { wsgi_req->proto_parser_status = PROTO_STATUS_RECV_VARS; wsgi_req->proto_parser_pos = 0; #ifdef __BIG_ENDIAN__ wsgi_req->uh->pktsize = uwsgi_swap16(wsgi_req->uh->pktsize); #endif #ifdef UWSGI_DEBUG uwsgi_debug("uwsgi payload size: %d (0x%X) modifier1: %d modifier2: %d\n", wsgi_req->uh.pktsize, wsgi_req->uh.pktsize, wsgi_req->uh.modifier1, wsgi_req->uh.modifier2); #endif if (wsgi_req->uh->pktsize > uwsgi.buffer_size) { return -1; } if (!wsgi_req->uh->pktsize) return UWSGI_OK; } return UWSGI_AGAIN; } else if (wsgi_req->proto_parser_status == PROTO_STATUS_RECV_VARS) { len = read(wsgi_req->fd, wsgi_req->buffer + wsgi_req->proto_parser_pos, wsgi_req->uh->pktsize - wsgi_req->proto_parser_pos); if (len <= 0) { uwsgi_error("read()"); return -1; } wsgi_req->proto_parser_pos += len; // body ready ? if (wsgi_req->proto_parser_pos >= wsgi_req->uh->pktsize) { // older OSX versions make mess with CMSG_FIRSTHDR #ifdef __APPLE__ if (!wsgi_req->msg.msg_controllen) return UWSGI_OK; #endif if (uwsgi.no_fd_passing) return UWSGI_OK; cmsg = CMSG_FIRSTHDR(&wsgi_req->msg); while (cmsg != NULL) { if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type && SCM_RIGHTS) { // upgrade connection to the new socket #ifdef UWSGI_DEBUG uwsgi_log("upgrading fd %d to ", wsgi_req->fd); #endif close(wsgi_req->fd); memcpy(&wsgi_req->fd, CMSG_DATA(cmsg), sizeof(int)); #ifdef UWSGI_DEBUG uwsgi_log("%d\n", wsgi_req->fd); #endif } cmsg = CMSG_NXTHDR(&wsgi_req->msg, cmsg); } return UWSGI_OK; } return UWSGI_AGAIN; } // never here return -1; } */ void uwsgi_proto_uwsgi_setup(struct uwsgi_socket *uwsgi_sock) { uwsgi_sock->proto = uwsgi_proto_uwsgi_parser; uwsgi_sock->proto_accept = uwsgi_proto_base_accept; uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers; uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header; uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers; uwsgi_sock->proto_read_body = uwsgi_proto_base_read_body; uwsgi_sock->proto_write = uwsgi_proto_base_write; uwsgi_sock->proto_writev = uwsgi_proto_base_writev; uwsgi_sock->proto_write_headers = uwsgi_proto_base_write; uwsgi_sock->proto_sendfile = uwsgi_proto_base_sendfile; uwsgi_sock->proto_close = uwsgi_proto_base_close; if (uwsgi.offload_threads > 0) uwsgi_sock->can_offload = 1; } #ifdef UWSGI_SSL void uwsgi_proto_suwsgi_setup(struct uwsgi_socket *uwsgi_sock) { uwsgi_sock->proto = uwsgi_proto_suwsgi_parser; uwsgi_sock->proto_accept = uwsgi_proto_ssl_accept; uwsgi_sock->proto_prepare_headers = uwsgi_proto_base_prepare_headers; uwsgi_sock->proto_add_header = uwsgi_proto_base_add_header; uwsgi_sock->proto_fix_headers = uwsgi_proto_base_fix_headers; uwsgi_sock->proto_read_body = uwsgi_proto_ssl_read_body; uwsgi_sock->proto_write = uwsgi_proto_ssl_write; uwsgi_sock->proto_write_headers = uwsgi_proto_ssl_write; uwsgi_sock->proto_sendfile = uwsgi_proto_ssl_sendfile; uwsgi_sock->proto_close = uwsgi_proto_ssl_close; if (uwsgi.offload_threads > 0) uwsgi_sock->can_offload = 1; } #endif uwsgi-2.0.29/setup.cpyext.py000066400000000000000000000072011477626554400160130ustar00rootroot00000000000000# encoding: utf-8 """ This is a hack allowing you installing uWSGI and uwsgidecorators via pip and easy_install since 1.9.11 it automatically detects pypy """ import os import sys import errno import shlex import uwsgiconfig from setuptools import setup, Extension from setuptools.command.build_ext import build_ext class uWSGIBuildExt(build_ext): UWSGI_NAME = 'uwsgi' UWSGI_PLUGIN = 'pyuwsgi' def build_extensions(self): self.uwsgi_setup() # XXX: needs uwsgiconfig fix self.uwsgi_build() if 'UWSGI_USE_DISTUTILS' not in os.environ: # XXX: needs uwsgiconfig fix # uwsgiconfig.build_uwsgi(self.uwsgi_config) return else: # XXX: needs uwsgiconfig fix os.unlink(self.uwsgi_config.get('bin_name')) # FIXME: else build fails :( for baddie in set(self.compiler.compiler_so) & set(('-Wstrict-prototypes',)): self.compiler.compiler_so.remove(baddie) build_ext.build_extensions(self) def uwsgi_setup(self): default = 'pypy' if '__pypy__' in sys.builtin_module_names else 'default' profile = os.environ.get('UWSGI_PROFILE') or 'buildconf/%s.ini' % default if not profile.endswith('.ini'): profile = profile + '.ini' if '/' not in profile: profile = 'buildconf/' + profile # FIXME: update uwsgiconfig to properly set _EVERYTHING_! config = uwsgiconfig.uConf(profile) # insert in the beginning so UWSGI_PYTHON_NOLIB is exported # before the python plugin compiles ep = config.get('embedded_plugins').split(',') if self.UWSGI_PLUGIN in ep: ep.remove(self.UWSGI_PLUGIN) ep.insert(0, self.UWSGI_PLUGIN) config.set('embedded_plugins', ','.join(ep)) config.set('as_shared_library', 'true') config.set('bin_name', self.get_ext_fullpath(self.UWSGI_NAME)) try: os.makedirs(os.path.dirname(config.get('bin_name'))) except OSError as e: if e.errno != errno.EEXIST: raise self.uwsgi_profile = profile self.uwsgi_config = config def uwsgi_build(self): uwsgiconfig.build_uwsgi(self.uwsgi_config) # XXX: merge uwsgi_setup (see other comments) for ext in self.extensions: if ext.name == self.UWSGI_NAME: ext.sources = [s + '.c' for s in self.uwsgi_config.gcc_list] ext.library_dirs = self.uwsgi_config.include_path[:] ext.libraries = list() ext.extra_compile_args = list() for x in uwsgiconfig.uniq_warnings( self.uwsgi_config.ldflags + self.uwsgi_config.libs, ): for y in shlex.split(x): if y.startswith('-l'): ext.libraries.append(y[2:]) elif y.startswith('-L'): ext.library_dirs.append(y[2:]) for x in self.uwsgi_config.cflags: for y in shlex.split(x): if y: ext.extra_compile_args.append(y) setup( name='uWSGI', license='GPL2', version=uwsgiconfig.uwsgi_version, author='Unbit', author_email='info@unbit.it', description='The uWSGI server', cmdclass={ 'build_ext': uWSGIBuildExt, }, py_modules=[ 'uwsgidecorators', ], ext_modules=[ Extension(uWSGIBuildExt.UWSGI_NAME, sources=[]), ], entry_points={ 'console_scripts': ['uwsgi=%s:run' % uWSGIBuildExt.UWSGI_NAME], }, ) uwsgi-2.0.29/setup.py000066400000000000000000000101041477626554400144740ustar00rootroot00000000000000import os import sys import uwsgiconfig as uc import shutil from setuptools import setup from setuptools.dist import Distribution from setuptools.command.install import install from setuptools.command.install_lib import install_lib from setuptools.command.build_ext import build_ext try: from wheel.bdist_wheel import bdist_wheel HAS_WHEEL = True except ImportError: HAS_WHEEL = False """ This is a hack allowing you installing uWSGI and uwsgidecorators via pip and easy_install since 1.9.11 it automatically detects pypy """ uwsgi_compiled = False def get_profile(): is_pypy = False try: import __pypy__ is_pypy = True except ImportError: pass if is_pypy: profile = os.environ.get('UWSGI_PROFILE', 'buildconf/pypy.ini') else: profile = os.environ.get('UWSGI_PROFILE', 'buildconf/default.ini') if not profile.endswith('.ini'): profile = "%s.ini" % profile if not '/' in profile: profile = "buildconf/%s" % profile return profile def patch_bin_path(cmd, conf): bin_name = conf.get('bin_name') if not os.path.isabs(bin_name): print('Patching "bin_name" to properly install_scripts dir') try: if not os.path.exists(cmd.install_scripts): os.makedirs(cmd.install_scripts) conf.set('bin_name', os.path.join(cmd.install_scripts, conf.get('bin_name'))) except: conf.set('bin_name', sys.prefix + '/bin/' + bin_name) class uWSGIBuilder(build_ext): def run(self): global uwsgi_compiled if not uwsgi_compiled: conf = uc.uConf(get_profile()) patch_bin_path(self, conf) uc.build_uwsgi(conf) uwsgi_compiled = True class uWSGIInstall(install): def run(self): global uwsgi_compiled if not uwsgi_compiled: conf = uc.uConf(get_profile()) patch_bin_path(self, conf) uc.build_uwsgi(conf) uwsgi_compiled = True install.run(self) class uWSGIInstallLib(install_lib): def run(self): global uwsgi_compiled if not uwsgi_compiled: conf = uc.uConf(get_profile()) patch_bin_path(self, conf) uc.build_uwsgi(conf) uwsgi_compiled = True install_lib.run(self) if HAS_WHEEL: class uWSGIWheel(bdist_wheel): def finalize_options(self): bdist_wheel.finalize_options(self) self.root_is_pure = False class uWSGIDistribution(Distribution): def __init__(self, *attrs): Distribution.__init__(self, *attrs) self.cmdclass['install'] = uWSGIInstall self.cmdclass['install_lib'] = uWSGIInstallLib self.cmdclass['build_ext'] = uWSGIBuilder if HAS_WHEEL: self.cmdclass['bdist_wheel'] = uWSGIWheel def is_pure(self): return False setup( name='uWSGI', version=uc.uwsgi_version, description='The uWSGI server', author='Unbit', author_email='info@unbit.it', license='GPLv2+', descriptions='The uWSGI Platform', url='https://uwsgi-docs.readthedocs.io/en/latest/', py_modules=['uwsgidecorators'], distclass=uWSGIDistribution, classifiers=[ 'Development Status :: 5 - Production/Stable', 'License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)', 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3.13', ], ) uwsgi-2.0.29/setup.pyuwsgi.py000066400000000000000000000130071477626554400162070ustar00rootroot00000000000000# encoding: utf-8 """ This is a hack allowing you installing uWSGI and uwsgidecorators via pip and easy_install since 1.9.11 it automatically detects pypy """ import os import sys import errno import shlex import uwsgiconfig from setuptools import setup from setuptools.command.build_ext import build_ext from distutils.core import Extension class uWSGIBuildExt(build_ext): UWSGI_NAME = 'pyuwsgi' UWSGI_PLUGIN = 'pyuwsgi' UWSGI_PROFILE = 'pyuwsgi' def build_extensions(self): self.uwsgi_setup() # XXX: needs uwsgiconfig fix self.uwsgi_build() if 'UWSGI_USE_DISTUTILS' not in os.environ: # XXX: needs uwsgiconfig fix # uwsgiconfig.build_uwsgi(self.uwsgi_config) return else: # XXX: needs uwsgiconfig fix os.unlink(self.uwsgi_config.get('bin_name')) # FIXME: else build fails :( for baddie in set(self.compiler.compiler_so) & set(('-Wstrict-prototypes',)): self.compiler.compiler_so.remove(baddie) build_ext.build_extensions(self) def uwsgi_setup(self): profile = os.environ.get('UWSGI_PROFILE') or 'buildconf/%s.ini' % self.UWSGI_PROFILE if not profile.endswith('.ini'): profile = profile + '.ini' if '/' not in profile: profile = 'buildconf/' + profile # FIXME: update uwsgiconfig to properly set _EVERYTHING_! config = uwsgiconfig.uConf(profile) # insert in the beginning so UWSGI_PYTHON_NOLIB is exported # before the python plugin compiles ep = config.get('embedded_plugins').split(',') if self.UWSGI_PLUGIN in ep: ep.remove(self.UWSGI_PLUGIN) ep.insert(0, self.UWSGI_PLUGIN) config.set('embedded_plugins', ','.join(ep)) config.set('as_shared_library', 'true') config.set('bin_name', self.get_ext_fullpath(self.UWSGI_NAME)) try: os.makedirs(os.path.dirname(config.get('bin_name'))) except OSError as e: if e.errno != errno.EEXIST: raise self.uwsgi_profile = profile self.uwsgi_config = config def uwsgi_build(self): uwsgiconfig.build_uwsgi(self.uwsgi_config) # XXX: merge uwsgi_setup (see other comments) for ext in self.extensions: if ext.name == self.UWSGI_NAME: ext.sources = [s + '.c' for s in self.uwsgi_config.gcc_list] ext.library_dirs = self.uwsgi_config.include_path[:] ext.libraries = list() ext.extra_compile_args = list() for x in uwsgiconfig.uniq_warnings( self.uwsgi_config.ldflags + self.uwsgi_config.libs, ): for y in shlex.split(x): if y.startswith('-l'): ext.libraries.append(y[2:]) elif y.startswith('-L'): ext.library_dirs.append(y[2:]) for x in self.uwsgi_config.cflags: for y in shlex.split(x): if y: ext.extra_compile_args.append(y) LONG_DESCRIPTION = """ # The uWSGI server as a Python module ## Install ``` pip install pyuwsgi ``` ## Run The installed script, `pyuwsgi`, is a drop-in replacement for the `uwsgi` script. You can also call it directly in your Python code with a list of valid uWSGI options: ```python import pyuwsgi pyuwsgi.run(["--help"]) ``` ## Differences from uWSGI This is built from uWSGI's source without any modifications. A different [`setup.py`](https://github.com/unbit/uwsgi/blob/uwsgi-2.0/setup.pyuwsgi.py) is used to make the project a friendlier part of the Python ecosystem. It allows it to be imported as a Python module and distributed using the [wheel format](https://www.python.org/dev/peps/pep-0427/). The full uWSGI documentation can be found at [https://uwsgi-docs.readthedocs.org](https://uwsgi-docs.readthedocs.org). --- [![Lincoln Loop](https://cldup.com/gyNz5rfTkR.png)](https://lincolnloop.com) `pyuwsgi` is sponsored by [Lincoln Loop](https://lincolnloop.com). [![Unbit](https://cldup.com/TTNag1Zlcw.png)](http://unbit.com/) `uwsgi` is the creation of [Unbit](http://unbit.com/). """ setup( name='pyuwsgi', license='GPL2', version=uwsgiconfig.uwsgi_version, author='Unbit', author_email='info@unbit.it', description='The uWSGI server', long_description=LONG_DESCRIPTION, long_description_content_type="text/markdown", cmdclass={ 'build_ext': uWSGIBuildExt, }, py_modules=[ 'uwsgidecorators', ], ext_modules=[ Extension('pyuwsgi', sources=[]), ], entry_points={ 'console_scripts': ['pyuwsgi=pyuwsgi:run'], }, classifiers=[ "Development Status :: 4 - Beta", "Environment :: Web Environment", "License :: OSI Approved :: GNU General Public License v2 (GPLv2)", "Operating System :: MacOS :: MacOS X", "Operating System :: POSIX", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Internet :: WWW/HTTP :: WSGI :: Server", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", ] ) uwsgi-2.0.29/t/000077500000000000000000000000001477626554400132315ustar00rootroot00000000000000uwsgi-2.0.29/t/cachebitmap.ini000066400000000000000000000011301477626554400161650ustar00rootroot00000000000000[uwsgi] socket = /tmp/foo cache2 = name=items_1,blocks=4,items=2,bitmap=1,blocksize=1 cache2 = name=items_2,blocks=4,items=3,bitmap=1,blocksize=1 cache2 = name=items_3,blocks=4,items=4,bitmap=1,blocksize=1 cache2 = name=items_4,blocks=5,items=5,bitmap=1,blocksize=1 cache2 = name=items_17,blocks=17,items=17,bitmap=1,blocksize=1 cache2 = name=items_4_10,blocks=5,items=5,bitmap=1,blocksize=10 cache2 = name=items_1_100000,blocks=1000,items=2,bitmap=1,blocksize=100 cache2 = name=items_non_bitmap,items=2,blocksize=20 cache2 = name=items_lru,items=3,blocksize=20,purge_lru=1 pyrun = t/cachebitmap.py uwsgi-2.0.29/t/cachebitmap.py000066400000000000000000000131631477626554400160470ustar00rootroot00000000000000import uwsgi import unittest import random import string class BitmapTest(unittest.TestCase): __caches__ = [ 'items_1', 'items_2', 'items_3', 'items_4', 'items_17', 'items_4_10', 'items_1_100000', 'items_non_bitmap', 'items_lru' ] def setUp(self): for cache in self.__caches__: uwsgi.cache_clear(cache) def test_failed_by_one(self): self.assertIsNone(uwsgi.cache_update('key1', 'HELLO', 0, 'items_1')) def test_ok_four_bytes(self): self.assertTrue(uwsgi.cache_update('key1', 'HELL', 0, 'items_1')) def test_two_items_using_four_blocks(self): self.assertTrue(uwsgi.cache_update('key1', 'HE', 0, 'items_2')) self.assertTrue(uwsgi.cache_update('key2', 'LL', 0, 'items_2')) self.assertTrue(uwsgi.cache_del('key1', 'items_2')) self.assertIsNone(uwsgi.cache_update('key1', 'HEL', 0, 'items_2')) self.assertTrue(uwsgi.cache_update('key1', 'HE', 0, 'items_2')) def test_overlapping(self): self.assertTrue(uwsgi.cache_update('key1', 'HE', 0, 'items_2')) self.assertIsNone(uwsgi.cache_update('key1', 'HELL', 0, 'items_2')) self.assertTrue(uwsgi.cache_del('key1', 'items_2')) self.assertTrue(uwsgi.cache_update('key1', 'HELL', 0, 'items_2')) def test_big_item(self): self.assertIsNone(uwsgi.cache_update('key1', 'HELLOHELLOHELLOHEL', 0, 'items_17')) self.assertTrue(uwsgi.cache_update('key1', 'HELLOHELLOHELLOHE', 0, 'items_17')) def test_set(self): self.assertTrue(uwsgi.cache_set('key1', 'HELLO', 0, 'items_17')) self.assertIsNone(uwsgi.cache_set('key1', 'HELLO', 0, 'items_17')) self.assertTrue(uwsgi.cache_del('key1', 'items_17')) self.assertTrue(uwsgi.cache_set('key1', 'HELLO', 0, 'items_17')) self.assertIsNone(uwsgi.cache_set('key1', 'HELLO', 0, 'items_17')) def test_too_much_items(self): self.assertTrue(uwsgi.cache_set('key1', 'HELLO', 0, 'items_4_10')) self.assertTrue(uwsgi.cache_set('key2', 'HELLO', 0, 'items_4_10')) self.assertTrue(uwsgi.cache_set('key3', 'HELLO', 0, 'items_4_10')) self.assertTrue(uwsgi.cache_set('key4', 'HELLO', 0, 'items_4_10')) self.assertIsNone(uwsgi.cache_set('key5', 'HELLO', 0, 'items_4_10')) def test_big_delete(self): self.assertTrue(uwsgi.cache_set('key1', 'X' * 50, 0, 'items_4_10')) self.assertTrue(uwsgi.cache_del('key1', 'items_4_10')) self.assertTrue(uwsgi.cache_set('key1', 'HELLOHELLO', 0, 'items_4_10')) self.assertTrue(uwsgi.cache_set('key2', 'HELLOHELLO', 0, 'items_4_10')) self.assertTrue(uwsgi.cache_set('key3', 'HELLOHELLO', 0, 'items_4_10')) self.assertTrue(uwsgi.cache_set('key4', 'HELLOHELLO', 0, 'items_4_10')) self.assertIsNone(uwsgi.cache_set('key5', 'HELLOHELLO', 0, 'items_4_10')) def test_big_update(self): self.assertTrue(uwsgi.cache_set('key1', 'X' * 40, 0, 'items_4_10')) self.assertTrue(uwsgi.cache_update('key1', 'X' * 10, 0, 'items_4_10')) self.assertTrue(uwsgi.cache_del('key1', 'items_4_10')) self.assertIsNone(uwsgi.cache_update('key1', 'X' * 51, 0, 'items_4_10')) self.assertTrue(uwsgi.cache_update('key1', 'X' * 50, 0, 'items_4_10')) def test_multi_clear(self): for i in range(0, 100): self.assertTrue(uwsgi.cache_clear('items_4_10')) def test_multi_delete(self): for i in range(0, 100): self.assertTrue(uwsgi.cache_set('key1', 'X' * 50, 0, 'items_4_10')) self.assertTrue(uwsgi.cache_del('key1', 'items_4_10')) for i in range(0, 100): self.assertIsNone(uwsgi.cache_set('key1', 'X' * 51, 0, 'items_4_10')) self.assertIsNone(uwsgi.cache_del('key1', 'items_4_10')) for i in range(0, 100): self.assertTrue(uwsgi.cache_set('key1', 'X' * 50, 0, 'items_4_10')) self.assertTrue(uwsgi.cache_del('key1', 'items_4_10')) def test_big_key(self): self.assertTrue(uwsgi.cache_set('K' * 2048, 'X' * 50, 0, 'items_4_10')) self.assertIsNone(uwsgi.cache_set('K' * 2049, 'X' * 50, 0, 'items_4_10')) def rand_blob(self, n=32): return ''.join(random.choice(string.ascii_letters + string.digits) for x in range(n)) def test_big_random(self): blob = self.rand_blob(100000) self.assertTrue(uwsgi.cache_set('KEY', blob, 0, 'items_1_100000')) get_blob = uwsgi.cache_get('KEY', 'items_1_100000') self.assertEqual(blob, get_blob) self.assertTrue(uwsgi.cache_del('KEY', 'items_1_100000')) self.assertIsNone(uwsgi.cache_set('KEY', 'X' * 100001, 0, 'items_1_100000')) self.assertTrue(uwsgi.cache_set('KEY', 'X' * 10000, 0, 'items_1_100000')) def test_non_bitmap(self): self.assertTrue(uwsgi.cache_set('KEY', 'X' * 20, 0, 'items_non_bitmap')) self.assertTrue(uwsgi.cache_del('KEY', 'items_non_bitmap')) self.assertIsNone(uwsgi.cache_set('KEY', 'X' * 21, 0, 'items_non_bitmap')) self.assertTrue(uwsgi.cache_set('KEY', 'X' * 20, 0, 'items_non_bitmap')) def test_lru(self): self.assertTrue(uwsgi.cache_set('KEY1', 'X' * 20, 0, 'items_lru')) self.assertTrue(uwsgi.cache_set('KEY2', 'X' * 20, 0, 'items_lru')) self.assertTrue(uwsgi.cache_set('KEY3', 'Y' * 20, 0, 'items_lru')) self.assertIsNone(uwsgi.cache_get('KEY1', 'items_lru')) uwsgi.cache_get('KEY3', 'items_lru') for i in range(4, 100): self.assertTrue(uwsgi.cache_set('KEY%d' % i, 'Y' * 20, 0, 'items_lru')) self.assertIsNone(uwsgi.cache_get('KEY%d' % (i-2), 'items_lru')) unittest.main() uwsgi-2.0.29/t/cachetest.py000066400000000000000000000013211477626554400155430ustar00rootroot00000000000000import uwsgi import random import string items = {} def gen_rand_n(max_n): return random.randint(8, max_n) def gen_rand_s(size): return ''.join(random.choice(string.letters) for i in range(size)) print('filling cache...') for i in range(0, 1000): kl = gen_rand_n(200) key = gen_rand_s(kl) vl = gen_rand_n(10000) val = gen_rand_s(vl) items[key] = val uwsgi.cache_set(key, val) print('checking cache...') count = 0 for key in items.keys(): val = uwsgi.cache_get(key) count += 1 if val != items[key]: print(len(val), val) print(len(items[key]), items[key]) raise Exception('CACHE TEST FAILED AFTER %d ITERATIONS !!!' % count) print("TEST PASSED") uwsgi-2.0.29/t/cgi/000077500000000000000000000000001477626554400137735ustar00rootroot00000000000000uwsgi-2.0.29/t/cgi/hello.cgi000077500000000000000000000001421477626554400155620ustar00rootroot00000000000000#!/bin/sh echo "Content-Type: text/plain" echo echo "Hello world!" echo "PATH_INFO=${PATH_INFO}" uwsgi-2.0.29/t/clojure/000077500000000000000000000000001477626554400146745ustar00rootroot00000000000000uwsgi-2.0.29/t/clojure/myapp.clj000066400000000000000000000004441477626554400165160ustar00rootroot00000000000000(ns myapp (import uwsgi) ) (defn handler [req] {:status 200 :headers { "Content-Type" "text/html" , "Server" "uWSGI" } :body (str "

    The requested uri is " (get req :uri) "

    " "

    reverse is " (uwsgi/rpc (into-array ["" "reverse" (get req :uri)])) "

    " ) } ) uwsgi-2.0.29/t/core/000077500000000000000000000000001477626554400141615ustar00rootroot00000000000000uwsgi-2.0.29/t/core/apps/000077500000000000000000000000001477626554400151245ustar00rootroot00000000000000uwsgi-2.0.29/t/core/apps/read_body_and_send.pl000066400000000000000000000002501477626554400212410ustar00rootroot00000000000000my $app = sub { my $env = shift; $env->{'psgi.input'}->read(my $body, $env->{CONTENT_LENGTH}); return [200, ['Content-Type' => 'x-application/binary'], [$body]]; }; uwsgi-2.0.29/t/core/read_body_and_send.pl000066400000000000000000000014251477626554400203030ustar00rootroot00000000000000#!/usr/bin/perl #uwsgi --http-socket :9090 --psgi t/core/apps/read_body_and_send.pl use IO::Socket::INET; my @chars = ("A".."Z", "a".."z"); foreach(0..100) { $size = int(rand(8*1024*1024)); print "testing: round ".$_." body size ".$size."\n"; my $req = "POST /foobar HTTP/1.0\r\n"; $req .= 'Content-Length: '.$size."\r\n\r\n"; my $body = ''; $body .= $chars[rand @chars] for 1..($size); $req .= $body; my $s = IO::Socket::INET->new(PeerAddr => $ARGV[0]); $s->send($req); my $response = ''; while(1) { $s->recv(my $buf, 4096); last unless length($buf); $response .= $buf; } $s->close; if ($response ne "HTTP/1.0 200 OK\r\nContent-Type: x-application/binary\r\n\r\n".$body) { print "TEST FOR ROUND ".$_." FAILED\n"; exit; } } print "test result: SUCCESS\n"; uwsgi-2.0.29/t/core/readline/000077500000000000000000000000001477626554400157445ustar00rootroot00000000000000uwsgi-2.0.29/t/core/readline/__init__.py000066400000000000000000000000001477626554400200430ustar00rootroot00000000000000uwsgi-2.0.29/t/core/readline/app.py000066400000000000000000000006161477626554400171010ustar00rootroot00000000000000#!/usr/bin/python3 # uwsgi --plugin python,http --http 0.0.0.0:8000 -w app from werkzeug.wrappers import Request, Response def application(env, start_response): request = Request(env) lines = b"" while True: line = request.stream.readline() if not line: break; lines += line response = Response(lines) return response(env, start_response) uwsgi-2.0.29/t/core/readline/client.py000066400000000000000000000003561477626554400176000ustar00rootroot00000000000000import requests headers = {'Content-Type': 'application/octet-stream'} data = '\n'.join(['{:04}'.format(i) for i in range(1001)] + ['final']) r = requests.post("http://127.0.0.1:8000", data=data, headers=headers) assert r.text == data uwsgi-2.0.29/t/core/readline/requirements.txt000066400000000000000000000000221477626554400212220ustar00rootroot00000000000000requests Werkzeug uwsgi-2.0.29/t/core/url_sanitize.pl000066400000000000000000000030571477626554400172330ustar00rootroot00000000000000#!/usr/bin/perl #uwsgi --http-socket :9090 --route-run "send:\${PATH_INFO}" use IO::Socket::INET; my @tests; push @tests, ['/foo','/foo']; push @tests, ['./foo','/foo']; push @tests, ['./foo/bar?a=1','/foo/bar']; push @tests, ['//foo/bar','//foo/bar']; push @tests, ['foo/bar','foo/bar']; push @tests, ['foo/bar/../','foo/']; push @tests, ['foo/bar/..','foo/']; push @tests, ['/foo/bar/..','/foo/']; push @tests, ['../../../foo/bar/..','/foo/']; push @tests, ['test1/test2/../test3/','test1/test3/']; push @tests, ['t#est1/test2/../test3/','t']; push @tests, ['/one/two/three/four/../five','/one/two/three/five']; push @tests, ['/one/two/three/four/../../five','/one/two/five']; push @tests, ['/one/two/three/four/../../five/','/one/two/five/']; push @tests, ['/one/two/three/four/../../five/..','/one/two/']; push @tests, ['.one/two/three/four/../../five/..','.one/two/']; push @tests, ['..one/two/three/four/../../five/..','..one/two/']; push @tests, ['/../','/']; push @tests, ['../','/']; push @tests, ['/.','/']; push @tests, ['..one/two/three/four/../../../../../five/..','/']; push @tests, ['./foo/.bar.','/foo/.bar.']; foreach(@tests) { print "testing: ".$_->[0]."\n"; my $req = "GET ".$_->[0]." HTTP/1.0\r\n\r\n"; my $s = IO::Socket::INET->new(PeerAddr => $ARGV[0]); $s->send($req); my $response = ''; while(1) { $s->recv(my $buf, 4096); last unless length($buf); $response .= $buf; } $s->close; if ($response ne $_->[1]) { print "TEST FOR ".$_->[0]." FAILED: EXPECTED ".$_->[1]." GOT ".$response."\n"; exit; } } print "test result: SUCCESS\n"; uwsgi-2.0.29/t/cron.ini000066400000000000000000000001271477626554400146730ustar00rootroot00000000000000[uwsgi] cron = -1 -1 -1 -1 -1 /bin/echo minus one cron = 14 -1 -1 -1 -1 /bin/echo zero uwsgi-2.0.29/t/go/000077500000000000000000000000001477626554400136365ustar00rootroot00000000000000uwsgi-2.0.29/t/go/cachetest.go000066400000000000000000000030221477626554400161250ustar00rootroot00000000000000package main import "uwsgi" import "net/http" import "fmt" func getHandler(w http.ResponseWriter, r *http.Request) { p := uwsgi.CacheGet("foobar", "") if p == nil { fmt.Fprintf(w, "

    item not found

    ") return } fmt.Fprintf(w, "

    " + string(p) + "

    ") } func setHandler(w http.ResponseWriter, r *http.Request) { if uwsgi.CacheSet("foobar", []byte("Hello World !"), 0, "") == false { fmt.Fprintf(w, "

    unable to set cache item

    ") return } fmt.Fprintf(w, "

    item set

    ") } func updateHandler(w http.ResponseWriter, r *http.Request) { if uwsgi.CacheUpdate("foobar", []byte("Hello World ! [updated]"), 0, "") == false { fmt.Fprintf(w, "

    unable to update cache item

    ") return } fmt.Fprintf(w, "

    item updated

    ") } func deleteHandler(w http.ResponseWriter, r *http.Request) { if uwsgi.CacheDel("foobar", "") == false { fmt.Fprintf(w, "

    unable to delete cache item

    ") return } fmt.Fprintf(w, "

    item deleted

    ") } func checkHandler(w http.ResponseWriter, r *http.Request) { if !uwsgi.CacheExists("foobar", "") { fmt.Fprintf(w, "

    item does not exist

    ") return } fmt.Fprintf(w, "

    item exists

    ") } func main() { http.HandleFunc("/get/", getHandler) http.HandleFunc("/update/", updateHandler) http.HandleFunc("/set/", setHandler) http.HandleFunc("/delete/", deleteHandler) http.HandleFunc("/check/", checkHandler) uwsgi.Run() } uwsgi-2.0.29/t/go/complextest.go000066400000000000000000000021111477626554400165270ustar00rootroot00000000000000package main import "uwsgi" import "fmt" import "net/http" import "time" func postfork() { if uwsgi.WorkerId() == 0 { fmt.Println("PoSt FoRk on mule", uwsgi.MuleId(), "!!!") } else { fmt.Println("PoSt FoRk on worker", uwsgi.WorkerId(), "!!!") } } func request_handler(w http.ResponseWriter, r *http.Request) { uwsgi.Signal(17) fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:]) fmt.Fprintf(w, "

    Hi there, I love %s!

    ", r.URL.Path[1:]) fmt.Println("LOGSIZE: ", uwsgi.LogSize()) uwsgi.Alarm("jabber", "Hello") go slow() } func hello(signum int) { fmt.Println("Ciao, 3 seconds elapsed or RequestHandler() called") } func hello2(signum int) { fmt.Println("I am an rb_timer running on mule", uwsgi.MuleId()) } func slow() { time.Sleep(8 * time.Second) fmt.Println("8 seconds ELAPSED !!!") } func postinit() { uwsgi.RegisterSignal(17, "", hello) uwsgi.AddTimer(17, 3) uwsgi.RegisterSignal(30, "mule1", hello2) uwsgi.AddTimer(30, 5) } func main() { uwsgi.PostInit(postinit) uwsgi.PostFork(postfork) uwsgi.RequestHandler(request_handler) uwsgi.Run() } uwsgi-2.0.29/t/go/uploadtest.go000066400000000000000000000017531477626554400163570ustar00rootroot00000000000000package main import "uwsgi" import "net/http" import "fmt" import "io/ioutil" import "os" func viewHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "
    ") } func postHandler(w http.ResponseWriter, r *http.Request) { foo := r.FormValue("foo") bar, handler, err := r.FormFile("bar") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } bar_data, err := ioutil.ReadAll(bar) w.Header().Set("Content-Type", "text/plain") w.Header().Set("X-Server", "uWSGI") fmt.Fprintf(w, foo + "\n\n" + handler.Filename + "\n\n" + string(bar_data)) } func signal30(sig uint8) { fmt.Println("ciao") } func main() { fmt.Println(os.Args) uwsgi.RegisterSignal(30, "", signal30) http.HandleFunc("/view/", viewHandler) http.HandleFunc("/post/", postHandler) uwsgi.Run() } uwsgi-2.0.29/t/java/000077500000000000000000000000001477626554400141525ustar00rootroot00000000000000uwsgi-2.0.29/t/java/rpc.java000066400000000000000000000006141477626554400156020ustar00rootroot00000000000000public class rpc { public static Object[] application(java.util.HashMap env) { String rpc_out = uwsgi.rpc("", "reverse", (String) env.get("REQUEST_URI")); java.util.HashMap headers = new java.util.HashMap(); headers.put("Content-Type", "text/html"); Object[] response = { 200, headers, "

    " + rpc_out + "

    "}; return response; } } uwsgi-2.0.29/t/lua/000077500000000000000000000000001477626554400140125ustar00rootroot00000000000000uwsgi-2.0.29/t/lua/basic.lua000066400000000000000000000010651477626554400156000ustar00rootroot00000000000000function hello(wsapi_env) local headers = { ["Content-type"] = "text/html", ["set-cookie"] = {"foo=bar", "bar=baz"} } local function hello_text() coroutine.yield("") coroutine.yield("

    Hello Wsapi!

    ") coroutine.yield("

    PATH_INFO: " .. wsapi_env.PATH_INFO .. "

    ") coroutine.yield("

    SCRIPT_NAME: " .. wsapi_env.SCRIPT_NAME .. "

    ") coroutine.yield("

    QUERY_STRING: " .. wsapi_env.QUERY_STRING .. "

    ") coroutine.yield("") end return 200, headers, coroutine.wrap(hello_text) end return hello uwsgi-2.0.29/t/mono/000077500000000000000000000000001477626554400142015ustar00rootroot00000000000000uwsgi-2.0.29/t/mono/cache.aspx000066400000000000000000000002021477626554400161330ustar00rootroot00000000000000<%@ language="C#"%> Hello 1
    <%= System.Text.Encoding.UTF8.GetString(uwsgi.api.CacheGet("/etc/passwd")) %>
    Hello 1
    uwsgi-2.0.29/t/mules/000077500000000000000000000000001477626554400143565ustar00rootroot00000000000000uwsgi-2.0.29/t/mules/mulebrain.py000066400000000000000000000007511477626554400167110ustar00rootroot00000000000000import signal, sys import time import uwsgi import os print(uwsgi.opt) sig_timeout = uwsgi.opt.get('test_mule_timeout', 10) sig_to_send = uwsgi.opt.get('test_signal', signal.SIGINT) def sig_handler(signum, frame): print('Hello from signal', signum) time.sleep(int(sig_timeout)) sys.exit(0) signal.signal(signal.SIGINT, sig_handler) signal.signal(signal.SIGHUP, sig_handler) time.sleep(1) os.kill(uwsgi.masterpid(), int(sig_to_send)) while True: uwsgi.farm_get_msg() uwsgi-2.0.29/t/mules/reload.py000066400000000000000000000016301477626554400161760ustar00rootroot00000000000000import os import unittest import time from subprocess import Popen, PIPE def touch(fname): with open(fname, 'a'): os.utime(fname, None) return def pgrep_mules(): cmd = ["pgrep", "-f", "uWSGI mule"] proc = Popen(cmd, stdout=PIPE) rv = set(map(int, proc.stdout.readlines())) proc.terminate() return rv class MuleReloadingTest(unittest.TestCase): def test_reloading(self): try: uwsgi = Popen(["./uwsgi", "--master", "--mule", "--touch-mules-reload=/tmp/reload", "--socket=:0", "--auto-procname"]) subprocesses = pgrep_mules() touch("/tmp/reload") time.sleep(1) new_subprocesses = pgrep_mules() proc_intersect = subprocesses.intersection(new_subprocesses) self.assertFalse(proc_intersect) finally: uwsgi.terminate() if __name__ == "__main__": unittest.main() uwsgi-2.0.29/t/mules/signal_management.py000066400000000000000000000026731477626554400204110ustar00rootroot00000000000000import unittest import subprocess import time class SignalHandlingTest(unittest.TestCase): def test_int_mercyless(self): started_at = int(time.time()) ret = subprocess.call(['./uwsgi', '--master', '--mule=t/mules/mulebrain.py', '--py-call-osafterfork', '--socket=:0', '--mule-reload-mercy=1']) self.assertEqual(ret, 0) self.assertLess(int(time.time()) - started_at, 6) def test_int(self): started_at = int(time.time()) ret = subprocess.call(['./uwsgi', '--set=test_mule_timeout=3', '--master', '--mule=t/mules/mulebrain.py', '--py-call-osafterfork', '--socket=:0']) self.assertEqual(ret, 0) self.assertLess(int(time.time()) - started_at, 8) def test_hup(self): started_at = int(time.time()) ret = subprocess.call(['./uwsgi', '--set=test_signal=1', '--set=test_mule_timeout=3', '--exit-on-reload', '--master', '--mule=t/mules/mulebrain.py', '--py-call-osafterfork', '--socket=:0']) self.assertEqual(ret, 0) self.assertLess(int(time.time()) - started_at, 8) def test_int_with_threads(self): started_at = int(time.time()) ret = subprocess.call(['./uwsgi', '--enable-threads', '--set=test_mule_timeout=3', '--master', '--mule=t/mules/mulebrain.py', '--py-call-osafterfork', '--socket=:0']) self.assertEqual(ret, 0) self.assertLess(int(time.time()) - started_at, 8) if __name__ == '__main__': unittest.main() uwsgi-2.0.29/t/perl/000077500000000000000000000000001477626554400141735ustar00rootroot00000000000000uwsgi-2.0.29/t/perl/active_workers_signal.pl000066400000000000000000000004351477626554400211160ustar00rootroot00000000000000#uwsgi --psgi t/perl/active_workers_signal.pl -s :3031 --perl-no-plack --timer "17 3" -p 8 --cheap --idle 10 my $handler = sub { print "hello i am the signal handler on worker ".uwsgi::worker_id()."\n"; }; uwsgi::register_signal(17, 'active-workers', $handler); my $app = sub { }; uwsgi-2.0.29/t/perl/apps/000077500000000000000000000000001477626554400151365ustar00rootroot00000000000000uwsgi-2.0.29/t/perl/apps/body-types.psgi000066400000000000000000000027451477626554400201310ustar00rootroot00000000000000use strict; use warnings; use FileHandle; use IO::File; use IO::String; my $code = do { local ( @ARGV, $/ ) = __FILE__; <> }; sub ObjectPath::path { __FILE__ } sub { my $path = shift->{PATH_INFO}; my $body = $path eq '/Array' ? [ split //, $code ] : $path eq '/Code' ? sub {} : $path eq '/DATA' ? \*DATA : $path eq '/DIRHANDLE' ? do { opendir my $fh, '.'; $fh } : $path eq '/FILEHANDLE' ? do { open my $fh, __FILE__; $fh } : $path eq '/FileHandle' ? FileHandle->new(__FILE__) : $path eq '/Float' ? 3.14 : $path eq '/FloatRef' ? \3.14 : $path eq '/Format' ? *STDOUT{FORMAT} : $path eq '/FormatRef' ? \*STDOUT{FORMAT} : $path eq '/IO::File' ? IO::File->new(__FILE__) : $path eq '/Hash' ? { foo => 'bar' } : $path eq '/Int' ? 3 : $path eq '/IntRef' ? \3 : $path eq '/IO::String' ? IO::String->new($code) : $path eq '/Object' ? bless({}) : $path eq '/ObjectPath' ? bless( {}, 'ObjectPath' ) : $path eq '/Regexp' ? qr/foo/ : $path eq '/String' ? 'foo' : $path eq '/StringRef' ? \'bar' : $path eq '/Undef' ? undef : $path eq '/UndefRef' ? \undef : return [ 404, [], [] ]; [ 200, [ 'X-ref' => ref $body ], $body ]; }; __DATA__ data data data uwsgi-2.0.29/t/perl/apps/env.psgi000066400000000000000000000002661477626554400166160ustar00rootroot00000000000000use strict; use warnings; sub { my $env = shift; my $body = join "\n", map "$_\n$env->{$_}", sort keys %$env; [ 200, [ 'Content-type' => 'text/plain' ], [$body] ]; }; uwsgi-2.0.29/t/perl/apps/input_with_offset.pl000066400000000000000000000004651477626554400212400ustar00rootroot00000000000000my $app = sub { my ($env) = @_; my $orig = $env->{QUERY_STRING}; if ($env->{CONTENT_LENGTH} > 0) { $env->{'psgi.input'}->read($orig, $env->{CONTENT_LENGTH}, $env->{HTTP_UWSGI_OFFSET}); } return [ 200, ['Content-Type' => 'text/plain'], [$orig."\n"]]; }; uwsgi-2.0.29/t/perl/body-types.t000066400000000000000000000031231477626554400164560ustar00rootroot00000000000000use strict; use warnings; BEGIN { exec qw( ./uwsgi --disable-logging --http-socket :5000 --perl-no-die-catch --perl-no-plack --psgi t/perl/apps/body-types.psgi ) unless my $pid = fork; END { kill 15, $pid } } use HTTP::Tiny; use Test::More tests => 22; my $http = HTTP::Tiny->new; my $code = do { local ( @ARGV, $/ ) = 't/perl/apps/body-types.psgi'; <> }; for ( [ Array => 1, 'ARRAY' ], [ Code => 0, 'CODE' ], [ DATA => 1, 'GLOB' ], [ DIRHANDLE => 0, 'GLOB' ], [ FILEHANDLE => 1, 'GLOB' ], [ FileHandle => 1, 'FileHandle' ], [ Float => 0, '' ], [ FloatRef => 0, 'SCALAR' ], [ Format => 0, '' ], [ FormatRef => 0, 'SCALAR' ], [ Hash => 0, 'HASH' ], [ Int => 0, '' ], [ IntRef => 0, 'SCALAR' ], [ 'IO::File' => 1, 'IO::File' ], [ 'IO::String' => 1, 'IO::String' ], [ Object => 0, 'main' ], [ ObjectPath => 1, 'ObjectPath' ], [ Regexp => 0, 'Regexp' ], [ String => 0, '' ], [ StringRef => 0, 'SCALAR' ], [ Undef => 0, '' ], [ UndefRef => 0, 'SCALAR' ], ) { my ( $path, $has_content, $ref ) = @$_; my $got = $http->get( 'http://localhost:5000/' . $path ); delete @$got{qw/protocol reason success status url/}; is_deeply $got, { content => $code x $has_content, headers => { 'x-ref' => $ref }, }, $path; } uwsgi-2.0.29/t/perl/env.t000066400000000000000000000043131477626554400151510ustar00rootroot00000000000000use strict; use warnings; use Config; use HTTP::Tiny; use Test::Deep; use Test::More; chomp( my $host = `hostname` ); my ( $t, $f ) = ( bool(1), bool(0) ); my $http = HTTP::Tiny->new; my %exp = ( HTTP_HOST => 'localhost:5000', HTTP_USER_AGENT => $http->agent, PATH_INFO => '/', QUERY_STRING => '', REMOTE_ADDR => '127.0.0.1', REQUEST_METHOD => 'GET', REQUEST_URI => '/', SCRIPT_NAME => '', SERVER_NAME => $host, SERVER_PORT => 5000, SERVER_PROTOCOL => 'HTTP/1.1', 'psgi.errors' => re(qr/^uwsgi::error=SCALAR\(0x[\da-f]+\)$/), 'psgi.input' => re(qr/^uwsgi::input=SCALAR\(0x[\da-f]+\)$/), 'psgi.multiprocess' => $f, 'psgi.multithread' => $f, 'psgi.nonblocking' => $f, 'psgi.run_once' => $f, 'psgi.streaming' => $t, 'psgi.url_scheme' => 'http', 'psgi.version' => re(qr/^ARRAY\(0x[\da-f]+\)$/), 'psgix.cleanup' => $t, 'psgix.cleanup.handlers' => re(qr/^ARRAY\(0x[\da-f]+\)$/), 'psgix.harakiri' => $f, 'psgix.input.buffered' => $f, 'psgix.logger' => re(qr/^CODE\(0x[\da-f]+\)$/), ); my @tests = ( [ 'Defaults', {} ], [ 'Master', { 'psgix.harakiri' => $t }, '--master' ], [ 'Async', { 'psgi.nonblocking' => $t }, '--async' => 1 ], [ 'Workers', { 'psgix.harakiri' => $t, 'psgi.multiprocess' => $t }, '--master', '--workers' => 2, ], ); push @tests, [ 'Threads', { 'psgi.multithread' => $t }, '--threads' => 2 ] if $ENV{UWSGI_PERL} =~ /-thread$/; plan tests => scalar @tests; for (@tests) { my ( $name, $exp, @opts ) = @$_; exec qw( ./uwsgi --disable-logging --http-socket :5000 --perl-no-die-catch --perl-no-plack --psgi t/perl/apps/env.psgi ), @opts unless my $pid = fork; sleep 1; # Let uWSGI start. my %got = split /\n/, $http->get('http://localhost:5000')->{content}; cmp_deeply \%got, { %exp, %$exp }, $name; kill 15, $pid; sleep 1; # Let uWSGI kill it's workers. } uwsgi-2.0.29/t/perl/run000077500000000000000000000021621477626554400147260ustar00rootroot00000000000000#!/usr/bin/env perl use strict; use warnings; use TAP::Harness; my $cpus = `nproc`; my @perls = qw/ 5.20.2 5.18.4 5.16.3 5.14.4 5.12.4 5.10.1 5.8.9 /; my %installed; @installed{ map /(uwsgi-perl-[-\w.]+)/ ? $1 : (), `perlbrew list` } = (); my $tap = TAP::Harness->new( { verbosity => 1 } ); for my $perl (@perls) { for my $thread (0, 1) { my $name = $ENV{UWSGI_PERL} = 'uwsgi-perl-' . $perl . ( '-thread' x $thread ); warn "\n# $name\n\n"; # Install required perlbrew, unless already installed. system 'perlbrew', 'install', $perl, '--as', $name, '-D', 'useshrplib', '-j', $cpus, '-n', '--noman', ('--thread') x $thread and die $! unless exists $installed{$name}; # Clean previously compiled uWSGI. system 'python', 'uwsgiconfig.py', '-c' and die $!; # Compile uWSGI, only show STDERR. `perlbrew exec --with $name python uwsgiconfig.py -b plonly`; exit if $?; my $res = $tap->runtests( @ARGV ? @ARGV : ); exit $res->exit if $res->exit; } } uwsgi-2.0.29/t/perl/test.psgi000066400000000000000000000032701477626554400160400ustar00rootroot00000000000000use strict; use warnings; BEGIN { die "PANIC: We should only load this once" if ++$main::count_BEGIN > 1; } die "PANIC: We should only run this once" if ++$main::count_runs > 1; uwsgi::register_rpc('hello', sub { my ($one, $two, $three) = @_; unless($one) { return "passed no args to RPC func"; } return $three.'-'.$two.'-'.$one; }); my $rpc_value = uwsgi::call('hello', 'foo', 'bar', 'test'); if ($rpc_value) { print "rpc value = ".$rpc_value."\n"; } my $one = sub { my $env = shift; sleep(1); print "one\n"; }; my $two = sub { my $env = shift; sleep(1); print "two\n"; }; my $four = sub { my $signum = shift; print "i am signal ".$signum."\n" ; }; uwsgi::register_signal(17, '', $four); uwsgi::register_signal(30, '', $two); my $three = sub { my $env = shift; sleep(1); print "three\n"; }; uwsgi::postfork(sub { print "forked !!!\n"; }); uwsgi::atexit(sub { print "exited\n"; }); my $app = sub { my $env = shift; uwsgi::signal(17); uwsgi::signal(30); my ($package, $filename, $line) = caller; die "Expecting reasonable caller() return values, not [$package, $filename, $line]" unless $package eq 'main' and $filename =~ /\btest\.psgi$/s and $line == 0; if ($env->{'psgix.cleanup'}) { print "cleanup supported\n"; push @{$env->{'psgix.cleanup.handlers'}}, $one; push @{$env->{'psgix.cleanup.handlers'}}, $two; push @{$env->{'psgix.cleanup.handlers'}}, $three; } uwsgi::cache_set("key1", "val1"); if ($rpc_value) { print uwsgi::call('hello')."\n"; } print 'pid '.$$."\n"; return [ '200', [ 'Content-Type' => 'text/plain' ], [ "Hello World\r\n", $env->{'REQUEST_URI'}, uwsgi::cache_get('key1'), uwsgi::call('hello') ], ]; }; uwsgi-2.0.29/t/perl/test_benchmark.pl000066400000000000000000000035461477626554400175310ustar00rootroot00000000000000use v5.10.0; use strict; use warnings; use Time::HiRes qw(sleep); use autodie qw(:all); my $psgi = $ARGV[0] || 't/perl/test_hello.psgi'; for my $use_thunder_lock (0,1) { for my $cpu_multiplier (1,2,4,8,16,32,64) { my $procs = 16 * $cpu_multiplier; my $desc = sprintf "%3d procs %2s/TL", $procs, ($use_thunder_lock ? "w" : "wo"); my $tl_cl = $use_thunder_lock ? "--thunder-lock --lock-engine ipcsem --ftok $psgi" : ""; #say STDERR "Now testing $desc"; system q[for p in $(ps auxf|grep uwsgi.*--disable-logging|grep -v grep|awk '{print $2}'); do kill $p; done]; system qq[./uwsgi --http 127.0.0.1:8080 --processes $procs --psgi $psgi --disable-logging $tl_cl >/dev/null 2>&1 &]; sleep 0.5; chomp(my $ab = qx[http_proxy= ab -n 10000 -c 32 http://localhost:8080/ 2>&1]); my ($seconds) = $ab =~ m[Time taken for tests:\s+([0-9.]+) seconds]; say STDERR "$seconds\t$desc"; system q[for p in $(ps auxf|grep uwsgi.*--disable-logging|grep -v grep|awk '{print $2}'); do kill $p; done]; sleep 0.5; } } __END__ $ perl t/perl/test_benchmark.pl t/perl/test_sleepy.psgi 7.128 16 procs wo/TL 3.547 32 procs wo/TL 2.038 64 procs wo/TL 2.880 128 procs wo/TL 4.578 256 procs wo/TL 8.199 512 procs wo/TL 13.379 1024 procs wo/TL 7.123 16 procs w/TL 3.559 32 procs w/TL 2.036 64 procs w/TL 1.972 128 procs w/TL 2.026 256 procs w/TL 2.172 512 procs w/TL 2.412 1024 procs w/TL $ perl t/perl/test_benchmark.pl t/perl/test_hello.psgi 1.392 16 procs wo/TL 1.743 32 procs wo/TL 2.374 64 procs wo/TL 3.530 128 procs wo/TL 4.984 256 procs wo/TL 8.258 512 procs wo/TL 9.343 1024 procs wo/TL 1.134 16 procs w/TL 1.284 32 procs w/TL 1.152 64 procs w/TL 1.084 128 procs w/TL 1.286 256 procs w/TL 1.559 512 procs w/TL 1.537 1024 procs w/TL uwsgi-2.0.29/t/perl/test_harakiri.psgi000066400000000000000000000011621477626554400177100ustar00rootroot00000000000000use strict; use warnings; { package psgix::harakiri::tester; sub DESTROY { print STDERR "$$: Calling DESTROY\n" } } uwsgi::atexit( sub { print STDERR "$$: Calling the atexit hook\n"; } ); sub { my $env = shift; die "PANIC: We should support psgix.harakiri here" unless $env->{'psgix.harakiri'}; $env->{'psgix.harakiri.tester'} = bless {} => 'psgix::harakiri::tester'; my $harakiri = $env->{QUERY_STRING}; $env->{'psgix.harakiri.commit'} = $harakiri ? 1 : 0; return [200, [], [ $harakiri ? "We are about to destroy ourselves\n" : "We will live for another request\n" ]]; } uwsgi-2.0.29/t/perl/test_hello.psgi000066400000000000000000000001441477626554400172200ustar00rootroot00000000000000use strict; use warnings; sub { my $env = shift; return [200, [], [ "Hello, world!" ]]; } uwsgi-2.0.29/t/perl/test_input_with_offset.pl000066400000000000000000000034441477626554400213340ustar00rootroot00000000000000#!/usr/bin/perl #uwsgi --http-socket :9090 --psgi apps/input_with_offset.pl use IO::Socket::INET; my @tests; my $base = 'one_two_three_four'; push @tests, ['-1', 'HELLO', 'one_two_three_fouHELLO']; push @tests, ['-2', 'HELLO', 'one_two_three_foHELLO']; push @tests, ['-2', 'HELLOHELLOHELLOTEST2TEST3', 'one_two_three_foHELLOHELLOHELLOTEST2TEST3']; push @tests, ['-12', 'HELLOHELLOHELLOTEST2TEST3', 'one_twHELLOHELLOHELLOTEST2TEST3']; push @tests, ['-22', 'HELLOHELLOHELLOTEST2TEST3', "HELLOHELLOHELLOTEST2TEST3"]; push @tests, ['-22', 'HELLO', "HELLOne_two_three_four"]; push @tests, ['-23', 'HELLO', "HELLOone_two_three_four"]; push @tests, ['-25', 'HELLO', "HELLO\0\0one_two_three_four"]; push @tests, ['1', 'HELLO', "oHELLOo_three_four"]; push @tests, ['3', 'HELLO', "oneHELLOthree_four"]; push @tests, ['30', 'HELLO', "one_two_three_four\0\0\0\0\0\0\0\0\0\0\0\0HELLO"]; @ARGV or die "You must provide a host to test on, e.g. localhost:8080"; foreach(@tests) { print "testing: offset(".$_->[0].") body(".$_->[1].")\n"; my $req = "POST /?".$base." HTTP/1.0\r\nContent-Length: ".length($_->[1])."\r\nuWSGI-Offset: ".$_->[0]."\r\n\r\n".$_->[1]; my $s = IO::Socket::INET->new(PeerAddr => $ARGV[0]) or die "PANIC: Unable to construct socket"; $s->send($req); my $response = ''; while(1) { $s->recv(my $buf, 4096); last unless length($buf); $response .= $buf; } $s->close; my $expected = "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\n".$_->[2]."\n"; if ($response ne $expected) { print "TEST FOR offset(".$_->[0].") body(".$_->[1].") FAILED:\nEXPECTED\n---\n".$expected."\n---\nGOT\n---\n".$response."\n---\n"; exit; } } print "test result: SUCCESS\n"; uwsgi-2.0.29/t/perl/test_post.psgi000066400000000000000000000024301477626554400171020ustar00rootroot00000000000000use strict; use warnings; sub { my $env = shift; my $cl = $env->{CONTENT_LENGTH}; $env->{'psgi.input'}->seek(0,0); my $content = ''; while ($cl) { $env->{'psgi.input'}->read(my $chunk, $cl < 8192 ? $cl : 8192); my $read = length $chunk; $cl -= $read; $content .= $chunk; } return [200, [], [ "Your content was: <$content>" ]]; }; __END__ This is a trivial test that prints out a POST request, it's here to test a regression introduced in 2.0-103-gf041d10 where doing reads without offsets, e.g.: $ http_proxy= curl -d '{ "what": "ever" }' http://localhost:8080/ Your content was: $VAR1 = '{ "what": "ever" }'; Would result in: Use of uninitialized value in subroutine entry at /home/v-perlbrew/perl5/perlbrew/perls/perl-5.19.6/lib/site_perl/5.19.6/Plack/Request.pm line 280. Which is due to this commit having a one-off error in counting stack items. $ git bisect good f041d1095ddf7541c4b275e16d2ed3355a8e2be9 is the first bad commit commit f041d1095ddf7541c4b275e16d2ed3355a8e2be9 Author: Unbit Date: Wed Feb 5 11:21:01 2014 +0100 perl refactoring :040000 040000 98a25406b7edb9bd0b9be8bbcd351a99e7ce2d33 0087e3ca4b6bd65a087fade65d43a56085298ef0 M plugins uwsgi-2.0.29/t/perl/test_sleepy.psgi000066400000000000000000000010271477626554400174170ustar00rootroot00000000000000use strict; use warnings; use Time::HiRes qw(usleep); sub { my $env = shift; die "PANIC: We are expecting to support psgix.cleanup" unless $env->{'psgix.cleanup'}; my $msleep = 2 * 1000 + int rand 7 * 1000; # 2..10ms my $csleep = 2 * 1000 + int rand 7 * 1000; # 2..10ms push @{$env->{'psgix.cleanup.handlers'}} => sub { usleep($csleep) }; usleep($msleep); return [ 200, [], [ "Responding. Slept $msleep us in the main phase, sleeping $csleep us in the cleanup phase" ], ]; } uwsgi-2.0.29/t/perl/test_streaming.psgi000066400000000000000000000025321477626554400201110ustar00rootroot00000000000000use strict; use warnings; sub { my $env = shift; return sub { my $responder = shift; my $writer = $responder->([ 200, [ 'Content-Type', 'text/plain' ]]); sleep 3; $writer->write("hello\n"); sleep 3; $writer->write("world\n"); $writer->close; return; }; } __END__ Making a request to this will give you: $ date; curl -s -N -D - 'http://localhost:8080' Sat Mar 15 14:08:25 UTC 2014 HTTP/1.1 200 OK Content-Type: text/plain hello world And monitoring it with tcpflow shows how the output (including headers) is flushed right away: $ sudo tcpflow -i lo -c port 8080 | perl -pe 's/^/localtime . " "/ge' Sat Mar 15 14:09:08 2014 127.000.000.001.55058-127.000.000.001.08080: GET / HTTP/1.1 Sat Mar 15 14:09:08 2014 User-Agent: curl/7.35.0 Sat Mar 15 14:09:08 2014 Host: localhost:8080 Sat Mar 15 14:09:08 2014 Accept: */* Sat Mar 15 14:09:08 2014 Sat Mar 15 14:09:08 2014 Sat Mar 15 14:09:08 2014 127.000.000.001.08080-127.000.000.001.55058: HTTP/1.1 200 OK Sat Mar 15 14:09:08 2014 Content-Type: text/plain Sat Mar 15 14:09:08 2014 Sat Mar 15 14:09:08 2014 Sat Mar 15 14:09:11 2014 127.000.000.001.08080-127.000.000.001.55058: hello Sat Mar 15 14:09:11 2014 Sat Mar 15 14:09:14 2014 127.000.000.001.08080-127.000.000.001.55058: world Sat Mar 15 14:09:14 2014 uwsgi-2.0.29/t/php/000077500000000000000000000000001477626554400140205ustar00rootroot00000000000000uwsgi-2.0.29/t/php/config.ini000066400000000000000000000004171477626554400157700ustar00rootroot00000000000000[uwsgi] http-socket = :8080 http-socket-modifier1 = 14 # required for php need-app = false plugins = php cache2 = name=session,items=1000,store=/tmp/uwsgi-session-cache,bitmap=1 php-set = session.save_handler=uwsgi php-set = session.save_path=session php-docroot = %d uwsgi-2.0.29/t/php/test.php000066400000000000000000000005431477626554400155120ustar00rootroot00000000000000 0: # start waiting for socket availability (4 seconds max) uwsgi.wait_fd_write(fd, 4) # suspend execution 'til event uwsgi.suspend() pos = len(command) - remains written = uwsgi.send(fd, command[pos:]) remains -= written # now wait for memcached response uwsgi.wait_fd_read(fd, 4) uwsgi.suspend() # read a chunk of data data = uwsgi.recv(fd, 4096) # .. and yield it yield data finally: # always ensure sockets are closed uwsgi.close(fd) print("sleeping for 3 seconds...") uwsgi.async_sleep(3) uwsgi.suspend() yield "done" uwsgi-2.0.29/t/python/000077500000000000000000000000001477626554400145525ustar00rootroot00000000000000uwsgi-2.0.29/t/python/forcecl.py000066400000000000000000000003461477626554400165440ustar00rootroot00000000000000# uwsgi --route-run remheader:Content-Length --route-run forcecl: --wsgi-file t/python/forcecl.py --http-socket :9090 def application(e, sr): sr('200 OK', [('Content-Length', '1'), ('Content-Length', '2')]) return ['xxx'] uwsgi-2.0.29/t/python/helloapp.py000066400000000000000000000002001477626554400167200ustar00rootroot00000000000000def application(env, start_response): start_response("200 OK", [("Content-Type", "text/html")]) return [b"Hello World"] uwsgi-2.0.29/t/python/manage_script_name/000077500000000000000000000000001477626554400203665ustar00rootroot00000000000000uwsgi-2.0.29/t/python/manage_script_name/manage_script_name_test.ini000066400000000000000000000003071477626554400257420ustar00rootroot00000000000000[uwsgi] ; Three apps on three mountpoints wsgi-file = %d/useless_app.py mount = /foo=%d/useless_app.py mount = /foobis/=%d/useless_app.py mount = /footris/=%d/useless_app.py manage-script-name = 1 uwsgi-2.0.29/t/python/manage_script_name/useless_app.py000066400000000000000000000002261477626554400232630ustar00rootroot00000000000000def application(env, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return [env['SCRIPT_NAME'].encode('ascii'), ] uwsgi-2.0.29/t/python/spooler_decorators/000077500000000000000000000000001477626554400204625ustar00rootroot00000000000000uwsgi-2.0.29/t/python/spooler_decorators/spooler_decorator_test.ini000066400000000000000000000005551477626554400257540ustar00rootroot00000000000000[uwsgi] socket = /tmp/temporary_socket ; Spooler! spooler-import = %d/spooler_handlers.py ; Specify the spooler spooler = $(SPOOLER_DIR) ; And the number of processes spooler-processes = 1 ; Spooler ordered scanning (only works with "numbered" dirs) spooler-ordered = 1 ; Spooler frequency spooler-frequency = 1 pyrun = %d/spooler_decorator_tests.py master = 1 uwsgi-2.0.29/t/python/spooler_decorators/spooler_decorator_tests.py000066400000000000000000000020061477626554400260010ustar00rootroot00000000000000# run it with: # export SPOOLER_DIR=t/python/spooler_priority/temporary_spooler; # or your spooler dir # ./uwsgi t/python/spooler_decorators/spooler_decorator_test.ini import unittest import uwsgi import spooler_handlers from os import remove, path class BitmapTest(unittest.TestCase): def setUp(self): try: remove(spooler_handlers.ghostpath) except OSError: # file does not exist pass spooler_handlers.controlled_task.spool(arg='alive', ghost='world') spooler_handlers.controlled_task.spool(arg='barbis') spooler_handlers.controlled_raw_task.spool(arg='alive', ghost='world') spooler_handlers.controlled_raw_task.spool(arg='barbis') spooler_handlers.controlled_arguments_task.spool( {'key': 'value'}, 2, key1='value1') for i in range(5): uwsgi.signal_wait(20) print("Signal received!") def test_spooler(self): self.assertFalse(path.exists(spooler_handlers.ghostpath)) unittest.main() uwsgi-2.0.29/t/python/spooler_decorators/spooler_handlers.py000066400000000000000000000014151477626554400244000ustar00rootroot00000000000000# See spooler_decorator_tests from uwsgidecorators import spool, spoolraw import uwsgi ghostpath = "/tmp/ghost" @spool(pass_arguments=True) def controlled_arguments_task(*args, **kwargs): if args != ({'key': 'value'}, 2) or kwargs != {'key1': 'value1'}: print("We have a problem!") open(ghostpath, 'w').close() uwsgi.signal(20) @spool def controlled_task(arguments): if arguments['arg'] != 'alive' and 'ghost' in arguments: print("We have a problem!") open(ghostpath, 'w').close() uwsgi.signal(20) @spoolraw def controlled_raw_task(arguments): if arguments['arg'] != 'alive' and 'ghost' in arguments: print("We have a problem!") open(ghostpath, 'w').close() uwsgi.signal(20) return uwsgi.SPOOL_OK uwsgi-2.0.29/t/python/spooler_handler.py000066400000000000000000000012131477626554400203010ustar00rootroot00000000000000#! /usr/bin/env python2 # coding = utf-8 from __future__ import print_function from constants import tasks, LOGFILE from os import remove import uwsgi counter = 0 def spoolerHandler(env): global counter # Spooler is handling a task with open(LOGFILE, "a") as log: print("%s" % (env['name']), file=log) counter += 1 if counter == len(tasks): # Each task has been processed. uwsgi.signal(17) # Spooler has done handling the task return uwsgi.SPOOL_OK uwsgi.spooler = spoolerHandler # Clear the logfile try: remove(LOGFILE) except OSError, e: # log does not exist pass # print(e) uwsgi-2.0.29/t/python/spooler_priority/000077500000000000000000000000001477626554400201765ustar00rootroot00000000000000uwsgi-2.0.29/t/python/spooler_priority/spooler_priority_constants.py000066400000000000000000000004271477626554400262730ustar00rootroot00000000000000#! /usr/bin/env python2 # coding = utf-8 tasks = [ (101, "101"), (101, "101Bis"), (2, "2"), (1, "1"), (0, "0"), (None, "NoPriority") ] ordered_tasks = [ "0", "1", "2", "101", "101Bis", "NoPriority" ] LOGFILE = "/tmp/spoolerlog" uwsgi-2.0.29/t/python/spooler_priority/spooler_priority_handler.py000066400000000000000000000012201477626554400256640ustar00rootroot00000000000000#! /usr/bin/env python # coding = utf-8 from __future__ import print_function from spooler_priority_constants import tasks, LOGFILE from os import remove import uwsgi counter = 0 def spoolerHandler(env): global counter # Spooler is handling a task with open(LOGFILE, "a") as log: print("%s" % (env['name']), file=log) counter += 1 if counter == len(tasks): # Each task has been processed. uwsgi.signal(17) # Spooler has done handling the task return uwsgi.SPOOL_OK uwsgi.spooler = spoolerHandler # Clear the logfile try: remove(LOGFILE) except OSError, e: # log does not exist print(e) uwsgi-2.0.29/t/python/spooler_priority/spooler_priority_test.ini000066400000000000000000000006161477626554400253650ustar00rootroot00000000000000[uwsgi] socket = /tmp/temporary-socket ; Specify the spooler spooler = %d/temporary_spooler ; Spooler handler spooler-import = %d/spooler_priority_handler.py ; And the number of processes spooler-processes = 1 ; Spooler ordered scanning (only works with "numbered" dirs) spooler-ordered = 1 ; Spooler scans folder each second spooler-frequency = 1 pyrun = %d/spooler_priority_test.py master = 1 uwsgi-2.0.29/t/python/spooler_priority/spooler_priority_test.py000066400000000000000000000036731477626554400252440ustar00rootroot00000000000000#! /usr/bin/env python # coding = utf-8 import uwsgi import unittest import os import fcntl from shutil import rmtree import time from signal import signal, SIGINT import spooler_priority_constants def spoolersTaskList(): # Get the list of tasks tasks = [ os.path.join(s, fn) for s in uwsgi.spoolers for fn in os.listdir(s) ] for t in tasks[:]: if os.path.isdir(t): tasks += [os.path.join(t, fn) for fn in os.listdir(t)] tasks.remove(t) return tasks def is_locked(filepath): # Check if file is locked with open(filepath, "a+") as f: try: fcntl.lockf(f.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB) is_locked = False except IOError: is_locked = True return is_locked def lockedTasks(tasklist): # List of locked tasks return [fp for fp in spoolersTaskList() if is_locked(fp)] def taskParameters(filepath): # Retrieve parameters return uwsgi.parsefile(filepath) def cleanTasks(): # Clean any remaining task for s in uwsgi.spoolers: for f in os.listdir(s): path = os.path.join(s, f) if os.path.isdir(path): rmtree(os.path.join(s, f)) else: os.remove(path) class BitmapTest(unittest.TestCase): def setUp(self): for priority, name in spooler_priority_constants.tasks: task = {'name': name, 'at': int(time.time() + 10)} if priority is not None: task['priority'] = str(priority) uwsgi.spool(task) def test_priority(self): uwsgi.signal_wait(17) print("Signal received.") with open(spooler_priority_constants.LOGFILE) as log: # Check logging ordering. loglines = [line.rstrip() for line in log] self.assertEqual(loglines, spooler_priority_constants.ordered_tasks) signal(SIGINT, cleanTasks) unittest.main() uwsgi-2.0.29/t/python/testba.py000066400000000000000000000003011477626554400164000ustar00rootroot00000000000000import array def application(e, sr): sr('200 OK', [('Content-Type', 'text/html')]) a = array.array('b', [54, 55, 56, 57]) yield a yield bytearray(b'abcdef') yield b'ciao' uwsgi-2.0.29/t/python/testmultipleenv.py000066400000000000000000000004751477626554400203760ustar00rootroot00000000000000# uwsgi --env foo=bar --env foo2=bar --http :8080 --wsgi-file t/python/testmultipleenv.py import os assert os.getenv('foo') == 'bar' assert os.getenv('foo2') == 'bar' print os.getenv('foo') print os.getenv('foo2') def application(e, sr): sr('200 OK', [('Content-Type', 'text/html')]) return b'Hello world' uwsgi-2.0.29/t/python/timers.py000066400000000000000000000002401477626554400164230ustar00rootroot00000000000000# uwsgi --wsgi-file t/python/timers.py --http :8080 --master from uwsgidecorators import mstimer @mstimer(500) def ms_timer(signum): print("500 ms timer") uwsgi-2.0.29/t/python/wsgi_chunked.py000066400000000000000000000007441477626554400176030ustar00rootroot00000000000000def application(environ, start_response): print(environ) start_response('200 OK', []) if not environ['wsgi.input_terminated']: return [] # print(environ['wsgi.input'].read()) data = environ['wsgi.input'].read(2) print(data) data = environ['wsgi.input'].read(2) print(data) data = environ['wsgi.input'].read(2) print(data) data = environ['wsgi.input'].read(6) print(data) print(environ['wsgi.input'].read()) return [data] uwsgi-2.0.29/t/rack/000077500000000000000000000000001477626554400141515ustar00rootroot00000000000000uwsgi-2.0.29/t/rack/app.ru000066400000000000000000000001561477626554400153030ustar00rootroot00000000000000class App def call(environ) [200, {"content-type" => "text/plain"}, ['Hello']] end end run App.new uwsgi-2.0.29/t/ring/000077500000000000000000000000001477626554400141705ustar00rootroot00000000000000uwsgi-2.0.29/t/ring/README.md000066400000000000000000000004661477626554400154550ustar00rootroot00000000000000Ring Test Suite ================ how to build and run --------------------- * cd UWSGIROOT * cd t/ring * lein uberjar * cd ../.. * uwsgi t/ring/config.ini * open http://localhost:9090 in your browser run cases in jetty ------------------- * lein ring server * open http://localhost:3000 in your browser uwsgi-2.0.29/t/ring/config.ini000066400000000000000000000004021477626554400161320ustar00rootroot00000000000000[uwsgi] http-socket = :9090 http-socket-modifier1 = 8 http-socket-modifier2 = 1 jvm-classpath = plugins/jvm/uwsgi.jar jvm-classpath = t/ring/target/uwsgi-ring-tests-0.0.1-standalone.jar jvm-class = uwsgi/ring/tests/app ring-app = uwsgi.ring.tests.app/app uwsgi-2.0.29/t/ring/project.clj000066400000000000000000000004431477626554400163310ustar00rootroot00000000000000(defproject unbit/uwsgi-ring-tests "0.0.1" :description "uwsgi-ring-tests: test cases for uwsgi ring server" :dependencies [[org.clojure/clojure "1.4.0"] [compojure "1.1.5"] [ring/ring "1.1.0"]] :source-paths ["src"] :aot [uwsgi.ring.tests.app] ) uwsgi-2.0.29/t/ring/src/000077500000000000000000000000001477626554400147575ustar00rootroot00000000000000uwsgi-2.0.29/t/ring/src/uwsgi/000077500000000000000000000000001477626554400161155ustar00rootroot00000000000000uwsgi-2.0.29/t/ring/src/uwsgi/ring/000077500000000000000000000000001477626554400170545ustar00rootroot00000000000000uwsgi-2.0.29/t/ring/src/uwsgi/ring/tests/000077500000000000000000000000001477626554400202165ustar00rootroot00000000000000uwsgi-2.0.29/t/ring/src/uwsgi/ring/tests/app.clj000066400000000000000000000015311477626554400214700ustar00rootroot00000000000000(ns uwsgi.ring.tests.app (:use compojure.core) (:use [ring.middleware params keyword-params nested-params multipart-params]) (:require [compojure.route :as route] [uwsgi.ring.tests.basic :as basic] [uwsgi.ring.tests.body :as body] [uwsgi.ring.tests.simple :as simple] [uwsgi.ring.tests.upload :as upload]) (:gen-class :main true)) (defn app-routes [req] (if (= (get req :uri) "/") (basic/index-page req) ((routes simple/app-routes body/app-routes upload/app-routes (route/not-found "

    Page not found

    ")) req))) (def app (-> app-routes wrap-keyword-params wrap-nested-params wrap-params wrap-multipart-params)) (defn -main [& args] (println "uwsgi ring tests app loaded")) uwsgi-2.0.29/t/ring/src/uwsgi/ring/tests/basic.clj000066400000000000000000000021421477626554400217700ustar00rootroot00000000000000(ns uwsgi.ring.tests.basic) (defn index-page [req] {:status 200 :headers { "Content-Type" "text/html" , "Server" "uWSGI" } :body (str "

    Ring test suites

    " "

    Simple tests

    " "" "

    Body type tests

    " "" "

    Upload tests

    " "
    " "

    " "Please select a file
    " "" "

    " "" "
    " "

    Other tests

    " "
      " "
    • ...
    • " "
    ")}) uwsgi-2.0.29/t/ring/src/uwsgi/ring/tests/body.clj000066400000000000000000000011071477626554400216440ustar00rootroot00000000000000(ns uwsgi.ring.tests.body (:use [compojure.core])) ; generating primary numbers ; https://clojuredocs.org/clojure.core/lazy-seq#example_1000 (defn sieve [s] (cons (first s) (lazy-seq (sieve (filter #(not= 0 (mod % (first s))) (rest s)))))) (defn numsequence [] (take 20 (sieve (iterate inc 2)))) (defn file [] (java.io.File. "CONTRIBUTORS")) (defn stream [] (java.io.FileInputStream. (java.io.File. "CONTRIBUTORS"))) (defroutes app-routes (GET "/sequence" [] (numsequence)) (GET "/file" [] (file)) (GET "/stream" [] (stream))) uwsgi-2.0.29/t/ring/src/uwsgi/ring/tests/simple.clj000066400000000000000000000004551477626554400222050ustar00rootroot00000000000000(ns uwsgi.ring.tests.simple (:use [compojure.core]) ) (defn hello [] "Hello, World!") (defn echo [msg] msg) (defn palindrome [msg] (clojure.string/reverse msg) ) (defroutes app-routes (GET "/hello" [] (hello) ) (GET "/echo" [msg] (echo msg) ) (GET "/palindrome" [msg] (palindrome msg) ) ) uwsgi-2.0.29/t/ring/src/uwsgi/ring/tests/upload.clj000066400000000000000000000010601477626554400221710ustar00rootroot00000000000000(ns uwsgi.ring.tests.upload (:use [compojure.core])) (defn upload-file [fname fsize fbody] { :status 200 :headers { "Content-Type" "text/html" , "Server" "uWSGI" } :body (str "

    Uploaded file

    " "
      " "
    • " fname "
    • " "
    • " fsize "
    • " "
    ")}) (defroutes app-routes (POST "/upload" {params :params} (let [file (params :file) file-name (file :filename) file-size (file :size) file-body (file :tempfile)] (upload-file file-name file-size file-body)))) uwsgi-2.0.29/t/routing/000077500000000000000000000000001477626554400147205ustar00rootroot00000000000000uwsgi-2.0.29/t/routing/auth.ini000066400000000000000000000034231477626554400163640ustar00rootroot00000000000000[uwsgi] http-socket = :9090 module = werkzeug.testapp:test_app ; allows up to 100 authenticated users cache = 100 master = true ; check if a uwsgiauth cookie is available route-if-not = empty:${cookie[uwsgiauth]} goto:cookieauth ; 2 users route-run = basicauth-next:Test0001,uno:due route-run = basicauth:Test0001,test:foo ; create an uuid for authorization and place it in AUTH_UUID request var route-run = addvar:AUTH_UUID=${uwsgi[uuid]} ; place it in the cache as REMOTE_USER:REMOTE_ADDR for 1 hour route-run = cacheset:key=${AUTH_UUID},value=${REMOTE_USER}:${REMOTE_ADDR},expires=3600 ; set the auth cookie route-run = addheader:Set-Cookie: uwsgiauth=${AUTH_UUID}; Expires=${httptime[3600]} ; continue to the request plugin handler route-run = last: ; here we manage the cookie (with some logging for debug) route-label = cookieauth route-run = log:COOKIE FOUND ; set AUTH_UUID with the cookie value route-run = addvar:AUTH_UUID=${cookie[uwsgiauth]} route-run = log:AUTH_UUID=${AUTH_UUID} ; get the cache value and place it in the var route-run = cachevar:key=${AUTH_UUID},var=AUTH_VALUE route-run = log:AUTH_VALUE=${AUTH_VALUE} ; if the item is not found reset credentials route-if = empty:${AUTH_VALUE} goto:reset ; check if the cookie is valid for the remote address route-if-not = endswith:${AUTH_VALUE};:${REMOTE_ADDR} goto:reset route-run = log:OK ; set REMOTE_USER (the parser stops at the first colon) route-run = setuser:${AUTH_VALUE} ; set the auth cookie (could be useless when using some framework) route-run = addheader:Set-Cookie: uwsgiauth=${AUTH_UUID} route-run = last: ; reset credentials route-label = reset route-run = log:RESETTING CREDENTIALS route-run = addheader:Set-Cookie: uwsgiauth=invalid; expires=Thu, 01 Jan 1970 00:00:00 GMT ; force a 401 route-run = basicauth:Test0001, uwsgi-2.0.29/t/routing/errorlimiter.ini000066400000000000000000000017721477626554400201470ustar00rootroot00000000000000[uwsgi] plugins = geoip, router_cache http-socket = :9090 ; 8 bytes blocksize is the right thing to do cache2 = name=limiter,items=1000,blocksize=8 ; allows expiring items master = true ; get the cache value for the current ip (if any) route-run = cachevar:key=${REMOTE_ADDR},as_num=1,var=LIMIT ; block the peer if it did more than 10 404 requests in the last 30 seconds route-if = >:${LIMIT};10 goto:blockit ; end of routing route-run = last: module = werkzeug.testapp:test_app threads = 10 ; track the user if a 404 is returned final-route-if = equal:${uwsgi[status]};404 goto:trackit ; end of final routing final-route-run = last: final-route-label = trackit ; increase the value in the 'limiter' cache final-route-run = cacheinc:key=${REMOTE_ADDR},expires=30 ; increase the value if the connection is from italy !!! final-route-if = equal:${geoip[country_name]};Italy cacheinc:key=${REMOTE_ADDR},expires=30 ; block the client route-label = blockit route-run = log:STOP YOU BASTARD !!! route-run = break:503 uwsgi-2.0.29/t/routing/limiter.ini000066400000000000000000000012421477626554400170650ustar00rootroot00000000000000[uwsgi] http-socket = :9090 ; 8 bytes blocksize is the right thing to do cache2 = name=limiter,items=1000,blocksize=8 ; allows expiring items master = true ; get the cache value for the current ip (if any) route-run = cachevar:key=${REMOTE_ADDR},as_num=1,var=LIMIT ; block the peer if it did more than 10 requests in the last 30 seconds route-if = >:${LIMIT};10 goto:blockit ; increment the value (expires value will not be updated) route-run = cacheinc:key=${REMOTE_ADDR},expires=30 ; end of the checks route-run = last: module = werkzeug.testapp:test_app threads = 10 ; block the client route-label = blockit route-run = log:STOP YOU BASTARD !!! route-run = break:503 uwsgi-2.0.29/t/runner000077500000000000000000000161261477626554400144760ustar00rootroot00000000000000#!/usr/bin/python3 # # This test suite runner runs some integration tests for uwsgi, that is # each test launches a test server with a specific configuration and # verifies (usually using a HTTP request) that this test server behaves as # expected. # # buildconf/integration-tests.ini holds the build configuration for this # to run fine. import os import requests import signal import socket import subprocess import sys import time import unittest TESTS_DIR = os.path.dirname(__file__) UWSGI_BINARY = os.getenv("UWSGI_BINARY", os.path.join(TESTS_DIR, "..", "uwsgi")) UWSGI_PLUGINS = os.getenv("UWSGI_PLUGINS_TEST", "all").split(" ") UWSGI_ADDR = "127.0.0.1" UWSGI_PORT = 8000 UWSGI_HTTP = f"{UWSGI_ADDR}:{UWSGI_PORT}" def plugins_available(plugins): available = False if "all" in UWSGI_PLUGINS: available = True else: available = all([plugin in UWSGI_PLUGINS for plugin in plugins]) return available, f"{plugins} plugins not available but required for this test case" class UwsgiTest(unittest.TestCase): def start_server(self, args): self.testserver = subprocess.Popen( [UWSGI_BINARY] + args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, ) def uwsgi_ready(self): try: s = socket.socket() s.connect( ( UWSGI_ADDR, UWSGI_PORT, ) ) except socket.error: return False else: return True finally: s.close() def start_listen_server(self, args): self.start_server(["--http-socket", UWSGI_HTTP] + args) # ensure server is ready retries = 10 while not self.uwsgi_ready() and retries > 0: time.sleep(0.1) retries = retries - 1 if retries == 0: raise RuntimeError("uwsgi test server is not available") def tearDown(self): if hasattr(self._outcome, "errors"): # Python 3.4 - 3.10 (These two methods have no side effects) result = self.defaultTestResult() self._feedErrorsToResult(result, self._outcome.errors) else: # Python 3.11+ result = self._outcome.result ok = not (result.errors + result.failures) if hasattr(self, "testserver"): self.testserver.send_signal(signal.SIGTERM) if not ok: print(self.testserver.stdout.read(), file=sys.stderr) self.testserver.wait() self.testserver.stdout.close() def assert_GET_body(self, url_path, body_expected): with requests.get(f"http://{UWSGI_HTTP}{url_path}") as r: self.assertEqual(r.text, body_expected) def test_static_expires(self): self.start_listen_server( [ "--plugin", "notfound", os.path.join(TESTS_DIR, "static", "config.ini"), ] ) with requests.get(f"http://{UWSGI_HTTP}/foobar/config.ini") as r: self.assertTrue("Expires" in r.headers) @unittest.skipUnless(*plugins_available(["python"])) def test_mountpoints(self): self.start_listen_server( [ "--plugin", "python", os.path.join( TESTS_DIR, "python", "manage_script_name", "manage_script_name_test.ini", ), ] ) mps = {"/foo", "/foobis/", "/footris/"} for mp in mps: # Requests to /foo should kick-in the managed script name. self.assert_GET_body(mp, mp) ends = mp.endswith("/") # And equally requests to /foo/ self.assert_GET_body(f"{mp}/" if not ends else f"{mp}"[:-1], mp) # Or correct requests (/foo/resource) self.assert_GET_body(f"{mp}/resource" if not ends else f"{mp}resource", mp) mps = { "/fooanything", "/foobisis/", "/foofighters", } for mp in mps: self.assert_GET_body(mp, "") @unittest.skipUnless(*plugins_available(["python"])) def test_python3_helloworld(self): self.start_listen_server( [ "--plugin", "python", "--wsgi-file", os.path.join(TESTS_DIR, "python", "helloapp.py"), ] ) self.assert_GET_body("/", "Hello World") @unittest.skipUnless(*plugins_available(["pypy"])) def test_pypy3_helloworld(self): self.start_listen_server( [ os.path.join(TESTS_DIR, "pypy", "config.ini"), ] ) self.assert_GET_body("/", "Hello World") @unittest.skipUnless(*plugins_available(["php"])) def test_php_session(self): self.start_listen_server( [ os.path.join(TESTS_DIR, "php", "config.ini"), ] ) self.assert_GET_body("/test.php", "PASS\n") @unittest.skipUnless(*plugins_available(["jvm"])) def test_jvm_hellworld(self): classpath = ":".join( [ "/usr/share/java/uwsgi.jar", os.path.join(TESTS_DIR, "java"), os.path.join(TESTS_DIR, "..", "plugins", "jvm"), ] ) subprocess.call( [ "javac", "-classpath", classpath, os.path.join(TESTS_DIR, "java", "rpc.java"), ] ) self.start_listen_server( [ "--need-app=0", "--plugins", "0:jvm,jwsgi", "--jvm-classpath", classpath, "--jwsgi", "rpc:application", ] ) self.assert_GET_body("/", "

    null

    ") @unittest.skipUnless(*plugins_available(["psgi"])) def test_psgi_helloworld(self): self.start_listen_server( [ "--plugins", "psgi", "--psgi", os.path.join(TESTS_DIR, "perl", "test_hello.psgi"), ] ) self.assert_GET_body("/", "Hello, world!") @unittest.skipUnless(*plugins_available(["cgi"])) def test_cgi_helloworld(self): self.start_listen_server( [ "--need-app=0", "--plugins", "0:cgi", "--cgi", os.path.join(TESTS_DIR, "cgi", "hello.cgi"), ] ) self.assert_GET_body( "/foobar/say_hello", "Hello world!\nPATH_INFO=/foobar/say_hello\n" ) @unittest.skipUnless(*plugins_available(["rack"])) def test_rack_helloworld(self): self.start_listen_server( [ "--plugins", "0:rack", "--rack", os.path.join(TESTS_DIR, "rack", "app.ru"), ] ) self.assert_GET_body("/", "Hello") if __name__ == "__main__": unittest.main() uwsgi-2.0.29/t/sharedarea/000077500000000000000000000000001477626554400153305ustar00rootroot00000000000000uwsgi-2.0.29/t/sharedarea/bigranges.ini000066400000000000000000000001241477626554400177670ustar00rootroot00000000000000[uwsgi] socket = /tmp/foo sharedarea = size=4300000000 pyrun = t/sharedarea/%n.py uwsgi-2.0.29/t/sharedarea/bigranges.py000066400000000000000000000006321477626554400176440ustar00rootroot00000000000000import uwsgi import unittest class SharedareaTest(unittest.TestCase): def test_32(self): pos = 2 * (1024 ** 3) uwsgi.sharedarea_write32(0, pos, 17) self.assertEqual(uwsgi.sharedarea_read32(0, pos), 17) def test_64(self): pos = 2 * (1024 ** 3) uwsgi.sharedarea_write64(0, pos, 30) self.assertEqual(uwsgi.sharedarea_read64(0, pos), 30) unittest.main() uwsgi-2.0.29/t/sharedarea/sharedarea_incdec.ini000066400000000000000000000001141477626554400214310ustar00rootroot00000000000000[uwsgi] socket = /tmp/foo sharedarea = size=64 pyrun = t/sharedarea/%n.py uwsgi-2.0.29/t/sharedarea/sharedarea_incdec.py000066400000000000000000000020121477626554400213010ustar00rootroot00000000000000import uwsgi import unittest class SharedareaTest(unittest.TestCase): def setUp(self): uwsgi.sharedarea_write(0, 0, '\0' * 64) def test_32(self): uwsgi.sharedarea_write32(0, 0, 17) self.assertEqual(uwsgi.sharedarea_read32(0, 0), 17) def test_inc32(self): uwsgi.sharedarea_write32(0, 4, 30) uwsgi.sharedarea_inc32(0, 4, 3) self.assertEqual(uwsgi.sharedarea_read32(0, 4), 33) def test_dec32(self): uwsgi.sharedarea_write32(0, 5, 30) uwsgi.sharedarea_dec32(0, 5, 4) self.assertEqual(uwsgi.sharedarea_read32(0, 5), 26) def test_inc64(self): uwsgi.sharedarea_write64(0, 8, 17 * (1024 ** 5)) uwsgi.sharedarea_inc64(0, 8, 1) self.assertEqual(uwsgi.sharedarea_read64(0, 8), 17 * (1024 ** 5) + 1) def test_dec64(self): uwsgi.sharedarea_write64(0, 8, 30 * (1024 ** 5)) uwsgi.sharedarea_dec64(0, 8, 30 * (1024 ** 5) - 1) self.assertEqual(uwsgi.sharedarea_read64(0, 8), 1) unittest.main() uwsgi-2.0.29/t/spooler/000077500000000000000000000000001477626554400147145ustar00rootroot00000000000000uwsgi-2.0.29/t/spooler/cheap.py000066400000000000000000000011021477626554400163400ustar00rootroot00000000000000# uwsgi --spooler spool1 --spooler spool2 --spooler-cheap --spooler-frequency 5 --spooler-processes 4 --mule --shared-py-import=t/spooler/cheap.py --stats :5000 from uwsgidecorators import * import time import random import os def fake(args): time.sleep(6) return uwsgi.SPOOL_OK uwsgi.spooler = fake base = os.getcwd() spoolers = [base + '/spool1', base + '/spool2'] @mule(1) def spooler_enqueuer(): while True: print("enqueuing task...") uwsgi.spool({'one':'two', 'spooler': random.choice(spoolers)}) time.sleep(random.randrange(1, 15)) uwsgi-2.0.29/t/spooler/read.py000066400000000000000000000014071477626554400162030ustar00rootroot00000000000000# uwsgi --spooler-external t/spooler/spooldir --mule --mule --wsgi-file t/spooler/read.py --http :8080 from uwsgidecorators import spoolraw, muleloop import uwsgi import time import collections import random import os spooling_directory = uwsgi.opt['spooler-external'] @muleloop(1) def reader(): c = collections.Counter() for file in os.listdir(spooling_directory): try: task_dest = uwsgi.spooler_get_task(spooling_directory + "/" + file)["dest"] c[task_dest] += 1 except Exception as e: print(e) print(c) time.sleep(5) projects = ["uwsgi", "python", "ruby", "nginx", "memcache"] @muleloop(2) def producer(): uwsgi.spool(ud_spool_func="consumer", dest=random.choice(projects)) time.sleep(2) uwsgi-2.0.29/t/spooler/reload.py000066400000000000000000000016641477626554400165430ustar00rootroot00000000000000import os import unittest import time from subprocess import Popen, PIPE def touch(fname): with open(fname, 'a'): os.utime(fname, None) return def pgrep_spoolers(): cmd = ["pgrep", "-f", "uWSGI spooler"] proc = Popen(cmd, stdout=PIPE) rv = set(map(int, proc.stdout.readlines())) proc.terminate() return rv class MuleReloadingTest(unittest.TestCase): def test_reloading(self): try: uwsgi = Popen(["./uwsgi", "--master", "--spooler=directory", "--touch-spoolers-reload=/tmp/reload", "--socket=:0", "--auto-procname"]) subprocesses = pgrep_spoolers() touch("/tmp/reload") time.sleep(1) new_subprocesses = pgrep_spoolers() proc_intersect = subprocesses.intersection(new_subprocesses) self.assertFalse(proc_intersect) finally: uwsgi.terminate() if __name__ == "__main__": unittest.main() uwsgi-2.0.29/t/spooler/spooldir/000077500000000000000000000000001477626554400165475ustar00rootroot00000000000000uwsgi-2.0.29/t/spooler/spooldir/.gitignore000066400000000000000000000000001477626554400205250ustar00rootroot00000000000000uwsgi-2.0.29/t/static/000077500000000000000000000000001477626554400145205ustar00rootroot00000000000000uwsgi-2.0.29/t/static/config.ini000066400000000000000000000001321477626554400164620ustar00rootroot00000000000000[uwsgi] need-app = False static-map = /foobar=%d static-expires-uri = ^/foobar/ 315360000 uwsgi-2.0.29/t/webdav/000077500000000000000000000000001477626554400145015ustar00rootroot00000000000000uwsgi-2.0.29/t/webdav/carddav.ini000066400000000000000000000007131477626554400166070ustar00rootroot00000000000000#! uwsgi -S addressbook=./carddav carddav.ini [uwsgi] plugin = webdav http-socket = :9090 http-socket-modifier1 = 35 route-run = basicauth:CardDav uWSGI server,unbit:unbit webdav-add-option = addressbook webdav-principal-base = /principals/users/ webdav-add-prop-href = urn:ietf:params:xml:ns:carddav addressbook-home-set /principals/users/unbit webdav-add-rtype-collection-prop = urn:ietf:params:xml:ns:carddav addressbook webdav-mount = %(addressbook) uwsgi-2.0.29/t/xslt/000077500000000000000000000000001477626554400142235ustar00rootroot00000000000000uwsgi-2.0.29/t/xslt/cd.xml000066400000000000000000000006641477626554400153410ustar00rootroot00000000000000 Quintessence Borknagar Torn Beyond Reason Woods Of Desolation Autumn Aurora Drudkh Om Negura Bunget Frostnacht Helrunar uwsgi-2.0.29/t/xslt/cd.xml.xslt000066400000000000000000000012431477626554400163240ustar00rootroot00000000000000

    Blackmetal albums

    Title Artist
    --
    uwsgi-2.0.29/t/xslt/routex.ini000066400000000000000000000003261477626554400162530ustar00rootroot00000000000000[uwsgi] http-socket = :9090 plugin = xslt xml_storage = t/xslt route = /(.*)$ xslt:doc=%(xml_storage)/$1.xml,stylesheet=%(xml_storage)/$1.xml.xslt,content_type=text/html,params=foobar=test&agent=${HTTP_USER_AGENT} uwsgi-2.0.29/tests/000077500000000000000000000000001477626554400141305ustar00rootroot00000000000000uwsgi-2.0.29/tests/Responder.pm000066400000000000000000000017661477626554400164410ustar00rootroot00000000000000package Responder; sub new { my $class = shift; my $self = { _env => shift, _counter => 0, _fd => -1, }; bless $self, $class; return $self; } sub getline { my $self = shift; if ($self->{_counter} > 10) { return undef; } elsif ($self->{_counter} == 3) { $self->{_counter}++; $self->{_fd} = uwsgi::async_connect("81.174.68.52:80"); return uwsgi::wait_fd_write($self->{_fd}, 3); } elsif ($self->{_counter} == 4) { $self->{_counter}++; return "connected to https://projects.unbit.it
    "; } elsif ($self->{_counter} == 7) { $self->{_counter}++; print "suspending the app...\n"; uwsgi::async_sleep(3); uwsgi::suspend(); print "resumed the app\n"; return "Suspended and Resumed the app
    "; } elsif ($self->{_counter} % 2 == 0) { $self->{_counter}++; print "sleeping...\n"; return uwsgi::async_sleep(1); } else { $self->{_counter}++; return "Hello World ".$self->{_counter}."
    "; } } sub close { my $self = shift; uwsgi::log("goodbye...\n"); } 1 uwsgi-2.0.29/tests/__init__.py000066400000000000000000000000001477626554400162270ustar00rootroot00000000000000uwsgi-2.0.29/tests/badthread.py000066400000000000000000000001001477626554400164070ustar00rootroot00000000000000def application(env, start_response): while 1: pass uwsgi-2.0.29/tests/badwrites.py000066400000000000000000000011221477626554400164620ustar00rootroot00000000000000import time def application(e, sr): time.sleep(3) print("3 seconds elapsed") sr('200 Ok', [('Content-Type', 'text/html')]) time.sleep(2) print("2 seconds elapsed") yield "part1" try: time.sleep(2) except Exception: print("CLIENT DISCONNECTED !!!") print("2 seconds elapsed") yield "part2" try: time.sleep(2) except Exception: print("CLIENT DISCONNECTED !!!") print("2 seconds elapsed") yield "part3" time.sleep(2) print("2 seconds elapsed") yield "part4" print("end of request") uwsgi-2.0.29/tests/cpubound_async.py000066400000000000000000000003111477626554400175110ustar00rootroot00000000000000import time def application(env, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) for i in range(1, 1000): yield "

    %s at %s

    " % (i, str(time.time())) uwsgi-2.0.29/tests/cpubound_green.py000066400000000000000000000006531477626554400175050ustar00rootroot00000000000000import uwsgi import time def application(env, start_response): counter = 0 start_response('200 OK', [('Content-Type', 'text/html')]) start_time = time.time() for i in range(1, 100000): uwsgi.suspend() # print every 100 if i % 100 == 0: yield "

    %d

    \n" % i counter = counter + i yield "

    %d cycles after %d

    \n" % (counter, time.time() - start_time) uwsgi-2.0.29/tests/cpubound_stackless.py000066400000000000000000000005171477626554400204000ustar00rootroot00000000000000import time import stackless def application(env, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) for i in range(1, 100000): yield "

    %s at %s

    \n" % (i, str(time.time())) # schedule every 2 if i % 2 == 0: stackless.schedule() print("DONE AT %d" % i) uwsgi-2.0.29/tests/deadlocks/000077500000000000000000000000001477626554400160615ustar00rootroot00000000000000uwsgi-2.0.29/tests/deadlocks/main.py000066400000000000000000000002461477626554400173610ustar00rootroot00000000000000def application(env, start_response): start_response("200 OK", [("Content-Type", "text/plain")]) message = "Hello World" return [message.encode("utf-8")] uwsgi-2.0.29/tests/deadlocks/master-nothreads.ini000066400000000000000000000001541477626554400220420ustar00rootroot00000000000000[uwsgi] show-config = true master = true enable-threads = false workers = 1 py-call-uwsgi-fork-hooks = true uwsgi-2.0.29/tests/deadlocks/master-singleinterpreter-threads-10workers.ini000066400000000000000000000002061477626554400271010ustar00rootroot00000000000000[uwsgi] show-config = true master = true enable-threads = true workers = 10 single-interpreter = true py-call-uwsgi-fork-hooks = true uwsgi-2.0.29/tests/deadlocks/master-singleinterpreter-threads-1worker.ini000066400000000000000000000002051477626554400266350ustar00rootroot00000000000000[uwsgi] show-config = true master = true enable-threads = true workers = 1 single-interpreter = true py-call-uwsgi-fork-hooks = true uwsgi-2.0.29/tests/deadlocks/master-threads-10workers.ini000066400000000000000000000001541477626554400233400ustar00rootroot00000000000000[uwsgi] show-config = true master = true enable-threads = true workers = 10 py-call-uwsgi-fork-hooks = true uwsgi-2.0.29/tests/deadlocks/master-threads-1worker.ini000066400000000000000000000001531477626554400230740ustar00rootroot00000000000000[uwsgi] show-config = true master = true enable-threads = true workers = 1 py-call-uwsgi-fork-hooks = true uwsgi-2.0.29/tests/deadlocks/nomaster-threads-10workers.ini000066400000000000000000000001551477626554400236760ustar00rootroot00000000000000[uwsgi] show-config = true master = false enable-threads = true workers = 10 py-call-uwsgi-fork-hooks = true uwsgi-2.0.29/tests/deadlocks/nomaster-threads-1worker.ini000066400000000000000000000001541477626554400234320ustar00rootroot00000000000000[uwsgi] show-config = true master = false enable-threads = true workers = 1 py-call-uwsgi-fork-hooks = true uwsgi-2.0.29/tests/deadlocks/sitecustomize.py000066400000000000000000000003631477626554400213440ustar00rootroot00000000000000import threading import time def run(): print("[DEADLOCKS] started run") st = time.time() while time.time() < st + 5: pass print("[DEADLOCKS] finished run") t = threading.Thread(target=run) t.daemon = True t.start() uwsgi-2.0.29/tests/decoratortest.py000066400000000000000000000071041477626554400173660ustar00rootroot00000000000000#!./uwsgi --import decoratortest -s :3035 -M --spooler myspool --enable-threads -p 8 --spooler-ordered import uwsgi from uwsgidecorators import * from uwsgicc import app as application # NOQA import time from six.moves import range # register rpc function helloworld @rpc("helloworld") def hello2(): return "[RPC] Hello World" # register signal 1 @signal(1) def what_time_is_it(num): print(time.asctime()) # register signal 100 @signal(100, target='workers') def what_time_is_it(num): print("*** I AM THE WORKER %d AT %s ***" % (uwsgi.worker_id(), time.asctime())) # a 3 seconds timer @timer(3) def salut(num): print("Salut !!! 3 seconds elapsed and signal %d raised" % num) # a 10 seconds red black timer (executed by the spooler) @rbtimer(10, target='spooler') def tenseconds(num): print("red black timer !!! 10 seconds elapsed and signal %d raised" % num) # monitor /tmp directory @filemon("/tmp") def tmpmodified(num): print("/tmp has been modified") # spool a long running task @spool def a_long_task(args): for i in range(1, 10): print("%s = %d" % (str(args), i)) print(uwsgi.call('helloworld')) time.sleep(1) # continuously spool a long running task @spoolforever def an_infinite_task(args): for i in range(1, 4): print("infinite: %d %s" % (i, str(args))) print(uwsgi.call('helloworld')) uwsgi.signal(100) time.sleep(1) # spool a task after 5 seconds @spool def delayed_task(args): print("*** I am a delayed spool job. It is %s [%s]***" % (time.asctime(), str(args))) # send a signal to all workers uwsgi.signal(100) @spool def big_body_task(args): print("*** managing a task with a body of %d bytes ***" % len(args['body'])) print(args['body'].swapcase()) # run a task every hour @cron(59, -1, -1, -1, -1) def one_hour_passed(num): print("received signal %d after 1 hour" % num) @thread def a_running_thread(): while True: time.sleep(2) print("i am a no-args thread") @thread def a_running_thread_with_args(who): while True: time.sleep(2) print("Hello %s (from arged-thread)" % who) @postfork @thread def a_post_fork_thread(): while True: time.sleep(3) if uwsgi.i_am_the_spooler(): print("Hello from a thread in the spooler") else: print("Hello from a thread in worker %d" % uwsgi.worker_id()) @postfork def fork_happened(): print("fork() has been called [1]") @postfork def fork_happened2(): if uwsgi.i_am_the_spooler(): return print("worker %d is waiting for signal 100..." % uwsgi.worker_id()) uwsgi.signal_wait(100) print("worker %d received signal %d" % (uwsgi.worker_id(), uwsgi.signal_received())) print("fork() has been called [2] wid: %d" % uwsgi.worker_id()) @postfork @lock def locked_func(): print("starting locked function on worker %d" % uwsgi.worker_id()) for i in range(1, 5): time.sleep(1) print("[locked %d] waiting..." % uwsgi.worker_id()) print("done with locked function on worker %d" % uwsgi.worker_id()) print(uwsgi.call('helloworld')) spool_filename = a_long_task.spool({'foo': 'bar'}, hello='world') print("spool filename = %s" % spool_filename) an_infinite_task.spool(foo='bar', priority=3) when = int(time.time())+5 print("scheduling a delayed task at %d" % when) delayed_task.spool(foo2='bar2', at=when) a_running_thread() a_running_thread_with_args("uWSGI") uwsgi_source_file = open('uwsgi.c') print(big_body_task.spool(priority=9, filename='uwsgi.c', body=uwsgi_source_file.read())) uwsgi_source_file.close() uwsgi-2.0.29/tests/else_test.ini000066400000000000000000000003471477626554400166240ustar00rootroot00000000000000[uwsgi] if-hostname = foobar print = ok1 print = ok2 print = ok3 else = print = no1 print = no2 print = no3 socket = 127.0.0.1:0 else_executed = 1 endif = print = done if-not-opt = else_executed exit = 17 end = uwsgi-2.0.29/tests/fileserve_async.py000066400000000000000000000006461477626554400176710ustar00rootroot00000000000000import sys import mimetypes basedir = sys.argv[1] mimetypes.init() def application(environ, start_response): filename = basedir + environ['PATH_INFO'] (content_type, encoding) = mimetypes.guess_type(filename) if not content_type: content_type = 'text/plain' start_response('200 OK', [('Content-Type', content_type)]) fd = open(filename) yield environ['wsgi.file_wrapper'](fd, 32*1024) uwsgi-2.0.29/tests/gevent_spool.py000066400000000000000000000006351477626554400172120ustar00rootroot00000000000000from uwsgidecorators import * import gevent @spool def longtask(*args): print(args) return uwsgi.SPOOL_OK def level2(): longtask.spool(foo='bar', test1='test2') def level1(): gevent.spawn(level2) def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) gevent.spawn(level1) for i in range(100): yield "counter: %d
    " % i uwsgi-2.0.29/tests/gh-deadlocks.sh000077500000000000000000000002641477626554400170160ustar00rootroot00000000000000#!/bin/bash set -u PYTHON_VERSION="$1" . "./tests/gh-shared.sh" for INI_FILE in tests/deadlocks/*.ini ; do test_python_deadlocks "${PYTHON_VERSION}" "$INI_FILE" done results uwsgi-2.0.29/tests/gh-python.sh000077500000000000000000000003221477626554400164010ustar00rootroot00000000000000#!/bin/bash set -u PYTHON_VERSION="$1" . "./tests/gh-shared.sh" for WSGI_FILE in tests/staticfile.py tests/testworkers.py tests/testrpc.py ; do test_python "${PYTHON_VERSION}" "${WSGI_FILE}" done results uwsgi-2.0.29/tests/gh-rack.sh000077500000000000000000000002341477626554400160020ustar00rootroot00000000000000#!/bin/bash set -u RACK_VERSION="$1" . "./tests/gh-shared.sh" for RACK in examples/config2.ru ; do test_rack "${RACK_VERSION}" "${RACK}" done results uwsgi-2.0.29/tests/gh-shared.sh000077500000000000000000000063621477626554400163400ustar00rootroot00000000000000#!/bin/bash txtund=$(tput sgr 0 1) # underline txtbld=$(tput bold) # bold bldred=${txtbld}$(tput setaf 1) # red bldgre=${txtbld}$(tput setaf 2) # green bldyel=${txtbld}$(tput setaf 3) # yellow bldblu=${txtbld}$(tput setaf 4) # blue txtcya=$(tput setaf 6) # cyan bldwht=${txtbld}$(tput setaf 7) # white txtrst=$(tput sgr0) # reset ERROR=0 SUCCESS=0 die() { date > reload.txt sleep 3 pidof uwsgi && killall uwsgi sleep 1 pidof uwsgi && killall -9 uwsgi echo -e "$@" if [ -e uwsgi.log ]; then echo -e "${bldyel}>>> uwsgi.log:${txtrst}" echo -e "${txtcya}" cat uwsgi.log echo -e "${txtrst}" fi } http_test() { URL=$1 UPID=`pidof uwsgi` if [ "$UPID" != "" ]; then echo -e "${bldgre}>>> Spawned PID $UPID, running tests${txtrst}" sleep 5 curl -fI $URL RET=$? if [ $RET != 0 ]; then die "${bldred}>>> Error during curl run${txtrst}" ERROR=$((ERROR+1)) else SUCCESS=$((SUCCESS+1)) fi die "${bldyel}>>> SUCCESS: Done${txtrst}" else die "${bldred}>>> ERROR: uWSGI did not start${txtrst}" ERROR=$((ERROR+1)) fi } test_python() { date > reload.txt rm -f uwsgi.log echo -e "${bldyel}================== TESTING $1 $2 =====================${txtrst}" echo -e "${bldyel}>>> Spawning uWSGI python app${txtrst}" echo -en "${bldred}" ./uwsgi --master --plugin 0:$1 --http :8080 --exit-on-reload --touch-reload reload.txt --wsgi-file $2 --daemonize uwsgi.log sleep 1 echo -en "${txtrst}" http_test "http://localhost:8080/" echo -e "${bldyel}===================== DONE $1 $2 =====================${txtrst}\n\n" } test_python_deadlocks() { date > reload.txt rm -f uwsgi.log echo -e "${bldyel}================== TESTING DEADLOCKS $1 $2 =====================${txtrst}" echo -e "${bldyel}>>> Starting python app${txtrst}" echo -en "${bldred}" # initialize with tests/deadlocks/sitecustomize.py PYTHONPATH=tests/deadlocks ./uwsgi --plugin 0:$1 --http :8080 --exit-on-reload --touch-reload reload.txt --wsgi-file tests/deadlocks/main.py --ini $2 --daemonize uwsgi.log sleep 1 echo -en "${txtrst}" http_test "http://localhost:8080/" echo -e "${bldyel}===================== DONE $1 $2 =====================${txtrst}\n\n" } test_rack() { date > reload.txt rm -f uwsgi.log # the code assumes that ruby environment is activated by `rvm use` echo -e "${bldyel}================== TESTING $1 $2 =====================${txtrst}" echo -e "${bldyel}>>> Installing sinatra gem using gem${txtrst}" sudo gem install sinatra -v 2.2.2 || die echo -e "${bldyel}>>> Spawning uWSGI rack app${txtrst}" echo -en "${bldred}" ./uwsgi --master --plugin 0:$1 --http :8080 --exit-on-reload --touch-reload reload.txt --rack $2 --daemonize uwsgi.log echo -en "${txtrst}" http_test "http://localhost:8080/hi" echo -e "${bldyel}===================== DONE $1 $2 =====================${txtrst}\n\n" } results() { echo "${bldgre}>>> $SUCCESS SUCCESSFUL TEST(S)${txtrst}" if [ $ERROR -ge 1 ]; then echo "${bldred}>>> $ERROR FAILED TEST(S)${txtrst}" exit 1 fi exit 0 } uwsgi-2.0.29/tests/grunter.py000066400000000000000000000011441477626554400161700ustar00rootroot00000000000000import uwsgi import time from six.moves import range def application(env, start_response): start_response('200 Ok', [('Content-Type', 'text/html')]) yield "I am the worker %d
    " % uwsgi.worker_id() grunt = uwsgi.grunt() if grunt is None: print("worker %d detached" % uwsgi.worker_id()) else: yield "And now i am the grunt with a fix worker id of %d
    " % uwsgi.worker_id() time.sleep(2) yield "Now, i will start a very slow task...
    " for i in range(1, 10): yield "waiting for %d seconds
    " % i time.sleep(i) uwsgi-2.0.29/tests/harakiri.py000066400000000000000000000013661477626554400163020ustar00rootroot00000000000000# ./uwsgi --master --http :8080 --harakiri 1 --wsgi-file tests/harakiri.py --harakiri-graceful-timeout 1 --py-call-osafterfork --lazy-apps --enable-threads --threads 2 --harakiri-graceful-signal 31 import time import uwsgi import signal import sys import atexit def sig_handler(n, fp): print("[Python App] attempting graceful shutdown triggered by harakiri (signal %d)" % n) exit(1) def application(e, s): print("[Python App] sleeping") time.sleep(3) s('200 OK', [('Content-Type', 'text/html')]) return [b"OK"] def exit_handler(): time.sleep(3) # Should not reach this line (graceful harakiri deadline expired) print("[Python App] exiting now") atexit.register(exit_handler) signal.signal(signal.SIGSYS, sig_handler) uwsgi-2.0.29/tests/iobound_async.py000066400000000000000000000016631477626554400173440ustar00rootroot00000000000000import uwsgi def send_request(env, client): uwsgi.send(client, b"GET /intl/it_it/images/logo.gif HTTP/1.0\r\n") # test for suspend/resume uwsgi.suspend() uwsgi.send(client, b"Host: www.google.it\r\n\r\n") while 1: yield uwsgi.wait_fd_read(client, 2) if env['x-wsgiorg.fdevent.timeout']: return buf = uwsgi.recv(client, 4096) if buf: yield buf else: break def application(env, start_response): c = uwsgi.async_connect('74.125.232.115:80') # wait for connection yield uwsgi.wait_fd_write(c, 2) if env['x-wsgiorg.fdevent.timeout']: uwsgi.close(c) raise StopIteration if uwsgi.is_connected(c): for r in send_request(env, c): yield r else: start_response('500 Internal Server Error', [('Content-Type', 'text/html')]) yield "Internal Server Error" uwsgi.close(c) uwsgi-2.0.29/tests/iobound_async_unix.py000066400000000000000000000023101477626554400203750ustar00rootroot00000000000000import socket import errno import struct def send_request(env, client): client.setblocking(1) data = "hello world\r\n" # send uwsgi-echo header client.send(struct.pack('I am Mako at ${thetime}") uwsgi.green_schedule() yield mytemplate.render(thetime=time.time()) for i in range(1, 100): mytemplate = Template("Iteration ${thei} at ${thetime}
    ") uwsgi.green_schedule() yield mytemplate.render(thei=i, thetime=time.time()) uwsgi-2.0.29/tests/mule_file.py000066400000000000000000000001421477626554400164400ustar00rootroot00000000000000# uwsgi --master --plugins=python --mule=mule_file.py -s:0 import uwsgi print(uwsgi.mule_file()) uwsgi-2.0.29/tests/mulefunc.py000066400000000000000000000013071477626554400163210ustar00rootroot00000000000000from uwsgidecorators import * @timer(3, target='mule1') def hello_timer(signum): print("3 seconds elapsed") @mulefunc def conto_fino_a_dieci(uno, due, tre): print("MULE ID %d: conto_fino_a_dieci" % uwsgi.mule_id(), uno, due, tre) @mulefunc(2) def conto_fino_a_venti(uno, due, tre): print("MULE ID %d: conto_fino_a_venti" % uwsgi.mule_id(), uno, due, tre) @mulefunc('topogigio') def conto_fino_a_trenta(uno, due, tre): print("MULE ID %d: conto_fino_a_trenta" % uwsgi.mule_id(), uno, due, tre) def application(e, sr): conto_fino_a_dieci(1, 2, 3) conto_fino_a_venti(4, 5, 6) conto_fino_a_trenta(7, 8, 9) sr('200 OK', [('Content-Type', 'text/html')]) return "MULE !!!" uwsgi-2.0.29/tests/multiapp.txt000066400000000000000000000003371477626554400165270ustar00rootroot00000000000000- case 1 single static app - case 2 single static multiapp - case 3 multi app static mountpoint - case 4 dynamic apps with UWSGI_APPID - case 5 dynamic apps with SCRIPT_NAME - case 6 dynamic apps with vhost mode uwsgi-2.0.29/tests/myadmin.py000066400000000000000000000006201477626554400161360ustar00rootroot00000000000000import uwsgi import struct import sys print(sys.argv) if len(sys.argv) == 3: chunks = uwsgi.send_message(sys.argv[1], 10, int(sys.argv[2]), '') pkt = '' for chunk in chunks: pkt += chunk print("%d = %d" % (int(sys.argv[2]), struct.unpack("I", pkt)[0])) elif len(sys.argv) == 4: uwsgi.send_message(sys.argv[1], 10, int(sys.argv[2]), struct.pack("I", int(sys.argv[3]))) uwsgi-2.0.29/tests/pgbound_async.py000066400000000000000000000020701477626554400173340ustar00rootroot00000000000000import psycopg2 def pg_wait(conn, env, timeout=0): while 1: state = conn.poll() if state == psycopg2.extensions.POLL_OK: raise StopIteration elif state == psycopg2.extensions.POLL_WRITE: yield env['x-wsgiorg.fdevent.writable'](conn.fileno(), timeout) elif state == psycopg2.extensions.POLL_READ: yield env['x-wsgiorg.fdevent.readable'](conn.fileno(), timeout) else: raise psycopg2.OperationalError("poll() returned %s" % state) def application(env, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) connection = psycopg2.connect(database='uwsgi', user='uwsgi', password='uwsgi', host='192.168.173.100', async=1) for i in pg_wait(connection, env, 3): yield i print("connected") cursor = connection.cursor() cursor.execute("SELECT * FROM foo") for i in pg_wait(cursor.connection, env, 3): yield i print("query result available") for record in cursor: yield str(record) connection.close() uwsgi-2.0.29/tests/picazzo.py000066400000000000000000000010551477626554400161620ustar00rootroot00000000000000from picasso import * def home(req): if not req["session"].get("user"): return redirect("/login") return "

    Welcome back, %s!

    " % req["session"]["user"] def login(req): return "
    " def login_post(req): print(req) req["session"]["user"] = "James" return redirect("/") routes = setup_routes( GET("/", home), GET("/login", login), POST("/login", login_post), routing.not_found("

    Not Found

    ") ) app = setup_app(routes) uwsgi-2.0.29/tests/psycogreen_green.py000066400000000000000000000021301477626554400200340ustar00rootroot00000000000000import uwsgi import psycopg2 def ugreen_wait_callback(conn, timeout=-1): """A wait callback useful to allow uWSGI/uGreen to work with Psycopg.""" while True: state = conn.poll() if state == psycopg2.extensions.POLL_OK: break elif state == psycopg2.extensions.POLL_READ: uwsgi.green_wait_fdread(conn.fileno()) elif state == psycopg2.extensions.POLL_WRITE: uwsgi.green_wait_fdwrite(conn.fileno()) else: raise Exception("Unexpected result from poll: %r", state) # set the wait callback psycopg2.extensions.set_wait_callback(ugreen_wait_callback) def application(env, start_response): start_response('200 Ok', [('Content-type', 'text/html')]) # connect conn = psycopg2.connect("dbname=prova user=postgres") # get cursor curs = conn.cursor() yield "" # run query curs.execute("SELECT * FROM tests") while True: row = curs.fetchone() if not row: break yield "" % str(row) yield "
    %s
    " conn.close() uwsgi-2.0.29/tests/psycopg2_green.py000066400000000000000000000023141477626554400174300ustar00rootroot00000000000000# uwsgi --async 1000 --ugreen import uwsgi import psycopg2 def async_wait(conn): # conn can be a connection or a cursor if not hasattr(conn, 'poll'): conn = conn.connection # interesting part: suspend until ready while True: state = conn.poll() if state == psycopg2.extensions.POLL_OK: break elif state == psycopg2.extensions.POLL_READ: uwsgi.wait_fd_read(conn.fileno()) uwsgi.suspend() elif state == psycopg2.extensions.POLL_WRITE: uwsgi.wait_fd_write(conn.fileno()) uwsgi.suspend() else: raise Exception("Unexpected result from poll: %r", state) def application(env, start_response): start_response('200 Ok', [('Content-type', 'text/html')]) conn = psycopg2.connect("dbname=template1 user=postgres", async=True) # suspend until connection async_wait(conn) curs = conn.cursor() yield "" curs.execute("SELECT * FROM tests") # suspend until result async_wait(curs) while True: row = curs.fetchone() if not row: break yield "" % str(row) yield "
    %s
    " conn.close() uwsgi-2.0.29/tests/pump.py000066400000000000000000000003741477626554400154670ustar00rootroot00000000000000def app(req): print(req) ret = { "status": 200, "headers": { "content_type": "text/html", "foo": ['bar0', 'bar1', 'bar2'] }, "body": "

    Hello!

    ", } print(ret) return ret uwsgi-2.0.29/tests/queue.py000066400000000000000000000024751477626554400156360ustar00rootroot00000000000000# uwsgi --queue 10 --queue-store test.queue --master --module tests.queue --socket :3031 import uwsgi import os from flask import Flask, render_template, request, redirect, flash app = Flask(__name__) app.debug = True app.secret_key = os.urandom(24) @app.route('/') def index(): return render_template('queue.html', uwsgi=uwsgi) @app.route('/push', methods=['POST']) def push_item(): if uwsgi.queue_push(request.form['body']): flash('item enqueued') return redirect('/') else: flash('unable to enqueue item') return render_template('queue.html', uwsgi=uwsgi) @app.route('/get', methods=['POST']) def get_item(): flash("slot %s value = %s" % (request.form['slot'], uwsgi.queue_get(int(request.form['slot'])))) return redirect('/') @app.route('/pop', methods=['POST']) def pop_item(): flash("popped value = %s" % uwsgi.queue_pop()) return redirect('/') @app.route('/pull', methods=['POST']) def pull_item(): flash("pulled value = %s" % uwsgi.queue_pull()) return redirect('/') @app.route('/set', methods=['POST']) def set_item(): if uwsgi.queue_set(int(request.form['pos']), request.form['body']): flash('item set') return redirect('/') else: flash('unable to set item') return render_template('queue.html', uwsgi=uwsgi) uwsgi-2.0.29/tests/refcount.py000066400000000000000000000002411477626554400163240ustar00rootroot00000000000000import sys def application(e, sr): sr('200 OK', [('Content-Type', 'text/html')]) print(sys.gettotalrefcount()) yield '%s' % sys.gettotalrefcount() uwsgi-2.0.29/tests/rpc.lua000066400000000000000000000006511477626554400154210ustar00rootroot00000000000000function hello() return "Hello i am Lua" end function hello2() return "Hello i am Lua [2]" end function hello3(arg1) return "Hello i am a Lua function with 1 arg "..arg1 end function hello4(arg1, arg2) return "Hello i am a Lua function with 2 args "..arg1.." "..arg2 end uwsgi.register_rpc("hello", hello) uwsgi.register_rpc("hello2", hello2) uwsgi.register_rpc("hello3", hello3) uwsgi.register_rpc("hello4", hello4) uwsgi-2.0.29/tests/rpc.py000066400000000000000000000002021477626554400152600ustar00rootroot00000000000000import uwsgi def hello(): return "Hello World" print(uwsgi.register_rpc("hello", hello)) print(uwsgi.rpc(None, "hello")) uwsgi-2.0.29/tests/runningthread.py000066400000000000000000000004601477626554400173520ustar00rootroot00000000000000from threading import Thread import time import uwsgi def mess(): while True: for i in range(0, 100): if uwsgi.ready(): uwsgi.signal(17) print(i) time.sleep(0.1) t = Thread(target=mess) t.daemon = True t.start() print("thread started") uwsgi-2.0.29/tests/sendchunked.py000066400000000000000000000005271477626554400170010ustar00rootroot00000000000000import socket import sys from six.moves import input s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) (addr, port) = sys.argv[1].split(':') s.connect((addr, int(port))) s.send("POST /send HTTP/1.1\r\n") s.send("Transfer-Encoding: chunked\r\n\r\n") while True: msg = input("msg >> ") s.send("%X\r\n%s\r\n" % (len(msg), msg)) uwsgi-2.0.29/tests/sharedarea.py000066400000000000000000000005661477626554400166100ustar00rootroot00000000000000import uwsgi uwsgi.sharedarea_writelong(173, 30) def application(e, sr): sr('200 Ok', [('Content-Type', 'text/html')]) uwsgi.sharedarea_write(17, e['REQUEST_URI']) uwsgi.sharedarea_inclong(173) uwsgi.sharedarea_inclong(173, 17) yield uwsgi.sharedarea_read(17, len(e['REQUEST_URI'])) yield "
    " yield str(uwsgi.sharedarea_readlong(173)) uwsgi-2.0.29/tests/sig.lua000066400000000000000000000004261477626554400154170ustar00rootroot00000000000000function hello_signal(sig, payload) print("i am Lua received signal " .. sig .. " with payload " .. payload) end uwsgi.register_signal(1, 1, hello_signal, "roberta") uwsgi.register_signal(2, 1, hello_signal, "serena") uwsgi.register_signal(3, 1, hello_signal, "alessandro") uwsgi-2.0.29/tests/signals.py000066400000000000000000000020071477626554400161410ustar00rootroot00000000000000import uwsgi def hello_signal(num, payload): print("i am the signal %d" % num) def hello_signal2(num, payload): print("i am the signal %d with payload: %s" % (num, payload)) def hello_file(num, filename): print("file %s has been modified !!!" % filename) def hello_timer(num, secs): print("%s seconds elapsed" % secs) # uwsgi.register_signal(30, uwsgi.SIGNAL_KIND_WORKER, hello_signal) uwsgi.register_signal(30, "workers", hello_signal) uwsgi.register_signal(22, "worker", hello_signal2, "*** PAYLOAD FOO ***") uwsgi.register_file_monitor(3, "/tmp", "workers", hello_file) uwsgi.register_timer(26, 2, "worker", hello_timer) uwsgi.register_timer(17, 4, "worker2", hello_timer) uwsgi.register_timer(5, 8, "worker3", hello_timer) def application(env, start_response): start_response('200 Ok', [('Content-Type', 'text/html')]) # this will send a signal to the master that will report it to the first available worker uwsgi.signal(30) uwsgi.signal(22) return "signals sent to workers" uwsgi-2.0.29/tests/sigwait.py000066400000000000000000000012051477626554400161470ustar00rootroot00000000000000import uwsgi from uwsgidecorators import * @signal(17, target='workers') def hello(signum): print("I AM THE WORKER %d" % uwsgi.worker_id()) @signal(30, target='worker2') def hello2(signum): print("I AM THE WORKER 2") @postfork def wait_for_signal(): if uwsgi.worker_id() != 2: print("waiting for a signal...") uwsgi.signal_wait() print("signal %d received" % uwsgi.signal_received()) def application(e, s): s('200 OK', [('Content-Type', 'text/html')]) if e['PATH_INFO'] == '/30': uwsgi.signal(30) uwsgi.signal(100) else: uwsgi.signal(17) return "Signal raised" uwsgi-2.0.29/tests/sleeping_async.py000066400000000000000000000004451477626554400175100ustar00rootroot00000000000000import uwsgi sleepvalue = 5 def application(env, start_response): start_response('200 Ok', [('Content-type', 'text/html')]) yield uwsgi.async_sleep(sleepvalue) # print("TIMEOUT: ", env['x-wsgiorg.fdevent.timeout']) yield "

    Hello World after %d seconds

    " % sleepvalue uwsgi-2.0.29/tests/sleeping_green.py000066400000000000000000000007241477626554400174730ustar00rootroot00000000000000import uwsgi import time def application(env, start_response): sleepvalue = 5 if 'QUERY_STRING' in env: if env['QUERY_STRING'] != '': sleepvalue = int(env['QUERY_STRING']) start_response('200 Ok', [('Content-type', 'text/html')]) start_at = time.time() uwsgi.green_sleep(sleepvalue) # print("TIMEOUT: ", env['x-wsgiorg.fdevent.timeout']) yield "

    Hello World after %s seconds

    " % str(time.time() - start_at) uwsgi-2.0.29/tests/sleepthreadasync.py000066400000000000000000000005501477626554400200400ustar00rootroot00000000000000import uwsgi import threading import time def foo(): while True: time.sleep(1) print("ciao, sono un thread") t = threading.Thread(target=foo) t.daemon = True t.start() def application(e, s): s('200 OK', [('Content-Type', 'text/html')]) for i in range(0, 3): yield uwsgi.async_sleep(1) yield "iter: %d
    " % i uwsgi-2.0.29/tests/slow.py000066400000000000000000000003531477626554400154670ustar00rootroot00000000000000import time import uwsgi def application(e, s): print("locking") uwsgi.lock() print("locked") time.sleep(3) uwsgi.unlock() print("UN-locked") s('200 OK', [('Content-Type', 'text/html')]) return "slow" uwsgi-2.0.29/tests/spooler_dir.py000066400000000000000000000003741477626554400170270ustar00rootroot00000000000000# uwsgi --master --plugins=python27 --spooler=/var/spool/uwsgi/ --spooler-import spooler_dir.py import uwsgi def spooler_func(env): print(uwsgi.spooler_dir()) return uwsgi.SPOOL_RETRY uwsgi.spooler = spooler_func uwsgi.spool({"foo": "bar"}) uwsgi-2.0.29/tests/spoolme.py000066400000000000000000000006621477626554400161640ustar00rootroot00000000000000import uwsgi import time def slow_task(args): time.sleep(10) return uwsgi.SPOOL_OK uwsgi.spooler = slow_task def application(env, start_response): name = uwsgi.spool({ 'Hello': 'World', 'I am a': 'long running task' }) print("spooled as %s" % name) start_response('200 Ok', [ ('Content-Type', 'text/plain'), ('uWSGI-Status', 'spooled'), ]) return "task spooled" uwsgi-2.0.29/tests/static/000077500000000000000000000000001477626554400154175ustar00rootroot00000000000000uwsgi-2.0.29/tests/static/test.txt000066400000000000000000000000071477626554400171340ustar00rootroot00000000000000cookie uwsgi-2.0.29/tests/static/test2.txt000066400000000000000000000000101477626554400172100ustar00rootroot00000000000000cookie2 uwsgi-2.0.29/tests/staticfile.py000066400000000000000000000005701477626554400166330ustar00rootroot00000000000000import sys content_type = 'image/png' filename = 'logo_uWSGI.png' try: filename = sys.argv[1] except IndexError: pass try: content_type = sys.argv[2] except IndexError: pass def application(environ, start_response): start_response('200 OK', [('Content-Type', content_type)]) fd = open(filename) yield environ['wsgi.file_wrapper'](fd, 32*1024) uwsgi-2.0.29/tests/streamer.psgi000066400000000000000000000005721477626554400166420ustar00rootroot00000000000000sub streamer { my $responder = shift; my $writer = $responder->([ 200, [ 'Content-Type', 'text/html' ]]); my @chunks = ('One', 'Two', 'Three'); foreach(@chunks) { uwsgi::async_sleep(1); # something like $env->{'psgix.suspend'}(); ??? uwsgi::suspend(); $writer->write($_."
    "); } $writer->close; } my $app = sub { my $env = shift; return \&streamer; }; uwsgi-2.0.29/tests/t/000077500000000000000000000000001477626554400143735ustar00rootroot00000000000000uwsgi-2.0.29/tests/t/static.pl000066400000000000000000000035011477626554400162160ustar00rootroot00000000000000use IO::Socket::INET; use Digest::MD5 qw(md5) ; $NUM = 50; my @commands; push @commands, "./uwsgi --http-socket :9191 --disable-logging --static-offload-to-thread 64 --static-map /foobar=./t_foobar.txt --pidfile ./t_foobar.pid &"; push @commands, "./uwsgi --http-socket :9191 --disable-logging -M -p 4 --static-offload-to-thread 64 --static-map /foobar=./t_foobar.txt --pidfile ./t_foobar.pid &"; push @commands, "./uwsgi --http :9191 --disable-logging --static-map /foobar=./t_foobar.txt --static-offload-to-thread 64 --pidfile ./t_foobar.pid &"; print "generating random data for the test...\n"; my $content = generate_random_content(1024*1024); my $first_digest = md5($content); open FOOBAR,'>t_foobar.txt'; print FOOBAR $content; close FOOBAR; foreach my $cmd(@commands) { system $cmd; sleep(1); my @s; print "sending requests to uWSGI...\n"; for(my $i=0;$i<$NUM;$i++) { $s[$i] = IO::Socket::INET->new(PeerAddr => '127.0.0.1', PeerPort => 9191); $s[$i]->send("GET /foobar HTTP/1.0\r\nHost: 127.0.0.1:9191\r\n\r\n"); } my @body; print "receiving responses from uWSGI...\n"; while(1) { $end = 0; for(my $i=0;$i<$NUM;$i++) { $s[$i]->recv(my $buf, 32768); $end++ unless $buf; $body[$i].=$buf; } last if $end >= $NUM; } print "checking uWSGI responses...\n"; foreach my $data (@body) { $data =~ s/^(.|\n|\r)*\r\n\r\n//m; if (md5($data) ne $first_digest) { end_test("md5 does not match"); } } system('kill -INT `cat t_foobar.pid`'); sleep(3); } print "TEST PASSED\n"; sub generate_random_content { my $size = shift; my @chars=('a'..'z','A'..'Z','0'..'9'); my $random_string = ''; foreach (1..$size) { $random_string.=$chars[rand @chars]; } return $random_string; } sub end_test { my $msg = shift; print 'TEST FAILED: '.$msg."\n"; system('kill -INT `cat t_foobar.pid`'); exit; } uwsgi-2.0.29/tests/templates/000077500000000000000000000000001477626554400161265ustar00rootroot00000000000000uwsgi-2.0.29/tests/templates/queue.html000066400000000000000000000023711477626554400201430ustar00rootroot00000000000000 {% with messages = get_flashed_messages() %} {% if messages %}
      {% for message in messages %}
    • {{ message }}
    • {% endfor %}
    {% endif %} {% endwith %}

    next available slot: {{uwsgi.queue_slot()}}

    next available pull slot: {{uwsgi.queue_pull_slot()}}

    {% for item in range(0, uwsgi.queue_size) %} slot {{item}} = {{uwsgi.queue_get(item)}}
    {% endfor %}





    uwsgi-2.0.29/tests/testapp.py000066400000000000000000000116251477626554400161670ustar00rootroot00000000000000import uwsgi from six.moves import reload_module import time import sys import os sys.path.insert(0, '/opt/apps') os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings' #import django.core.handlers.wsgi #uwsgi.load_plugin(0, "plugins/example/example_plugin.so", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa") from threading import Thread class testthread(Thread): def run(self): while 1: time.sleep(2) print("i am a terrible python thread of the uWSGI master process", uwsgi.applications) tthread = testthread() tthread.start() p = "serena" #while 1: #print("MARSHALLED OUT: ",uwsgi.send_uwsgi_message("127.0.0.1", 3033, 33, 17, {'prodotto':p, 'tempo': time.time(), 'pippo':'pluto', 'topolino':'paperino', 'callable':4+1, 'nullo': None, 'embedded': {'a':1} }, 17)) def mako(filename, vars): return uwsgi.send_uwsgi_message("127.0.0.1", 3033, 33, 17, (filename, vars), 17) #print(uwsgi.send_uwsgi_message("127.0.0.1", 3033, 33, 17, ('makotest.txt', {'whattimeisit':time.time(), 'roberta':'serena'}), 17)) def myspooler(env): print(env) for i in range(1, 100): uwsgi.sharedarea_inclong(100) # time.sleep(1) uwsgi.spooler = myspooler #print("SPOOLER: ", uwsgi.send_to_spooler({'TESTKEY':'TESTVALUE', 'APPNAME':'uWSGI'})) def helloworld(): return 'Hello World' def increment(): return "Shared counter is %d\n" % uwsgi.sharedarea_inclong(100) def force_harakiri(): time.sleep(60) def application(env, start_response): print(env) start_response('200 OK', [('Content-Type', 'text/plain')]) yield { '/': helloworld, '/sleep': force_harakiri, '/counter': increment, '/uwsgi/': helloworld }[env['PATH_INFO']]() print(env) def gomako(): from mako.template import Template uwsgi.start_response('200 OK', [('Content-Type', 'text/html')]) yield Template("hello ${data}!").render(data="world") def goxml(): import xml.dom.minidom doc = xml.dom.minidom.Document() foo = doc.createElement("foo") doc.appendChild(foo) uwsgi.start_response('200 OK', [('Content-Type', 'text/xml')]) return doc.toxml() def djangohomepage(): from django.template import Template, Context uwsgi.start_response('200 OK', [('Content-Type', 'text/html')]) t = Template("My name is {{ my_name }}.") c = Context({"my_name": "Serena"}) print(t, c) a = t.render(c) print("ciao", a) yield str(a) def reload(env, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) #uwsgi.sorry_i_need_to_block() #time.sleep(1) #uwsgi.reload() # print(str(uwsgi.masterpid()) + "\n") # print("i am python") #yo() # yield "python" #print 4/0 # yield str(uwsgi.masterpid()) #print(uwsgi.pippo) #print 4/0 # try: # print 4/0 # # print uwsgi.pippo # except Exception: # print "bah" # print("ok") # yield 4/0 yield '

    uWSGI status ('+env['SCRIPT_NAME']+')

    ' yield 'masterpid: ' + str(uwsgi.masterpid()) + '
    ' yield 'started on: ' + time.ctime(uwsgi.started_on) + '
    ' yield 'buffer size: ' + str(uwsgi.buffer_size) + '
    ' yield 'total_requests: ' + str(uwsgi.total_requests()) + '
    ' yield 'workers: ' + str(uwsgi.numproc) + '
    ' yield '' yield '' workers = uwsgi.workers() yield '

    workers

    ' for w in workers: #print(w) #print(w['running_time']) if w is not None: yield '' print(w) yield '
    worker idpidin requestrequestsrunning timeaddress spacerss
    ' + str(w['id']) + '' + str(w['pid']) + '' + str(w['pid']) + '' + str(w['requests']) + '' + str(w['running_time']) + '' + str(w['vsz']) + '' + str(w['rss']) + '
    ' #yield out #print("FATTOfattoFATTO") def remotemako(env, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) clusters = ( ('192.168.173.5', 3431, [0, 3000]), ('192.168.173.5', 3432, [3001, 6000]), ('192.168.173.5', 3433, [6001, 9000]), ('192.168.173.5', 3434, [9001, 12000]), ('192.168.173.5', 3435, [12001, 15000]) ) print(clusters) all_values = uwsgi.send_multi_uwsgi_message(clusters, 33, 17, 40) print(all_values) return mako('makotest.txt', { 'whattimeisit': time.time(), 'roberta': 'serena', 'cluster_values': all_values }) uwsgi.fastfuncs.insert(10, gomako) uwsgi.fastfuncs.insert(11, goxml) uwsgi.fastfuncs.insert(17, djangohomepage) #djangoapp = django.core.handlers.wsgi.WSGIHandler() #applications = { '/':django.core.handlers.wsgi.WSGIHandler() } uwsgi.applications = { '/': reload, '/pippo': reload } print(uwsgi.applications) print(uwsgi.applist) uwsgi-2.0.29/tests/testfilewrapper.py000066400000000000000000000062161477626554400177270ustar00rootroot00000000000000from __future__ import print_function import gc import io import os.path import time import flask import flask.helpers application = flask.Flask(__name__) FILENAME = os.path.join(os.path.dirname(__file__), "static", "test.txt") FILENAME2 = os.path.join(os.path.dirname(__file__), "static", "test2.txt") @application.after_request def _after(response): gc.collect() fds = os.listdir("/proc/self/fd") print("PY: objects:", len(gc.get_objects()), "fds:", len(fds)) return response @application.route("/") def index(): return "HELLO\n" @application.route("/1") def send_file_1(): fp = open(FILENAME, "rb") return flask.send_file(fp, attachment_filename="test.txt") @application.route("/2") def send_file_2(): bio = io.BytesIO(b"cookie\n") return flask.send_file(bio, attachment_filename="test.txt") @application.route("/3") def send_file_3(): """ What happens if we call the wsgi.file_wrapper twice? This should respond with cookie2 """ fp = open(FILENAME, "rb") flask.send_file(fp, attachment_filename="test.txt") fp = open(FILENAME2, "rb") return flask.send_file(fp, attachment_filename="test.txt") @application.route("/4") def send_file_4(): """ Non-filelike object to send_file/wrap_file/wsgi.file_wrapper. AttributeError on the call to wsgi.file_wrapper. """ return flask.send_file(object(), attachment_filename="test.txt") @application.route("/stream1") def stream1(): """ Unrelated to wsgi.file_wrapper, just ensuring the iterator stuff still works. """ def _yield(): start = time.time() for i in range(3): time.sleep(0.1) yield " {:.2f} cookie".format(time.time() - start).encode("utf-8") yield b"\n" return flask.Response(_yield(), mimetype="text/plain") @application.route("/stream2") def stream2(): """ Yielding the result of a wrap_file call with a file object. gunicorn / werkzeug do not support this as it's not required. """ fp = open(FILENAME, "rb") resp = flask.helpers.wrap_file(flask.request.environ, fp) print("PY: resp after return", hex(id(resp))) def _yield(): print("PY: _yield() run", hex(id(resp)), repr(resp)) yield resp return flask.Response(_yield()) @application.route("/stream3") def stream3(): """ Yielding the result of a wrap_file call with a BytesIO object. gunicorn / werkzeug do not support this as it's not required. """ bio = io.BytesIO(b"cookie\n") resp = flask.helpers.wrap_file(flask.request.environ, bio) def _yield(): yield resp return flask.Response(_yield()) @application.route("/stream4") def stream4(): """ werkzeug logs: AssertionError: applications must write bytes gunicorn logs: TypeError: is not a byte uwsgi didn't log, should now.. """ fp = open(FILENAME, "rb") resp = flask.send_file(fp, attachment_filename="test.txt") print("PY: resp after return", hex(id(resp))) def _yield(): print("PY: _yield() run", hex(id(resp)), repr(resp)) yield resp return flask.Response(_yield(), direct_passthrough=True) uwsgi-2.0.29/tests/testgevent.py000066400000000000000000000015731477626554400167000ustar00rootroot00000000000000# uwsgi -s :3031 -M -p 4 --plugin gevent --loop gevent --async 1000 --enable-threads -w tests.testgevent from threading import Thread import gevent import uwsgi import time def microtask(wid): print("i am a gevent task") gevent.sleep(10) print("10 seconds elapsed in worker id %d" % wid) def athread(): while True: time.sleep(1) print("i am the thread 1") def athread2(): while True: time.sleep(1) print("i am the thread 2") t1 = Thread(target=athread) t1.daemon = True t1.start() t2 = Thread(target=athread2) t2.daemon = True t2.start() def application(environ, start_response): gevent.sleep() start_response('200 OK', [('Content-Type', 'text/html')]) yield "sleeping for 3 seconds...
    " gevent.sleep(3) yield "done
    " gevent.spawn(microtask, uwsgi.worker_id()) yield "microtask started
    " uwsgi-2.0.29/tests/testpy3.py000066400000000000000000000005061477626554400161160ustar00rootroot00000000000000import uwsgi def app1(e, sr): print(e) sr('200 Ok', [('Content-Type', 'text/plain')]) return b'i Am a Python 3.x bytestring' def app2(e, sr): print(e) sr('404 Not Found', [('Content-Type', 'text/plain')]) return b'i Am a Python 3.x Not Found page' uwsgi.applications = {b'': app1, b'/test': app2} uwsgi-2.0.29/tests/testrpc.py000066400000000000000000000004701477626554400161670ustar00rootroot00000000000000import uwsgi def hello(): pass def application(env, start_response): try: uwsgi.register_rpc("A"*300, hello) start_response('500 Buffer Overflow', [('Content-Type', 'text/plain')]) except ValueError: start_response('200 OK', [('Content-Type', 'text/plain')]) return () uwsgi-2.0.29/tests/testsignals.py000066400000000000000000000006171477626554400170460ustar00rootroot00000000000000import uwsgi # send a raw signal to register with file_monitor subsystem # uwsgi.signal(10, "/tmp/topolino") uwsgi.signal(10, "/tmp") # uwsgi.signal(10, "/root") # send a raw signal to register with timer subsystem uwsgi.signal(11, "3") uwsgi.signal(11, "4") uwsgi.signal(11, "8") def application(e, s): s('200 Ok', [('Content-Type', 'text/html')]) return "

    Hello World

    " uwsgi-2.0.29/tests/testworkers.py000066400000000000000000000015611477626554400171010ustar00rootroot00000000000000""" Regression test for #2056 - uwsgi.workers() leaking objects. """ import uwsgi import gc def application(env, start_response): gc.collect() start_objs = len(gc.get_objects()) for i in range(200): workers = uwsgi.workers() assert workers, "none/empty uwsgi.workers() - " + repr(workers) for w in workers: assert w["apps"], "none/empty apps in worker dict: " + repr(w) gc.collect() end_objs = len(gc.get_objects()) diff_objs = end_objs - start_objs # Sometimes there is a spurious diff of 4 objects or so. if diff_objs > 10: start_response('500 Leaking', [('Content-Type', 'text/plain')]) yield "Leaking objects...\n".encode("utf-8") else: start_response('200 OK', [('Content-Type', 'text/plain')]) yield "{} {} {}\n".format(start_objs, end_objs, diff_objs).encode("utf-8") uwsgi-2.0.29/tests/threads.py000066400000000000000000000014231477626554400161340ustar00rootroot00000000000000import uwsgi import threading import time import sys from six.moves import reload_module def monitor1(): while 1: time.sleep(1) print("i am the monitor 1") def monitor2(): while 1: time.sleep(2) print("i am the monitor 2") print(sys.modules) def monitor3(): while 1: time.sleep(5) print("5 seconds elapsed") # reload_module(fake) def spawn_my_magic_threads(): print("^^^ spawning magic threads ^^^") threading.Thread(target=monitor1).start() threading.Thread(target=monitor2).start() threading.Thread(target=monitor3).start() uwsgi.post_fork_hook = spawn_my_magic_threads def application(e, s): s('200 Ok', [('Content-Type', 'text/html')]) return "Hello Threaded World !!!" uwsgi-2.0.29/tests/threads_atexit.py000066400000000000000000000017551477626554400175220ustar00rootroot00000000000000# https://github.com/unbit/uwsgi/pull/2615 # atexit should be called when reached max-requests. # # Start this app: # # $ ./uwsgi --http-socket :8000 --master -L --wsgi-file=tests/threads_atexit.py \ # --workers 1 --threads 32 --max-requests 40 --min-worker-lifetime 6 --lazy-apps # # Access to this app with hey[1]: # # # Do http access for 5 minutes with 32 concurrency # $ ./hey -c 32 -z 5m 'http://127.0.0.1:8000/' # # Search how many stamp files: # # $ ls uwsgi_worker*.txt | wc -l # 39 # should be 0 # # [1] https://github.com/rakyll/hey import atexit import os import sys import time pid = os.getpid() stamp_file = f"./uwsgi_worker{pid}.txt" with open(stamp_file, "w") as f: print(time.time(), file=f) @atexit.register def on_finish_worker(): print(f"removing {stamp_file}", file=sys.stderr) os.remove(stamp_file) def application(env, start_response): time.sleep(1) start_response('200 OK', [('Content-Type', 'text/html')]) return [b"Hello World"] uwsgi-2.0.29/tests/threads_heavy.py000066400000000000000000000016761477626554400173420ustar00rootroot00000000000000# https://github.com/unbit/uwsgi/pull/2615 # CPU heavy application in multi threaded uWSGI doesn't shutdown gracefully. # # $ ./uwsgi \ # --wsgi-file=threads_heavy.py --master --http-socket=:8000 \ # --workers=4 --threads=8 --max-requests=20 --min-worker-lifetime=6 -L \ # --worker-reload-mercy=20 2>&1 | tee uwsgi.log # # $ hey -c 16 -z 3m 'http://127.0.0.1:8000/' # # $ grep MERCY uwsgi.log # Tue Mar 19 14:01:59 2024 - worker 1 (pid: 62113) is taking too much time to die...NO MERCY !!! # Tue Mar 19 14:02:23 2024 - worker 2 (pid: 62218) is taking too much time to die...NO MERCY !!! # ... # # This was caused by pthread_cancel() is called from non-main thread. def fibonacci(n): if n <= 1: return n return fibonacci(n - 1) + fibonacci(n - 2) def application(env, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) n = 24 r = fibonacci(n) s = f"F({n}) = {r}" return [s.encode()] uwsgi-2.0.29/tests/travis.sh000077500000000000000000000075641477626554400160130ustar00rootroot00000000000000#!/bin/bash set -u CI_CONFIG="$1" txtund=$(tput sgr 0 1) # underline txtbld=$(tput bold) # bold bldred=${txtbld}$(tput setaf 1) # red bldgre=${txtbld}$(tput setaf 2) # green bldyel=${txtbld}$(tput setaf 3) # yellow bldblu=${txtbld}$(tput setaf 4) # blue txtcya=$(tput setaf 6) # cyan bldwht=${txtbld}$(tput setaf 7) # white txtrst=$(tput sgr0) # reset ERROR=0 SUCCESS=0 die() { date > reload.txt sleep 3 pidof uwsgi && killall uwsgi sleep 1 pidof uwsgi && killall -9 uwsgi echo -e "$@" if [ -e uwsgi.log ]; then echo -e "${bldyel}>>> uwsgi.log:${txtrst}" echo -e "${txtcya}" cat uwsgi.log echo -e "${txtrst}" fi } http_test() { URL=$1 UPID=`pidof uwsgi` if [ "$UPID" != "" ]; then echo -e "${bldgre}>>> Spawned PID $UPID, running tests${txtrst}" sleep 5 curl -fI $URL RET=$? if [ $RET != 0 ]; then die "${bldred}>>> Error during curl run${txtrst}" ERROR=$((ERROR+1)) else SUCCESS=$((SUCCESS+1)) fi die "${bldyel}>>> SUCCESS: Done${txtrst}" else die "${bldred}>>> ERROR: uWSGI did not start${txtrst}" ERROR=$((ERROR+1)) fi } test_python() { date > reload.txt rm -f uwsgi.log echo -e "${bldyel}================== TESTING $1 $2 =====================${txtrst}" echo -e "${bldyel}>>> Spawning uWSGI python app${txtrst}" echo -en "${bldred}" ./uwsgi --master --plugin 0:$1 --http :8080 --exit-on-reload --touch-reload reload.txt --wsgi-file $2 --daemonize uwsgi.log sleep 1 echo -en "${txtrst}" http_test "http://localhost:8080/" echo -e "${bldyel}===================== DONE $1 $2 =====================${txtrst}\n\n" } test_python_deadlocks() { date > reload.txt rm -f uwsgi.log echo -e "${bldyel}================== TESTING DEADLOCKS $1 $2 =====================${txtrst}" echo -e "${bldyel}>>> Starting python app${txtrst}" echo -en "${bldred}" # initialize with tests/deadlocks/sitecustomize.py PYTHONPATH=tests/deadlocks ./uwsgi --plugin 0:$1 --http :8080 --exit-on-reload --touch-reload reload.txt --wsgi-file tests/deadlocks/main.py --ini $2 --daemonize uwsgi.log sleep 1 echo -en "${txtrst}" http_test "http://localhost:8080/" echo -e "${bldyel}===================== DONE $1 $2 =====================${txtrst}\n\n" } test_rack() { date > reload.txt rm -f uwsgi.log # the code assumes that ruby environment is activated by `rvm use` echo -e "${bldyel}================== TESTING $1 $2 =====================${txtrst}" echo -e "${bldyel}>>> Installing sinatra gem using gem${txtrst}" sudo gem install sinatra -v 2.2.2 || die echo -e "${bldyel}>>> Spawning uWSGI rack app${txtrst}" echo -en "${bldred}" ./uwsgi --master --plugin 0:$1 --http :8080 --exit-on-reload --touch-reload reload.txt --rack $2 --daemonize uwsgi.log echo -en "${txtrst}" http_test "http://localhost:8080/hi" echo -e "${bldyel}===================== DONE $1 $2 =====================${txtrst}\n\n" } while read PV ; do for WSGI_FILE in tests/staticfile.py tests/testworkers.py tests/testrpc.py ; do test_python $PV $WSGI_FILE done done < <(cat "$CI_CONFIG" | grep "plugins/python base" | sed s_".*plugins/python base "_""_g) while read PV ; do for INI_FILE in tests/deadlocks/*.ini ; do test_python_deadlocks $PV $INI_FILE done done < <(cat "$CI_CONFIG" | grep "plugins/python base" | sed s_".*plugins/python base "_""_g) while read RV ; do for RACK in examples/config2.ru ; do test_rack $RV $RACK done done < <(cat "$CI_CONFIG" | grep "plugins/rack base" | sed s_".*plugins/rack base "_""_g) echo "${bldgre}>>> $SUCCESS SUCCESSFUL TEST(S)${txtrst}" if [ $ERROR -ge 1 ]; then echo "${bldred}>>> $ERROR FAILED TEST(S)${txtrst}" exit 1 fi exit 0 uwsgi-2.0.29/tests/ugevent.py000066400000000000000000000032061477626554400161600ustar00rootroot00000000000000import gevent import gevent.socket import sys import uwsgi from uwsgidecorators import timer, signal, filemon if 'gettotalrefcount' in sys.__dict__: REFCNT = True else: REFCNT = False @signal(17) def hello(signum): print("hello i am signal %d, i am here because the background job is finished" % signum) if REFCNT: print(sys.gettotalrefcount()) @timer(10) def ten_seconds(signum): print("10 seconds elapsed, signal %d raised" % signum) if REFCNT: print(sys.gettotalrefcount()) @filemon('/tmp') def tmp_modified(signum): print("/tmp has been touched, i am the greenlet %s running on worker %d" % (gevent.getcurrent(), uwsgi.worker_id())) if REFCNT: print(sys.gettotalrefcount()) def bg_task(): for i in range(1, 10): print("background task", i) gevent.sleep(1) # task ended raise a signal !!! uwsgi.signal(17) def long_task(): for i in range(1, 10): print(i) gevent.sleep() def application(e, sr): sr('200 OK', [('Content-Type', 'text/html')]) t = gevent.spawn(long_task) t.join() yield "sleeping for 3 seconds...
    " gevent.sleep(3) yield "done
    " yield "getting some ips...
    " urls = ['www.google.com', 'www.example.com', 'www.python.org', 'projects.unbit.it'] jobs = [gevent.spawn(gevent.socket.gethostbyname, url) for url in urls] gevent.joinall(jobs, timeout=2) for j in jobs: yield "ip = %s
    " % j.value if REFCNT: print(sys.gettotalrefcount()) yield "%d" % sys.gettotalrefcount() # this task will goes on after request end gevent.spawn(bg_task) uwsgi-2.0.29/tests/web3.py000066400000000000000000000003541477626554400153440ustar00rootroot00000000000000class AppClass(object): def __call__(self, environ): status = b'200 OK' headers = [(b'Content-type', b'text/plain')] body = [b'Hello world!\n'] return body, status, headers application = AppClass() uwsgi-2.0.29/tests/websockets.py000066400000000000000000000043311477626554400166540ustar00rootroot00000000000000#!./uwsgi --https :8443,foobar.crt,foobar.key --http-websockets --gevent 100 --module tests.websocket import uwsgi import gevent from gevent.queue import JoinableQueue from gevent.socket import wait_read queue = JoinableQueue() def application(env, sr): ws_scheme = 'ws' if 'HTTPS' in env or env['wsgi.url_scheme'] == 'https': ws_scheme = 'wss' if env['PATH_INFO'] == '/': sr('200 OK', [('Content-Type', 'text/html')]) return """

    WebSocket

    """ % (ws_scheme, env['HTTP_HOST']) elif env['PATH_INFO'] == '/foobar/': uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', '')) print("websockets...") while True: msg = uwsgi.websocket_recv_nb() if msg: queue.put(msg) else: try: wait_read(uwsgi.connection_fd(), 0.1) except gevent.socket.timeout: try: msg = queue.get_nowait() uwsgi.websocket_send(msg) except Exception: pass return "" uwsgi-2.0.29/tests/websockets_chat.pl000066400000000000000000000072641477626554400176460ustar00rootroot00000000000000#!./uwsgi --http-socket :9090 --coroae 100 --psgi tests/websockets_chat.pl use Coro::AnyEvent; use AnyEvent::Redis; # Coro::AnyEvent uWSGI/PSGI websocket app # you can build a Coro::AnyEvent-enabled uWSGI binary with 'make coroae' # note: we need two redis connections, one for publishing and one for subscribing my $app = sub { my ($env) = @_; my $ws_scheme = 'ws'; $ws_scheme = 'wss' if ($env->{'HTTPS'} || $env->{'wsgi.url_scheme'} eq 'https'); if ($env->{'PATH_INFO'} eq '/') { my $host = $env->{'HTTP_HOST'}; my $html = <

    WebSocket

    EOF return [200, ['Content-Type' => 'text/html'], [$html]]; } elsif ($env->{'PATH_INFO'} eq '/favicon.ico') { return [404, [], []]; } elsif ($env->{'PATH_INFO'} eq '/foobar/') { # when 1 something was wrong and we need to close the connection my $error = 0; # when 1 there is something in the websocket my $websocket_event = 0; # when defined there is a redis message available my $redis_message = undef; # do the handshake uwsgi::websocket_handshake($env->{'HTTP_SEC_WEBSOCKET_KEY'}, $env->{'HTTP_ORIGIN'}); print "websockets...\n" ; # this condvar will allow us to wait for events my $w = AnyEvent->condvar; # connect to redis my $redis = AnyEvent::Redis->new( host => '127.0.0.1', port => 6379, encoding => 'utf8', on_error => sub { warn @_; $error = 1; $w->send; }, on_cleanup => sub { warn "Connection closed: @_"; $error = 1; $w->send; }, ); # subscribe to the 'foobar' channel $redis->subscribe('foobar', sub { my ($message, $channel) = @_; $redis_message = $message; # wakeup !!! $w->send; }); # open a second connection to publish messages my $redis_publisher = AnyEvent::Redis->new( host => '127.0.0.1', port => 6379, encoding => 'utf8', on_error => sub { warn @_; $error = 1; $w->send; }, on_cleanup => sub { warn "Connection closed: @_"; $error = 1; $w->send; }, ); # start waiting for read events in the websocket my $ws = AnyEvent->io( fh => uwsgi::connection_fd, poll => 'r', cb => sub { $websocket_event = 1; # wakeup !!! $w->send; } ); # the main loop for(;;) { # here we block until an event is available $w->recv; break if $error; # any websocket message available ? if ($websocket_event) { my $msg = uwsgi::websocket_recv_nb; $redis_publisher->publish('foobar', $msg) if $msg; $websocket_event = 0; } # any redis message available ? if ($redis_message) { uwsgi::websocket_send('['.time().'] '.$redis_message); $redis_message = undef; } $w = AnyEvent->condvar; } } } uwsgi-2.0.29/tests/websockets_chat.py000066400000000000000000000052751477626554400176630ustar00rootroot00000000000000#!./uwsgi --http-socket :9090 --gevent 100 --module tests.websockets_chat --gevent-monkey-patch import uwsgi import time import gevent.select import redis def application(env, sr): ws_scheme = 'ws' if 'HTTPS' in env or env['wsgi.url_scheme'] == 'https': ws_scheme = 'wss' if env['PATH_INFO'] == '/': sr('200 OK', [('Content-Type', 'text/html')]) return """

    WebSocket

    """ % (ws_scheme, env['HTTP_HOST']) elif env['PATH_INFO'] == '/favicon.ico': return "" elif env['PATH_INFO'] == '/foobar/': uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', '')) print("websockets...") r = redis.StrictRedis(host='localhost', port=6379, db=0) channel = r.pubsub() channel.subscribe('foobar') websocket_fd = uwsgi.connection_fd() redis_fd = channel.connection._sock.fileno() while True: # wait max 4 seconds to allow ping to be sent ready = gevent.select.select([websocket_fd, redis_fd], [], [], 4.0) # send ping on timeout if not ready[0]: uwsgi.websocket_recv_nb() for fd in ready[0]: if fd == websocket_fd: msg = uwsgi.websocket_recv_nb() if msg: r.publish('foobar', msg) elif fd == redis_fd: msg = channel.parse_response() # only interested in user messages if msg[0] == 'message': uwsgi.websocket_send("[%s] %s" % (time.time(), msg)) uwsgi-2.0.29/tests/websockets_chat_2.py000066400000000000000000000066071477626554400201040ustar00rootroot00000000000000#!./uwsgi --http-socket :9090 --http-raw-body --gevent 100 --module tests.websockets_chat_2 import uwsgi import time import gevent from gevent.queue import Queue class ClientManager(object): clients = set() @classmethod def add(cls, client): cls.clients.add(client) @classmethod def remove(cls, client): cls.clients.remove(client) @classmethod def count(cls): return len(cls.clients) @classmethod def broadcast(cls, data): data = "{0} {1}".format(time.time(), data) def do_broadcast(): for c in cls.clients: c.send(data) gevent.spawn(do_broadcast) class Client(object): def __init__(self): self.ctx = None self.send_queue = Queue() self.jobs = [] def _recv_job(self): while True: data = uwsgi.websocket_recv(request_context=self.ctx) self.on_data(data) def _send_job(self): while True: data = self.send_queue.get() uwsgi.websocket_send(data, request_context=self.ctx) def _exit(self, *args): for j in self.jobs: j.unlink(self._exit) gevent.killall(self.jobs) ClientManager.remove(self) self.on_exit() def on_data(self, data): print "GOT: {0}".format(data) ClientManager.broadcast(data) def on_exit(self): print "bye bye..." def send(self, data): self.send_queue.put(data) def start(self): uwsgi.websocket_handshake() self.ctx = uwsgi.request_context() ClientManager.add(self) self.jobs.extend([ gevent.spawn(self._recv_job), gevent.spawn(self._send_job), ]) for j in self.jobs: j.link(self._exit) gevent.joinall(self.jobs) def application(env, sr): ws_scheme = 'ws' if 'HTTPS' in env or env['wsgi.url_scheme'] == 'https': ws_scheme = 'wss' if env['PATH_INFO'] == '/': sr('200 OK', [('Content-Type', 'text/html')]) return """

    WebSocket

    """ % (ws_scheme, env['HTTP_HOST']) elif env['PATH_INFO'] == '/favicon.ico': return "" elif env['PATH_INFO'] == '/foobar/': print "websockets..." client = Client() client.start() return "" uwsgi-2.0.29/tests/websockets_chat_async.lua000066400000000000000000000051271477626554400212050ustar00rootroot00000000000000#!./uwsgi --http :9090 --http-modifier1 6 --http-raw-body --async 256 --ugreen --master --lua tests/websockets_chat_async.lua -- Same worker = Same luaState = Same chat room local PAGE_STATIC = [[

    WebSocket

    ]]; local PAGE_STATIC_HEADERS = { ["Content-type"] = "text/html" }; local MSG_FORMAT = "[%s][%s]: %s"; local MSG_DATE_FORMAT = "%H:%M:%S"; local subs = {}; local send_to_subs = function(msg) uwsgi.log(msg); for id, handler in next, subs do if not handler:send(msg) then subs[id] = nil; end end end local say = function(who, msg) if msg:len() > 0 then send_to_subs(string.format(MSG_FORMAT, os.date(MSG_DATE_FORMAT), who or "System", msg)); end end local loop = function(my_name) local wait_fd = uwsgi.connection_fd(); while true do uwsgi.wait_fd_read(wait_fd, 30); -- 2th arg for ping/pong coroutine.yield(); say(my_name, uwsgi.websocket_recv_nb()); end end local gogo_websockets = function(env) uwsgi.websocket_handshake(nil, nil, "chat"); local handler = assert(uwsgi.websocket_handler(), "no handler"); local id = assert(handler:async_id(), "handler is dead"); subs[id] = handler; -- add to subs local my_name = "User" .. id; say(nil, my_name .. " Has been Connected"); -- say hallo pcall(loop, my_name); -- start listen from user subs[id] = nil; -- remove from subs say(nil, my_name .. " Has been Disconnected"); -- say bye end return function(env) if env['PATH_INFO'] == '/' then return "200", PAGE_STATIC_HEADERS, string.format(PAGE_STATIC, env['HTTPS'] and 'wss' or 'ws', env['HTTP_HOST']); end if env['PATH_INFO'] == '/foobar/' then return nil, nil, coroutine.wrap(gogo_websockets), env; end return "404"; end uwsgi-2.0.29/tests/websockets_chat_async.py000066400000000000000000000063241477626554400210540ustar00rootroot00000000000000#!./uwsgi --http-socket :9090 --async 100 ... # same chat example but using uwsgi async api # for pypy + continulets just run: # uwsgi --http-socket :9090 --pypy-home /opt/pypy --pypy-wsgi-file tests/websockets_chat_async.py --pypy-eval "uwsgi_pypy_setup_continulets()" --async 100 import uwsgi import time import redis import sys def application(env, sr): ws_scheme = 'ws' if 'HTTPS' in env or env['wsgi.url_scheme'] == 'https': ws_scheme = 'wss' if env['PATH_INFO'] == '/': sr('200 OK', [('Content-Type', 'text/html')]) output = """

    WebSocket

    """ % (ws_scheme, env['HTTP_HOST']) if sys.version_info[0] > 2: return output.encode('latin1') return output elif env['PATH_INFO'] == '/favicon.ico': return "" elif env['PATH_INFO'] == '/foobar/': uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', '')) print("websockets...") r = redis.StrictRedis(host='localhost', port=6379, db=0) channel = r.pubsub() channel.subscribe('foobar') websocket_fd = uwsgi.connection_fd() redis_fd = channel.connection._sock.fileno() while True: uwsgi.wait_fd_read(websocket_fd, 3) uwsgi.wait_fd_read(redis_fd) uwsgi.suspend() fd = uwsgi.ready_fd() if fd > -1: if fd == websocket_fd: msg = uwsgi.websocket_recv_nb() if msg: r.publish('foobar', msg) elif fd == redis_fd: msg = channel.parse_response() print(msg) # only interested in user messages t = 'message' if sys.version_info[0] > 2: t = b'message' if msg[0] == t: uwsgi.websocket_send("[%s] %s" % (time.time(), msg)) else: # on timeout call websocket_recv_nb again to manage ping/pong msg = uwsgi.websocket_recv_nb() if msg: r.publish('foobar', msg) uwsgi-2.0.29/tests/websockets_chat_asyncio.py000066400000000000000000000104721477626554400214030ustar00rootroot00000000000000#!./uwsgi --http-socket :9090 --asyncio 100 --module tests.websockets_chat_asyncio --greenlet import uwsgi import asyncio import asyncio_redis import time import greenlet class GreenFuture(asyncio.Future): def __init__(self): super().__init__() self.greenlet = greenlet.getcurrent() self.add_done_callback(lambda f: f.greenlet.switch()) def result(self): while True: if self.done(): return super().result() self.greenlet.parent.switch() @asyncio.coroutine def redis_open(f): connection = yield from asyncio_redis.Connection.create(host='localhost', port=6379) f.set_result(connection) f.greenlet.switch() @asyncio.coroutine def redis_subscribe(f): connection = yield from asyncio_redis.Connection.create(host='localhost', port=6379) subscriber = yield from connection.start_subscribe() yield from subscriber.subscribe(['foobar']) f.set_result(subscriber) f.greenlet.switch() def ws_recv_msg(g): g.has_ws_msg = True g.switch() @asyncio.coroutine def redis_wait(subscriber, f): reply = yield from subscriber.next_published() f.set_result(reply.value) f.greenlet.switch() @asyncio.coroutine def redis_publish(connection, msg): yield from connection.publish('foobar', msg.decode('utf-8')) def application(env, sr): ws_scheme = 'ws' if 'HTTPS' in env or env['wsgi.url_scheme'] == 'https': ws_scheme = 'wss' if env['PATH_INFO'] == '/': sr('200 OK', [('Content-Type', 'text/html')]) return ("""

    WebSocket

    """ % (ws_scheme, env['HTTP_HOST'])).encode() elif env['PATH_INFO'] == '/favicon.ico': return b"" elif env['PATH_INFO'] == '/foobar/': uwsgi.websocket_handshake() print("websockets...") # a future for waiting for redis connection f = GreenFuture() asyncio.Task(redis_subscribe(f)) # the result() method will switch greenlets if needed subscriber = f.result() # open another redis connection for publishing messages f0 = GreenFuture() t = asyncio.Task(redis_open(f0)) connection = f0.result() myself = greenlet.getcurrent() myself.has_ws_msg = False # start monitoring websocket events asyncio.get_event_loop().add_reader(uwsgi.connection_fd(), ws_recv_msg, myself) # add a 4 seconds timer to manage ping/pong asyncio.get_event_loop().call_later(4, ws_recv_msg, myself) # add a coroutine for redis messages f = GreenFuture() asyncio.Task(redis_wait(subscriber, f)) # switch again f.greenlet.parent.switch() while True: # any redis message in the queue ? if f.done(): msg = f.result() uwsgi.websocket_send("[%s] %s" % (time.time(), msg)) # restart coroutine f = GreenFuture() asyncio.Task(redis_wait(subscriber, f)) if myself.has_ws_msg: myself.has_ws_msg = False msg = uwsgi.websocket_recv_nb() if msg: asyncio.Task(redis_publish(connection, msg)) # switch again f.greenlet.parent.switch() uwsgi-2.0.29/tests/websockets_echo.lua000066400000000000000000000035131477626554400200040ustar00rootroot00000000000000#!./uwsgi --https :8443,foobar.crt,foobar.key --http-modifier1 6 --http-raw-body --threads 100 --lua tests/websockets_echo.lua function app(env) local function html() coroutine.yield(string.format([[

    WebSocket

    ]], ws_scheme, env['HTTP_HOST'])) end ws_scheme = 'ws' if env['HTTPS'] ~= nil then ws_scheme = 'wss' end if env['PATH_INFO'] == '/' then return 200, { ["Content-type"] = "text/html" }, coroutine.wrap(html) elseif env['PATH_INFO'] == '/foobar/' then uwsgi.websocket_handshake(nil, nil, 'echo') print("websockets...") while 1 do msg = uwsgi.websocket_recv() uwsgi.websocket_send(string.format("[%s] %s", os.time(), msg)) end end end return app uwsgi-2.0.29/tests/websockets_echo.pl000066400000000000000000000034401477626554400176350ustar00rootroot00000000000000#!./uwsgi --plugins http,0:psgi,coroae --https :443,foobar.crt,foobar.key --http-websockets --coroae 40 --psgi tests/websockets_echo.pl my $app = sub { my $env = shift; my $ws_scheme = 'ws'; if (exists($env->{HTTPS}) || $env['psgi.url_scheme'] eq 'https') { $ws_scheme = 'wss'; } if ($env->{PATH_INFO} eq '/') { my $body = <

    WebSocket

    EOF return ['200', ['Content-Type' => 'text/html'], [$body]]; } elsif ($env->{PATH_INFO} eq '/foobar/') { uwsgi::websocket_handshake($env->{HTTP_SEC_WEBSOCKET_KEY}, $env->{HTTP_ORIGIN}); print "websockets...\n"; while(1) { my $msg = uwsgi::websocket_recv; uwsgi::websocket_send('['.time().'] '.$msg); } } } uwsgi-2.0.29/tests/websockets_echo.py000066400000000000000000000033361477626554400176560ustar00rootroot00000000000000#!./uwsgi --https :8443,foobar.crt,foobar.key --http-raw-body --gevent 100 --module tests.websockets_echo import uwsgi import time def application(env, sr): ws_scheme = 'ws' if 'HTTPS' in env or env['wsgi.url_scheme'] == 'https': ws_scheme = 'wss' if env['PATH_INFO'] == '/': sr('200 OK', [('Content-Type', 'text/html')]) return """

    WebSocket

    """ % (ws_scheme, env['HTTP_HOST']) elif env['PATH_INFO'] == '/foobar/': uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', '')) print("websockets...") while True: msg = uwsgi.websocket_recv() uwsgi.websocket_send("[%s] %s" % (time.time(), msg)) uwsgi-2.0.29/tests/websockets_echo.ru000066400000000000000000000035001477626554400176450ustar00rootroot00000000000000#!./uwsgi --plugins http,0:rack,fiber --https :443,foobar.crt,foobar.key --http-websockets --fiber --rack tests/websockets_echo.ru --async 100 class WebsocketEcho def call(env) ws_scheme = 'ws' if env.has_key?('HTTPS') or env['rack.url_scheme'] == 'https' ws_scheme = 'wss' end if env['PATH_INFO'] == '/' body = <

    WebSocket

    EOF return [200, { 'Content-Type' => 'text/html'}, [body]] elsif env['PATH_INFO'] == '/foobar/' UWSGI::websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env['HTTP_ORIGIN']) puts "websockets..." loop do msg = UWSGI::websocket_recv UWSGI::websocket_send("[#{Time.now}] #{msg}") end end end end run WebsocketEcho.new uwsgi-2.0.29/tests/werkzeug_app.py000066400000000000000000000001651477626554400172070ustar00rootroot00000000000000import uwsgi print(uwsgi.opt) print(uwsgi.magic_table) from werkzeug.testapp import test_app as application # NOQA uwsgi-2.0.29/unittest/000077500000000000000000000000001477626554400146455ustar00rootroot00000000000000uwsgi-2.0.29/unittest/Makefile000066400000000000000000000011311477626554400163010ustar00rootroot00000000000000 CFLAGS = $(shell pkg-config --cflags check) CFLAGS += -DUWSGI_PCRE2 LDFLAGS = $(shell pkg-config --libs check) LDFLAGS += -ldl -lz LDFLAGS += $(shell xml2-config --libs) LDFLAGS += $(shell pkg-config --libs openssl) LDFLAGS += $(shell pcre2-config --libs8) LDFLAGS += $(shell pkg-config --libs jansson) UNAME_S := $(shell uname -s) ifeq ($(UNAME_S),Linux) LDFLAGS += -lcap endif objects = check_core check_regexp all: $(objects) $(objects): %: %.c ../libuwsgi.a $(CC) $(CFLAGS) -o $@ $< ../libuwsgi.a $(LDFLAGS) test: all @for file in $(objects); do ./$$file; done clean: rm -f $(objects) uwsgi-2.0.29/unittest/check_core.c000066400000000000000000000045171477626554400171050ustar00rootroot00000000000000#include #include "../uwsgi.h" START_TEST(test_uwsgi_strncmp) { int result; result = uwsgi_strncmp("test", 4, "test", 4); ck_assert(result == 0); result = uwsgi_strncmp("test", 4, "tes", 3); ck_assert(result == 1); result = uwsgi_strncmp("tes", 3, "test", 4); ck_assert(result == 1); result = uwsgi_strncmp("aaa", 3, "bbb", 3); ck_assert_msg(result < 0, "result: %d", result); result = uwsgi_strncmp("bbb", 3, "aaa", 3); ck_assert_msg(result > 0, "result: %d", result); } END_TEST Suite *check_core_strings(void) { Suite *s = suite_create("uwsgi strings"); TCase *tc = tcase_create("strings"); suite_add_tcase(s, tc); tcase_add_test(tc, test_uwsgi_strncmp); return s; } START_TEST(test_uwsgi_opt_set_int) { int result; uwsgi_opt_set_int("", "true", &result); ck_assert(result == 0); uwsgi_opt_set_int("", "false", &result); ck_assert(result == 0); uwsgi_opt_set_int("", "0", &result); ck_assert(result == 0); uwsgi_opt_set_int("", "60", &result); ck_assert(result == 60); // When used with "optional_argument", value will be passed as NULL uwsgi_opt_set_int("", NULL, &result); ck_assert(result == 1); } END_TEST Suite *check_core_opt_parsing(void) { Suite *s = suite_create("uwsgi opt parsing"); TCase *tc = tcase_create("opt_parsing"); suite_add_tcase(s, tc); tcase_add_test(tc, test_uwsgi_opt_set_int); return s; } START_TEST(test_uwsgi_cron_task_needs_execution_handles_weekday_7_as_sunday) { int result; struct tm *t; time_t now; now = time(NULL); t = localtime(&now); t->tm_wday= 0; result = uwsgi_cron_task_needs_execution(t, -1, -1, -1, -1, 0); ck_assert(result == 1); result = uwsgi_cron_task_needs_execution(t, -1, -1, -1, -1, 7); ck_assert(result == 1); result = uwsgi_cron_task_needs_execution(t, -1, -1, -1, -1, 1); ck_assert(result == 0); } END_TEST Suite *check_core_cron(void) { Suite *s = suite_create("uwsgi cron"); TCase *tc = tcase_create("cron"); suite_add_tcase(s, tc); tcase_add_test(tc, test_uwsgi_cron_task_needs_execution_handles_weekday_7_as_sunday); return s; } int main(void) { int nf; SRunner *r = srunner_create(check_core_strings()); srunner_add_suite(r, check_core_opt_parsing()); srunner_add_suite(r, check_core_cron()); srunner_run_all(r, CK_NORMAL); nf = srunner_ntests_failed(r); srunner_free(r); return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } uwsgi-2.0.29/unittest/check_regexp.c000066400000000000000000000040711477626554400174420ustar00rootroot00000000000000#include #include "../uwsgi.h" START_TEST(test_uwsgi_regexp_match) { int result; uwsgi_pcre *pattern_all; uwsgi_pcre *pattern; result = uwsgi_regexp_build(".*", &pattern_all); ck_assert(result == 0); result = uwsgi_regexp_match(pattern_all, "/fooba", 6); ck_assert(result >= 0); result = uwsgi_regexp_build("/foobar/.*", &pattern); ck_assert(result == 0); result = uwsgi_regexp_match(pattern, "/fooba", 6); ck_assert(result < 0); result = uwsgi_regexp_match(pattern, "/foobar/baz", 11); ck_assert(result >= 0); pcre2_code_free(pattern_all); pcre2_code_free(pattern); } END_TEST START_TEST(test_uwsgi_regexp_match_ovec) { int result; uwsgi_pcre *pattern; int *ovec = calloc((2+1)*2, sizeof(int)); char buf[20], sub[20]; result = uwsgi_regexp_build("^/foo/(.*)\\.jpg\\?([0-9]{2})", &pattern); ck_assert(result == 0); result = uwsgi_regexp_ovector(pattern); ck_assert(result == 2); result = uwsgi_regexp_match_ovec(pattern, "/fooba", 6, ovec, 2); ck_assert(result < 0); strcpy(buf, "/foo/bar.jpg?422"); result = uwsgi_regexp_match_ovec(pattern, buf, strlen(buf), ovec, 2); ck_assert(result >= 0); strncpy(sub, buf+ovec[0], ovec[1]-ovec[0]); sub[ovec[1]-ovec[0]] = '\0'; ck_assert_str_eq(sub, "/foo/bar.jpg?42"); strncpy(sub, buf+ovec[2], ovec[3]-ovec[2]); sub[ovec[3]-ovec[2]] = '\0'; ck_assert_str_eq(sub, "bar"); strncpy(sub, buf+ovec[4], ovec[5]-ovec[4]); sub[ovec[5]-ovec[4]] = '\0'; ck_assert_str_eq(sub, "42"); strcpy(sub, uwsgi_regexp_apply_ovec(buf, strlen(buf), "key=$1.$2.jpg", 13, ovec, 2)); ck_assert_str_eq(sub, "key=bar.42.jpg"); pcre2_code_free(pattern); free(ovec); } END_TEST Suite *check_regexp(void) { Suite *s = suite_create("uwsgi regexp"); TCase *tc = tcase_create("regexp"); suite_add_tcase(s, tc); tcase_add_test(tc, test_uwsgi_regexp_match); tcase_add_test(tc, test_uwsgi_regexp_match_ovec); return s; } int main(void) { int nf; SRunner *r = srunner_create(check_regexp()); srunner_run_all(r, CK_NORMAL); nf = srunner_ntests_failed(r); srunner_free(r); return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } uwsgi-2.0.29/uwsgi.gemspec000066400000000000000000000010551477626554400154720ustar00rootroot00000000000000Gem::Specification.new do |s| s.name = 'uwsgi' s.license = 'GPL-2' s.version = `python -c "import uwsgiconfig as uc; print uc.uwsgi_version"`.sub(/-dev-.*/,'') s.date = '2025-04-11' s.summary = "uWSGI" s.description = "The uWSGI server for Ruby/Rack" s.authors = ["Unbit"] s.email = 'info@unbit.it' s.extensions = ['ext/uwsgi/extconf.rb'] s.files = [] s.require_paths = ['.'] s.executables << 'uwsgi' s.homepage = 'http://projects.unbit.it/uwsgi' s.add_runtime_dependency 'rack' end uwsgi-2.0.29/uwsgi.h000066400000000000000000003725131477626554400143100ustar00rootroot00000000000000/* uWSGI */ /* indent -i8 -br -brs -brf -l0 -npsl -nip -npcs -npsl -di1 -il0 */ #ifdef __cplusplus extern "C" { #endif #define UWSGI_PLUGIN_API 1 #define UWSGI_HAS_OFFLOAD_UBUFS 1 #define UMAX16 65536 #define UMAX8 256 #define UMAX64_STR "18446744073709551615" #define MAX64_STR "-9223372036854775808" #define UWSGI_END_OF_OPTIONS { NULL, 0, 0, NULL, NULL, NULL, 0}, #define uwsgi_error(x) uwsgi_log("%s: %s [%s line %d]\n", x, strerror(errno), __FILE__, __LINE__); #define uwsgi_error_realpath(x) uwsgi_log("realpath() of %s failed: %s [%s line %d]\n", x, strerror(errno), __FILE__, __LINE__); #define uwsgi_log_safe(x) if (uwsgi.original_log_fd != 2) dup2(uwsgi.original_log_fd, 2) ; uwsgi_log(x); #define uwsgi_error_safe(x) if (uwsgi.original_log_fd != 2) dup2(uwsgi.original_log_fd, 2) ; uwsgi_log("%s: %s [%s line %d]\n", x, strerror(errno), __FILE__, __LINE__); #define uwsgi_log_initial if (!uwsgi.no_initial_output) uwsgi_log #define uwsgi_log_alarm(x, ...) uwsgi_log("[uwsgi-alarm" x, __VA_ARGS__) #define uwsgi_fatal_error(x) uwsgi_error(x); exit(1); #define uwsgi_error_open(x) uwsgi_log("open(\"%s\"): %s [%s line %d]\n", x, strerror(errno), __FILE__, __LINE__); #define uwsgi_req_error(x) if (wsgi_req->uri_len > 0 && wsgi_req->method_len > 0 && wsgi_req->remote_addr_len > 0) uwsgi_log_verbose("%s: %s [%s line %d] during %.*s %.*s (%.*s)\n", x, strerror(errno), __FILE__, __LINE__,\ wsgi_req->method_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri, wsgi_req->remote_addr_len, wsgi_req->remote_addr); else uwsgi_log_verbose("%s %s [%s line %d] \n",x, strerror(errno), __FILE__, __LINE__); #define uwsgi_debug(x, ...) uwsgi_log("[uWSGI DEBUG] " x, __VA_ARGS__); #define uwsgi_rawlog(x) if (write(2, x, strlen(x)) != strlen(x)) uwsgi_error("write()") #define uwsgi_str(x) uwsgi_concat2(x, (char *)"") #define uwsgi_notify(x) if (uwsgi.notify) uwsgi.notify(x) #define uwsgi_notify_ready() uwsgi.shared->ready = 1 ; if (uwsgi.notify_ready) uwsgi.notify_ready() #define uwsgi_apps uwsgi.workers[uwsgi.mywid].apps #define uwsgi_apps_cnt uwsgi.workers[uwsgi.mywid].apps_cnt #define wsgi_req_time ((wsgi_req->end_of_request-wsgi_req->start_of_request)/1000) #define thunder_lock if (!uwsgi.is_et) {\ if (uwsgi.use_thunder_lock) {\ uwsgi_lock(uwsgi.the_thunder_lock);\ }\ else if (uwsgi.threads > 1) {\ pthread_mutex_lock(&uwsgi.thunder_mutex);\ }\ } #define thunder_unlock if (!uwsgi.is_et) {\ if (uwsgi.use_thunder_lock) {\ uwsgi_unlock(uwsgi.the_thunder_lock);\ }\ else if (uwsgi.threads > 1) {\ pthread_mutex_unlock(&uwsgi.thunder_mutex);\ }\ } #define uwsgi_n64(x) strtoul(x, NULL, 10) #define ushared uwsgi.shared #define UWSGI_OPT_IMMEDIATE (1 << 0) #define UWSGI_OPT_MASTER (1 << 1) #define UWSGI_OPT_LOG_MASTER (1 << 2) #define UWSGI_OPT_THREADS (1 << 3) #define UWSGI_OPT_CHEAPER (1 << 4) #define UWSGI_OPT_VHOST (1 << 5) #define UWSGI_OPT_MEMORY (1 << 6) #define UWSGI_OPT_PROCNAME (1 << 7) #define UWSGI_OPT_LAZY (1 << 8) #define UWSGI_OPT_NO_INITIAL (1 << 9) #define UWSGI_OPT_NO_SERVER (1 << 10) #define UWSGI_OPT_POST_BUFFERING (1 << 11) #define UWSGI_OPT_CLUSTER (1 << 12) #define UWSGI_OPT_MIME (1 << 13) #define UWSGI_OPT_REQ_LOG_MASTER (1 << 14) #define UWSGI_OPT_METRICS (1 << 15) #define MAX_GENERIC_PLUGINS 128 #define MAX_GATEWAYS 64 #define MAX_TIMERS 64 #define MAX_CRONS 64 #define UWSGI_VIA_SENDFILE 1 #define UWSGI_VIA_ROUTE 2 #define UWSGI_VIA_OFFLOAD 3 #ifndef UWSGI_LOAD_EMBEDDED_PLUGINS #define UWSGI_LOAD_EMBEDDED_PLUGINS #endif #ifndef UWSGI_DECLARE_EMBEDDED_PLUGINS #define UWSGI_DECLARE_EMBEDDED_PLUGINS #endif #ifdef UWSGI_EMBED_CONFIG extern char UWSGI_EMBED_CONFIG; extern char UWSGI_EMBED_CONFIG_END; #endif #define UDEP(pname) extern struct uwsgi_plugin pname##_plugin; #define ULEP(pname)\ if (pname##_plugin.request) {\ uwsgi.p[pname##_plugin.modifier1] = &pname##_plugin;\ if (uwsgi.p[pname##_plugin.modifier1]->on_load)\ uwsgi.p[pname##_plugin.modifier1]->on_load();\ }\ else {\ if (uwsgi.gp_cnt >= MAX_GENERIC_PLUGINS) {\ uwsgi_log("you have embedded too much generic plugins !!!\n");\ exit(1);\ }\ uwsgi.gp[uwsgi.gp_cnt] = &pname##_plugin;\ if (uwsgi.gp[uwsgi.gp_cnt]->on_load)\ uwsgi.gp[uwsgi.gp_cnt]->on_load();\ uwsgi.gp_cnt++;\ }\ #define fill_plugin_table(x, up)\ if (up->request) {\ uwsgi.p[x] = up;\ }\ else {\ if (uwsgi.gp_cnt >= MAX_GENERIC_PLUGINS) {\ uwsgi_log("you have embedded too much generic plugins !!!\n");\ exit(1);\ }\ uwsgi.gp[uwsgi.gp_cnt] = up;\ uwsgi.gp_cnt++;\ }\ #define uwsgi_foreach(x, y) for(x=y;x;x = x->next) #define uwsgi_foreach_token(x, y, z, w) for(z=strtok_r(x, y, &w);z;z = strtok_r(NULL, y, &w)) #ifndef __need_IOV_MAX #define __need_IOV_MAX #endif #ifdef __sun__ #ifndef _XPG4_2 #define _XPG4_2 #endif #ifndef __EXTENSIONS__ #define __EXTENSIONS__ #endif #endif #if defined(__linux__) || defined(__GNUC__) #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifndef __USE_GNU #define __USE_GNU #endif #endif #include #include #include #include #include #include #include #include #ifdef __linux__ #ifndef MSG_FASTOPEN #define MSG_FASTOPEN 0x20000000 #endif #endif #include #include #ifdef UWSGI_UUID #include #endif #include #include #include #ifdef __linux__ #ifndef TCP_FASTOPEN #define TCP_FASTOPEN 23 #endif #endif #include #if defined(__GNU_kFreeBSD__) #include #endif #if defined(__FreeBSD__) || defined(__GNU_kFreeBSD__) #include #include #include #include #ifdef UWSGI_HAS_FREEBSD_LIBJAIL #include #endif #endif #include #include #include #include #ifndef __USE_ISOC99 #define __USE_ISOC99 #endif #include #include #include #ifdef UWSGI_HAS_IFADDRS #include #endif #include #include #include #ifdef __linux__ #include #include #include #endif #if defined(__linux) || defined(__FreeBSD__) || defined(__GNU_kFreeBSD__) #include #endif #ifdef __linux__ extern int pivot_root(const char *new_root, const char *put_old); #endif #include #include #ifndef UWSGI_PLUGIN_BASE #define UWSGI_PLUGIN_BASE "" #endif #include #include #include #include #include #ifndef WAIT_ANY #define WAIT_ANY (-1) #endif #ifdef __APPLE__ #ifndef MAC_OS_X_VERSION_MIN_REQUIRED #define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_4 #endif #include #endif #include #include #include #include #include #include #include #include #ifdef __APPLE__ #include #include #include #endif #ifdef _POSIX_C_SOURCE #undef _POSIX_C_SOURCE #endif #if defined(__sun__) #define WAIT_ANY (-1) #include #define PRIO_MAX 20 #endif #if defined(__HAIKU__) || defined(__CYGWIN__) #ifndef WAIT_ANY #define WAIT_ANY (-1) #endif #define PRIO_MAX 20 #endif #include #ifdef __linux__ #include #include #elif defined(__GNU_kFreeBSD__) #include #include #elif defined(__sun__) #include #include #elif defined(__HAIKU__) #elif defined(__CYGWIN__) #elif defined(__HURD__) #else #include #endif #ifdef UWSGI_CAP #include #endif #ifdef __HAIKU__ #include #endif #undef _XOPEN_SOURCE #ifdef __sun__ #undef __EXTENSIONS__ #endif #ifdef _GNU_SOURCE #undef _GNU_SOURCE #endif #define UWSGI_CACHE_FLAG_UNGETTABLE 0x01 #define UWSGI_CACHE_FLAG_UPDATE 1 << 1 #define UWSGI_CACHE_FLAG_LOCAL 1 << 2 #define UWSGI_CACHE_FLAG_ABSEXPIRE 1 << 3 #define UWSGI_CACHE_FLAG_MATH 1 << 4 #define UWSGI_CACHE_FLAG_INC 1 << 5 #define UWSGI_CACHE_FLAG_DEC 1 << 6 #define UWSGI_CACHE_FLAG_MUL 1 << 7 #define UWSGI_CACHE_FLAG_DIV 1 << 8 #define UWSGI_CACHE_FLAG_FIXEXPIRE 1 << 9 #ifdef UWSGI_SSL #include #include #include #if OPENSSL_VERSION_NUMBER < 0x10100000L #define UWSGI_SSL_SESSION_CACHE #endif #endif #include #ifdef __CYGWIN__ #define __WINCRYPT_H__ #include #ifdef UWSGI_UUID #undef uuid_t #endif #undef CMSG_DATA #define CMSG_DATA(cmsg) \ ((unsigned char *) ((struct cmsghdr *)(cmsg) + 1)) #endif struct uwsgi_buffer { char *buf; size_t pos; size_t len; size_t limit; #ifdef UWSGI_DEBUG_BUFFER int freed; #endif }; struct uwsgi_string_list { char *value; size_t len; uint64_t custom; uint64_t custom2; void *custom_ptr; struct uwsgi_string_list *next; }; struct uwsgi_custom_option { char *name; char *value; int has_args; struct uwsgi_custom_option *next; }; struct uwsgi_lock_item { char *id; void *lock_ptr; int rw; pid_t pid; int can_deadlock; struct uwsgi_lock_item *next; }; struct uwsgi_lock_ops { struct uwsgi_lock_item *(*lock_init) (char *); pid_t(*lock_check) (struct uwsgi_lock_item *); void (*lock) (struct uwsgi_lock_item *); void (*unlock) (struct uwsgi_lock_item *); struct uwsgi_lock_item *(*rwlock_init) (char *); pid_t(*rwlock_check) (struct uwsgi_lock_item *); void (*rlock) (struct uwsgi_lock_item *); void (*wlock) (struct uwsgi_lock_item *); void (*rwunlock) (struct uwsgi_lock_item *); }; #define uwsgi_lock_init(x) uwsgi.lock_ops.lock_init(x) #define uwsgi_lock_check(x) uwsgi.lock_ops.lock_check(x) #define uwsgi_lock(x) uwsgi.lock_ops.lock(x) #define uwsgi_unlock(x) uwsgi.lock_ops.unlock(x) #define uwsgi_rwlock_init(x) uwsgi.lock_ops.rwlock_init(x) #define uwsgi_rwlock_check(x) uwsgi.lock_ops.rwlock_check(x) #define uwsgi_rlock(x) uwsgi.lock_ops.rlock(x) #define uwsgi_wlock(x) uwsgi.lock_ops.wlock(x) #define uwsgi_rwunlock(x) uwsgi.lock_ops.rwunlock(x) #define uwsgi_wait_read_req(x) uwsgi.wait_read_hook(x->fd, uwsgi.socket_timeout) ; x->switches++ #define uwsgi_wait_write_req(x) uwsgi.wait_write_hook(x->fd, uwsgi.socket_timeout) ; x->switches++ #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) #ifdef UWSGI_PCRE2 #define PCRE2_CODE_UNIT_WIDTH 8 #include #define PCRE_OVECTOR_BYTESIZE(n) (n+1)*2 typedef pcre2_code uwsgi_pcre; #else #include #define PCRE_OVECTOR_BYTESIZE(n) (n+1)*3 typedef struct { pcre *p; pcre_extra *extra; } uwsgi_pcre; #endif #endif struct uwsgi_dyn_dict { char *key; int keylen; char *value; int vallen; uint64_t hits; int status; struct uwsgi_dyn_dict *prev; struct uwsgi_dyn_dict *next; #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) uwsgi_pcre *pattern; #endif }; struct uwsgi_hook { char *name; int (*func)(char *); struct uwsgi_hook *next; }; #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) struct uwsgi_regexp_list { uwsgi_pcre *pattern; uint64_t custom; char *custom_str; void *custom_ptr; struct uwsgi_regexp_list *next; }; #endif struct uwsgi_rbtree { struct uwsgi_rb_timer *root; struct uwsgi_rb_timer *sentinel; }; struct uwsgi_rb_timer { uint8_t color; struct uwsgi_rb_timer *parent; struct uwsgi_rb_timer *left; struct uwsgi_rb_timer *right; uint64_t value; void *data; }; struct uwsgi_rbtree *uwsgi_init_rb_timer(void); struct uwsgi_rb_timer *uwsgi_min_rb_timer(struct uwsgi_rbtree *, struct uwsgi_rb_timer *); struct uwsgi_rb_timer *uwsgi_add_rb_timer(struct uwsgi_rbtree *, uint64_t, void *); void uwsgi_del_rb_timer(struct uwsgi_rbtree *, struct uwsgi_rb_timer *); union uwsgi_sockaddr { struct sockaddr sa; struct sockaddr_in sa_in; struct sockaddr_un sa_un; #ifdef AF_INET6 struct sockaddr_in6 sa_in6; #endif }; union uwsgi_sockaddr_ptr { struct sockaddr *sa; struct sockaddr_in *sa_in; struct sockaddr_un *sa_un; #ifdef AF_INET6 struct sockaddr_in6 *sa_in6; #endif }; // Gateways are processes (managed by the master) that extends the // server core features // -- Gateways can prefork or spawn threads -- struct uwsgi_gateway { char *name; char *fullname; void (*loop) (int, void *); pid_t pid; int num; int use_signals; int internal_subscription_pipe[2]; uint64_t respawns; uid_t uid; gid_t gid; void *data; }; struct uwsgi_gateway_socket { char *name; size_t name_len; int fd; char *zerg; char *port; int port_len; int no_defer; void *data; int subscription; int shared; char *owner; struct uwsgi_gateway *gateway; struct uwsgi_gateway_socket *next; // could be useful for ssl void *ctx; // could be useful for plugins int mode; }; // Daemons are external processes maintained by the master struct uwsgi_daemon { char *command; pid_t pid; uint64_t respawns; time_t born; time_t last_spawn; int status; int registered; int has_daemonized; char *pidfile; int daemonize; // this is incremented every time a pidfile is not found uint64_t pidfile_checks; // frequency of pidfile checks (default 10 secs) int freq; int control; struct uwsgi_daemon *next; int stop_signal; int reload_signal; uid_t uid; uid_t gid; int honour_stdin; struct uwsgi_string_list *touch; #ifdef UWSGI_SSL char *legion; #endif int ns_pid; int throttle; char *chdir; int max_throttle; int notifypid; }; struct uwsgi_logger { char *name; char *id; ssize_t(*func) (struct uwsgi_logger *, char *, size_t); int configured; int fd; void *data; union uwsgi_sockaddr addr; socklen_t addr_len; int count; struct msghdr msg; char *buf; // used by choosen logger char *arg; struct uwsgi_logger *next; }; #ifdef UWSGI_SSL struct uwsgi_legion_node { char *name; uint16_t name_len; uint64_t valor; char uuid[37]; char *scroll; uint16_t scroll_len; uint64_t checksum; uint64_t lord_valor; char lord_uuid[36]; time_t last_seen; struct uwsgi_legion_node *prev; struct uwsgi_legion_node *next; }; struct uwsgi_legion { char *legion; uint16_t legion_len; uint64_t valor; char *addr; char *name; uint16_t name_len; pid_t pid; char uuid[37]; int socket; int quorum; int changed; // if set the next packet will be a death-announce int dead; // set to 1 first time when quorum is reached int joined; uint64_t checksum; char *scroll; uint16_t scroll_len; char *lord_scroll; uint16_t lord_scroll_len; uint16_t lord_scroll_size; char lord_uuid[36]; uint64_t lord_valor; time_t i_am_the_lord; time_t unix_check; time_t last_warning; struct uwsgi_lock_item *lock; EVP_CIPHER_CTX *encrypt_ctx; EVP_CIPHER_CTX *decrypt_ctx; char *scrolls; uint64_t scrolls_len; uint64_t scrolls_max_size; // found nodes dynamic lists struct uwsgi_legion_node *nodes_head; struct uwsgi_legion_node *nodes_tail; // static list of nodes to send announces to struct uwsgi_string_list *nodes; struct uwsgi_string_list *lord_hooks; struct uwsgi_string_list *unlord_hooks; struct uwsgi_string_list *setup_hooks; struct uwsgi_string_list *death_hooks; struct uwsgi_string_list *join_hooks; struct uwsgi_string_list *node_joined_hooks; struct uwsgi_string_list *node_left_hooks; time_t suspended_til; struct uwsgi_legion *next; }; struct uwsgi_legion_action { char *name; int (*func) (struct uwsgi_legion *, char *); char *log_msg; struct uwsgi_legion_action *next; }; #endif struct uwsgi_queue_header { uint64_t pos; uint64_t pull_pos; }; struct uwsgi_queue_item { uint64_t size; time_t ts; }; struct uwsgi_hash_algo { char *name; uint32_t(*func) (char *, uint64_t); struct uwsgi_hash_algo *next; }; struct uwsgi_hash_algo *uwsgi_hash_algo_get(char *); void uwsgi_hash_algo_register(char *, uint32_t(*)(char *, uint64_t)); void uwsgi_hash_algo_register_all(void); struct uwsgi_sharedarea { int id; int pages; int fd; struct uwsgi_lock_item *lock; char *area; uint64_t max_pos; uint64_t updates; uint64_t hits; uint8_t honour_used; uint64_t used; void *obj; }; // maintain alignment here !!! struct uwsgi_cache_item { // item specific flags uint64_t flags; // size of the key uint64_t keysize; // hash of the key uint64_t hash; // size of the value (64bit) uint64_t valsize; // block position (in non-bitmap mode maps to the key index) uint64_t first_block; // 64bit expiration (0 for immortal) uint64_t expires; // 64bit hits uint64_t hits; // previous same-hash item uint64_t prev; // next same-hash item uint64_t next; // previous lru item uint64_t lru_prev; // next lru item uint64_t lru_next; // key characters follows... char key[]; } __attribute__ ((__packed__)); struct uwsgi_cache { char *name; uint16_t name_len; uint64_t keysize; uint64_t blocks; uint64_t blocksize; struct uwsgi_hash_algo *hash; uint64_t *hashtable; uint32_t hashsize; uint64_t first_available_block; uint64_t *unused_blocks_stack; uint64_t unused_blocks_stack_ptr; uint8_t use_blocks_bitmap; uint8_t *blocks_bitmap; uint64_t blocks_bitmap_pos; uint64_t blocks_bitmap_size; uint64_t max_items; uint64_t max_item_size; uint64_t n_items; struct uwsgi_cache_item *items; uint8_t use_last_modified; time_t last_modified_at; void *data; uint8_t no_expire; uint64_t full; uint64_t hits; uint64_t miss; char *store; uint64_t filesize; uint64_t store_sync; int64_t math_initial; struct uwsgi_string_list *nodes; int udp_node_socket; struct uwsgi_string_list *sync_nodes; struct uwsgi_string_list *udp_servers; struct uwsgi_lock_item *lock; struct uwsgi_cache *next; int ignore_full; uint64_t next_scan; int purge_lru; uint64_t lru_head; uint64_t lru_tail; int store_delete; int lazy_expire; uint64_t sweep_on_full; int clear_on_full; }; struct uwsgi_option { char *name; int type; int shortcut; char *help; void (*func) (char *, char *, void *); void *data; uint64_t flags; }; struct uwsgi_opt { char *key; char *value; int configured; }; #define UWSGI_OK 0 #define UWSGI_AGAIN 1 #define UWSGI_ACCEPTING 2 #define UWSGI_PAUSED 3 #ifdef __linux__ #include #if defined(__BYTE_ORDER__) #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #define __BIG_ENDIAN__ 1 #endif #endif #elif defined(__sun__) #include #ifdef _BIG_ENDIAN #define __BIG_ENDIAN__ 1 #endif #elif defined(__APPLE__) #include #elif defined(__HAIKU__) #elif defined(__HURD__) #define PATH_MAX 8192 #define RTLD_DEFAULT ((void *) 0) #else #include #endif #define UWSGI_SPOOLER_EXTERNAL 1 #define UWSGI_MODIFIER_ADMIN_REQUEST 10 #define UWSGI_MODIFIER_SPOOL_REQUEST 17 #define UWSGI_MODIFIER_EVAL 22 #define UWSGI_MODIFIER_FASTFUNC 26 #define UWSGI_MODIFIER_MANAGE_PATH_INFO 30 #define UWSGI_MODIFIER_MESSAGE 31 #define UWSGI_MODIFIER_MESSAGE_ARRAY 32 #define UWSGI_MODIFIER_MESSAGE_MARSHAL 33 #define UWSGI_MODIFIER_MULTICAST_ANNOUNCE 73 #define UWSGI_MODIFIER_MULTICAST 74 #define UWSGI_MODIFIER_PING 100 #define UWSGI_MODIFIER_RESPONSE 255 #define NL_SIZE 2 #define H_SEP_SIZE 2 #define UWSGI_RELOAD_CODE 17 #define UWSGI_END_CODE 30 #define UWSGI_EXILE_CODE 26 #define UWSGI_FAILED_APP_CODE 22 #define UWSGI_DE_HIJACKED_CODE 173 #define UWSGI_EXCEPTION_CODE 5 #define UWSGI_QUIET_CODE 29 #define UWSGI_BRUTAL_RELOAD_CODE 31 #define UWSGI_GO_CHEAP_CODE 15 #define MAX_VARS 64 struct uwsgi_loop { char *name; void (*loop) (void); struct uwsgi_loop *next; }; struct wsgi_request; struct uwsgi_socket { int fd; char *name; int name_len; int family; int bound; int arg; void *ctx; uint64_t queue; uint64_t max_queue; int no_defer; int auto_port; // true if connection must be initialized for each core int per_core; // this is the protocol internal name char *proto_name; // call that when a request is accepted int (*proto_accept) (struct wsgi_request *, int); // call that to parse the request (without the body) int (*proto) (struct wsgi_request *); // call that to write reponse int (*proto_write) (struct wsgi_request *, char *, size_t); // call that to write headers (if a special case is needed for them) int (*proto_write_headers) (struct wsgi_request *, char *, size_t); // call that when sendfile() is invoked int (*proto_sendfile) (struct wsgi_request *, int, size_t, size_t); // call that to read the body of a request (could map to a simple read()) ssize_t(*proto_read_body) (struct wsgi_request *, char *, size_t); // hook to call when a new series of response headers is created struct uwsgi_buffer *(*proto_prepare_headers) (struct wsgi_request *, char *, uint16_t); // hook to call when a header must be added struct uwsgi_buffer *(*proto_add_header) (struct wsgi_request *, char *, uint16_t, char *, uint16_t); // last function to call before sending headers to the client int (*proto_fix_headers) (struct wsgi_request *); // hook to call when a request is closed void (*proto_close) (struct wsgi_request *); // special hook to call (if needed) in multithread mode void (*proto_thread_fixup) (struct uwsgi_socket *, int); // optimization for vectors int (*proto_writev) (struct wsgi_request *, struct iovec *, size_t *); int edge_trigger; int *retry; int can_offload; // this is a special map for having socket->thread mapping int *fd_threads; // generally used by zeromq handlers char uuid[37]; void *pub; void *pull; pthread_key_t key; pthread_mutex_t lock; char *receiver; int disabled; int recv_flag; struct uwsgi_socket *next; int lazy; int shared; int from_shared; // used for avoiding vacuum mess ino_t inode; #ifdef UWSGI_SSL SSL_CTX *ssl_ctx; #endif }; struct uwsgi_protocol { char *name; void (*func)(struct uwsgi_socket *); struct uwsgi_protocol *next; }; struct uwsgi_server; struct uwsgi_instance; struct uwsgi_plugin { const char *name; const char *alias; uint8_t modifier1; void *data; void (*on_load) (void); int (*init) (void); void (*post_init) (void); void (*post_fork) (void); struct uwsgi_option *options; void (*enable_threads) (void); void (*init_thread) (int); int (*request) (struct wsgi_request *); void (*after_request) (struct wsgi_request *); void (*preinit_apps) (void); void (*init_apps) (void); void (*postinit_apps) (void); void (*fixup) (void); void (*master_fixup) (int); void (*master_cycle) (void); int (*mount_app) (char *, char *); int (*manage_udp) (char *, int, char *, int); void (*suspend) (struct wsgi_request *); void (*resume) (struct wsgi_request *); void (*harakiri) (int); void (*hijack_worker) (void); void (*spooler_init) (void); void (*atexit) (void); int (*magic) (char *, char *); void *(*encode_string) (char *); char *(*decode_string) (void *); int (*signal_handler) (uint8_t, void *); char *(*code_string) (char *, char *, char *, char *, uint16_t); int (*spooler) (char *, char *, uint16_t, char *, size_t); uint64_t(*rpc) (void *, uint8_t, char **, uint16_t *, char **); void (*jail) (int (*)(void *), char **); void (*post_jail) (void); void (*before_privileges_drop) (void); int (*mule) (char *); int (*mule_msg) (char *, size_t); void (*master_cleanup) (void); struct uwsgi_buffer* (*backtrace)(struct wsgi_request *); struct uwsgi_buffer* (*exception_class)(struct wsgi_request *); struct uwsgi_buffer* (*exception_msg)(struct wsgi_request *); struct uwsgi_buffer* (*exception_repr)(struct wsgi_request *); void (*exception_log)(struct wsgi_request *); void (*vassal)(struct uwsgi_instance *); void (*vassal_before_exec)(struct uwsgi_instance *); int (*worker)(void); void (*early_post_jail) (void); void (*pre_uwsgi_fork) (void); void (*post_uwsgi_fork) (int); }; #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) int uwsgi_regexp_build(char *, uwsgi_pcre **); int uwsgi_regexp_match(uwsgi_pcre *, const char *, int); int uwsgi_regexp_match_ovec(uwsgi_pcre *, const char *, int, int *, int); int uwsgi_regexp_ovector(const uwsgi_pcre *); char *uwsgi_regexp_apply_ovec(char *, int, char *, int, int *, int); int uwsgi_regexp_match_pattern(char *pattern, char *str); #endif struct uwsgi_app { uint8_t modifier1; char mountpoint[0xff]; uint8_t mountpoint_len; void *interpreter; void *callable; void **args; void **environ; void *sendfile; void *input; void *error; void *stream; // custom values you can use for internal purpose void *responder0; void *responder1; void *responder2; void *eventfd_read; void *eventfd_write; void *(*request_subhandler) (struct wsgi_request *, struct uwsgi_app *); int (*response_subhandler) (struct wsgi_request *); int argc; uint64_t requests; uint64_t exceptions; char chdir[0xff]; char touch_reload[0xff]; time_t touch_reload_mtime; void *gateway_version; void *uwsgi_version; void *uwsgi_node; time_t started_at; time_t startup_time; uint64_t avg_response_time; }; struct uwsgi_spooler { char dir[PATH_MAX]; pid_t pid; uint64_t respawned; uint64_t tasks; struct uwsgi_lock_item *lock; time_t harakiri; time_t user_harakiri; int mode; int running; int signal_pipe[2]; struct uwsgi_spooler *next; time_t cursed_at; time_t no_mercy_at; }; #ifdef UWSGI_ROUTING // go to the next route #define UWSGI_ROUTE_NEXT 0 // continue to the request handler #define UWSGI_ROUTE_CONTINUE 1 // close the request #define UWSGI_ROUTE_BREAK 2 struct uwsgi_route { uwsgi_pcre *pattern; char *orig_route; // one for each core int *ovn; int **ovector; struct uwsgi_buffer **condition_ub; char *subject_str; size_t subject_str_len; size_t subject; size_t subject_len; int (*if_func)(struct wsgi_request *, struct uwsgi_route *); int if_negate; int if_status; int (*func) (struct wsgi_request *, struct uwsgi_route *); void *data; size_t data_len; void *data2; size_t data2_len; void *data3; size_t data3_len; void *data4; size_t data4_len; // 64bit value for custom usage uint64_t custom; uint64_t pos; char *label; size_t label_len; char *regexp; char *action; // this is used by virtual route to free resources void (*free)(struct uwsgi_route *); struct uwsgi_route *next; }; struct uwsgi_route_condition { char *name; int (*func)(struct wsgi_request *, struct uwsgi_route *); struct uwsgi_route_condition *next; }; struct uwsgi_route_var { char *name; uint16_t name_len; char *(*func)(struct wsgi_request *, char *, uint16_t, uint16_t *); int need_free; struct uwsgi_route_var *next; }; struct uwsgi_router { char *name; int (*func) (struct uwsgi_route *, char *); struct uwsgi_router *next; }; #endif struct uwsgi_alarm; struct uwsgi_alarm_instance { char *name; char *arg; void *data_ptr; uint8_t data8; uint16_t data16; uint32_t data32; uint64_t data64; time_t last_run; char *last_msg; size_t last_msg_size; struct uwsgi_alarm *alarm; struct uwsgi_alarm_instance *next; }; struct uwsgi_alarm { char *name; void (*init) (struct uwsgi_alarm_instance *); void (*func) (struct uwsgi_alarm_instance *, char *, size_t); struct uwsgi_alarm *next; }; struct uwsgi_alarm_fd { int fd; size_t buf_len; void *buf; char *msg; size_t msg_len; struct uwsgi_alarm_instance *alarm; struct uwsgi_alarm_fd *next; }; struct uwsgi_alarm_fd *uwsgi_add_alarm_fd(int, char *, size_t, char *, size_t); #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) struct uwsgi_alarm_ll { struct uwsgi_alarm_instance *alarm; struct uwsgi_alarm_ll *next; }; struct uwsgi_alarm_log { uwsgi_pcre *pattern; int negate; struct uwsgi_alarm_ll *alarms; struct uwsgi_alarm_log *next; }; #endif struct __attribute__ ((packed)) uwsgi_header { uint8_t modifier1; uint16_t pktsize; uint8_t modifier2; }; struct uwsgi_async_fd { int fd; int event; struct uwsgi_async_fd *prev; struct uwsgi_async_fd *next; }; struct uwsgi_logvar { char key[256]; uint8_t keylen; char val[256]; uint8_t vallen; struct uwsgi_logvar *next; }; struct uwsgi_log_encoder { char *name; char *(*func)(struct uwsgi_log_encoder *, char *, size_t, size_t *); int configured; char *use_for; char *args; void *data; struct uwsgi_log_encoder *next; }; struct uwsgi_transformation { int (*func)(struct wsgi_request *, struct uwsgi_transformation *); struct uwsgi_buffer *chunk; uint8_t can_stream; uint8_t is_final; uint8_t flushed; void *data; uint64_t round; int fd; struct uwsgi_buffer *ub; uint64_t len; uint64_t custom64; struct uwsgi_transformation *next; }; enum uwsgi_range { UWSGI_RANGE_NOT_PARSED, UWSGI_RANGE_PARSED, UWSGI_RANGE_VALID, UWSGI_RANGE_INVALID, }; struct wsgi_request { int fd; struct uwsgi_header *uh; int app_id; int dynamic; int parsed; char *appid; uint16_t appid_len; // This structure should not be used any more // in favor of the union client_addr at the end struct sockaddr_un c_addr; int c_len; //iovec struct iovec *hvec; uint64_t start_of_request; uint64_t start_of_request_in_sec; uint64_t end_of_request; char *uri; uint16_t uri_len; char *remote_addr; uint16_t remote_addr_len; char *remote_user; uint16_t remote_user_len; char *query_string; uint16_t query_string_len; char *protocol; uint16_t protocol_len; char *method; uint16_t method_len; char *scheme; uint16_t scheme_len; char *https; uint16_t https_len; char *script_name; uint16_t script_name_len; int script_name_pos; char *host; uint16_t host_len; char *content_type; uint16_t content_type_len; char *document_root; uint16_t document_root_len; char *user_agent; uint16_t user_agent_len; char *encoding; uint16_t encoding_len; char *referer; uint16_t referer_len; char *cookie; uint16_t cookie_len; char *path_info; uint16_t path_info_len; int path_info_pos; char *authorization; uint16_t authorization_len; uint16_t via; char *script; uint16_t script_len; char *module; uint16_t module_len; char *callable; uint16_t callable_len; char *home; uint16_t home_len; char *file; uint16_t file_len; char *paste; uint16_t paste_len; char *chdir; uint16_t chdir_len; char *touch_reload; uint16_t touch_reload_len; char *cache_get; uint16_t cache_get_len; char *if_modified_since; uint16_t if_modified_since_len; int fd_closed; int sendfile_fd; size_t sendfile_fd_chunk; size_t sendfile_fd_size; off_t sendfile_fd_pos; void *sendfile_obj; uint16_t var_cnt; uint16_t header_cnt; int do_not_log; int do_not_add_to_async_queue; int do_not_account; int status; struct uwsgi_buffer *headers; size_t response_size; size_t headers_size; int async_id; int async_status; int switches; size_t write_pos; int async_timed_out; int async_ready_fd; int async_last_ready_fd; struct uwsgi_rb_timer *async_timeout; struct uwsgi_async_fd *waiting_fds; void *async_app; void *async_result; void *async_placeholder; void *async_args; void *async_environ; void *async_input; void *async_sendfile; int async_force_again; int async_plagued; int suspended; uint64_t write_errors; uint64_t read_errors; int *ovector; size_t post_cl; size_t post_pos; size_t post_readline_size; size_t post_readline_pos; size_t post_readline_watermark; FILE *post_file; char *post_readline_buf; // this is used when no post buffering is in place char *post_read_buf; size_t post_read_buf_size; char *post_buffering_buf; // when set, do not send warnings about bad behaviours int post_warning; // deprecated fields: size_t is 32bit on 32bit platform size_t __range_from; size_t __range_to; // current socket mapped to request struct uwsgi_socket *socket; // check if headers are already sent int headers_sent; int headers_hvec; uint64_t proto_parser_pos; uint64_t proto_parser_move; int64_t proto_parser_status; void *proto_parser_buf; uint64_t proto_parser_buf_size; void *proto_parser_remains_buf; size_t proto_parser_remains; char *buffer; int log_this; int sigwait; int signal_received; struct uwsgi_logvar *logvars; struct uwsgi_string_list *additional_headers; struct uwsgi_string_list *remove_headers; struct uwsgi_buffer *websocket_buf; struct uwsgi_buffer *websocket_send_buf; size_t websocket_need; int websocket_phase; uint8_t websocket_opcode; size_t websocket_has_mask; size_t websocket_size; size_t websocket_pktsize; time_t websocket_last_ping; time_t websocket_last_pong; int websocket_closed; // websocket specific headers char *http_sec_websocket_key; uint16_t http_sec_websocket_key_len; char *http_origin; uint16_t http_origin_len; char *http_sec_websocket_protocol; uint16_t http_sec_websocket_protocol_len; struct uwsgi_buffer *chunked_input_buf; uint8_t chunked_input_parser_status; ssize_t chunked_input_chunk_len; size_t chunked_input_need; uint8_t chunked_input_complete; size_t chunked_input_decapitate; uint64_t stream_id; // avoid routing loops int is_routing; int is_final_routing; int is_error_routing; int is_response_routing; int routes_applied; int response_routes_applied; // internal routing vm program counter uint32_t route_pc; uint32_t error_route_pc; uint32_t response_route_pc; uint32_t final_route_pc; // internal routing goto instruction uint32_t route_goto; uint32_t error_route_goto; uint32_t response_route_goto; uint32_t final_route_goto; int ignore_body; struct uwsgi_transformation *transformations; char *transformed_chunk; size_t transformed_chunk_len; int is_raw; #ifdef UWSGI_SSL SSL *ssl; #endif // do not update avg_rt after request int do_not_account_avg_rt; // used for protocol parsers requiring EOF signaling int proto_parser_eof; // 64bit range, deprecates size_t __range_from, __range_to enum uwsgi_range range_parsed; int64_t range_from; int64_t range_to; char * if_range; uint16_t if_range_len; // client address in a type-safe fashion; always use this over // c_addr (which only exists to maintain binary compatibility in this // struct) union address { struct sockaddr_in sin; struct sockaddr_in6 sin6; struct sockaddr_un sun; } client_addr; uint8_t websocket_is_fin; }; struct uwsgi_fmon { char filename[0xff]; int fd; int id; int registered; uint8_t sig; }; struct uwsgi_timer { int value; int fd; int id; int registered; uint8_t sig; }; struct uwsgi_signal_rb_timer { int value; int registered; int iterations; int iterations_done; uint8_t sig; struct uwsgi_rb_timer *uwsgi_rb_timer; }; struct uwsgi_cheaper_algo { char *name; int (*func) (int); struct uwsgi_cheaper_algo *next; }; struct uwsgi_emperor_scanner; struct uwsgi_imperial_monitor { char *scheme; void (*init) (struct uwsgi_emperor_scanner *); void (*func) (struct uwsgi_emperor_scanner *); struct uwsgi_imperial_monitor *next; }; struct uwsgi_clock { char *name; time_t(*seconds) (void); uint64_t(*microseconds) (void); struct uwsgi_clock *next; }; struct uwsgi_subscribe_slot; struct uwsgi_stats_pusher; struct uwsgi_stats_pusher_instance; #define UWSGI_PROTO_MIN_CHECK 4 #define UWSGI_PROTO_MAX_CHECK 28 struct uwsgi_offload_engine; // these are the possible states of an instance struct uwsgi_instance_status { int gracefully_reloading; int brutally_reloading; int gracefully_destroying; int brutally_destroying; int chain_reloading; int workers_reloading; int is_cheap; int is_cleaning; int dying_for_need_app; }; struct uwsgi_configurator { char *name; void (*func)(char *, char **); struct uwsgi_configurator *next; }; struct uwsgi_configurator *uwsgi_register_configurator(char *, void (*)(char *, char **)); void uwsgi_opt_load_config(char *, char *, void *); #define uwsgi_instance_is_dying (uwsgi.status.gracefully_destroying || uwsgi.status.brutally_destroying) #define uwsgi_instance_is_reloading (uwsgi.status.gracefully_reloading || uwsgi.status.brutally_reloading) #define exit(x) uwsgi_exit(x) struct uwsgi_metric; struct uwsgi_logging_options { int enabled; int memory_report; int zero; int _4xx; int _5xx; int sendfile; int ioerror; uint32_t slow; uint64_t big; int log_x_forwarded_for; }; struct uwsgi_harakiri_options { int workers; int spoolers; int mules; }; struct uwsgi_fsmon { char *path; int fd; int id; void *data; void (*func)(struct uwsgi_fsmon *); struct uwsgi_fsmon *next; }; struct uwsgi_server { // store the machine hostname char hostname[256]; int hostname_len; // used to store the exit code for atexit hooks int last_exit_code; int (*proto_hooks[UWSGI_PROTO_MAX_CHECK]) (struct wsgi_request *, char *, char *, uint16_t); struct uwsgi_configurator *configurators; char **orig_argv; char **argv; int argc; int max_procname; int auto_procname; char **environ; char *procname_prefix; char *procname_append; char *procname_master; char *procname; struct uwsgi_logging_options logging_options; struct uwsgi_harakiri_options harakiri_options; int socket_timeout; int reaper; int cgi_mode; uint64_t max_requests; uint64_t min_worker_lifetime; uint64_t max_worker_lifetime; // daemontools-like envdir struct uwsgi_string_list *envdirs; char *requested_clock; struct uwsgi_clock *clocks; struct uwsgi_clock *clock; char *empty; // quiet startup int no_initial_output; struct uwsgi_instance_status status; struct uwsgi_string_list *get_list; // enable threads int has_threads; int no_threads_wait; // default app id int default_app; char *logto2; char *logformat; int logformat_strftime; int logformat_vectors; struct uwsgi_logchunk *logchunks; struct uwsgi_logchunk *registered_logchunks; void (*logit) (struct wsgi_request *); struct iovec **logvectors; // autoload plugins int autoload; struct uwsgi_string_list *plugins_dir; struct uwsgi_string_list *blacklist; struct uwsgi_string_list *whitelist; char *blacklist_context; char *whitelist_context; unsigned int reloads; // leave master running as root int master_as_root; // postpone privileges drop int drop_after_init; int drop_after_apps; int master_is_reforked; struct uwsgi_string_list *master_fifo; int master_fifo_fd; int master_fifo_slot; // kill the stack on SIGTERM (instead of brutal reloading) int die_on_term; // force the first gateway without a master int force_gateway; // disable fd passing on unix socket int no_fd_passing; // store the current time time_t current_time; uint64_t master_cycles; int reuse_port; int tcp_fast_open; int tcp_fast_open_client; int enable_proxy_protocol; uint64_t fastcgi_modifier1; uint64_t fastcgi_modifier2; uint64_t http_modifier1; uint64_t http_modifier2; uint64_t https_modifier1; uint64_t https_modifier2; uint64_t scgi_modifier1; uint64_t scgi_modifier2; uint64_t raw_modifier1; uint64_t raw_modifier2; // enable lazy mode int lazy; // enable lazy-apps mode int lazy_apps; // enable cheaper mode int cheaper; char *requested_cheaper_algo; struct uwsgi_cheaper_algo *cheaper_algos; int (*cheaper_algo) (int); int cheaper_step; uint64_t cheaper_overload; // minimal number of running workers in cheaper mode int cheaper_count; int cheaper_initial; // enable idle mode int idle; // cheaper mode memory usage limits uint64_t cheaper_rss_limit_soft; uint64_t cheaper_rss_limit_hard; int cheaper_fifo_delta; // destroy the stack when idle int die_on_idle; // store the screen session char *screen_session; // true if run under the emperor int has_emperor; char *emperor_procname; char *emperor_proxy; int emperor_fd; int emperor_fd_proxy; int emperor_queue; int emperor_nofollow; int emperor_tyrant; int emperor_tyrant_nofollow; int emperor_fd_config; int early_emperor; int emperor_throttle; int emperor_freq; int emperor_max_throttle; int emperor_magic_exec; int emperor_heartbeat; int emperor_curse_tolerance; struct uwsgi_string_list *emperor_extra_extension; // search for a file with the specified extension at the same level of the vassal file char *emperor_on_demand_extension; // bind to a unix socket on the specified directory named directory/vassal.socket char *emperor_on_demand_directory; // run a shell script passing the vassal as the only argument, the stdout is used as the socket char *emperor_on_demand_exec; int disable_nuclear_blast; time_t next_heartbeat; int heartbeat; struct uwsgi_string_list *emperor; struct uwsgi_imperial_monitor *emperor_monitors; char *emperor_absolute_dir; char *emperor_pidfile; pid_t emperor_pid; int emperor_broodlord; int emperor_broodlord_count; uint64_t emperor_broodlord_num; char *emperor_stats; int emperor_stats_fd; struct uwsgi_string_list *vassals_templates; struct uwsgi_string_list *vassals_includes; struct uwsgi_string_list *vassals_templates_before; struct uwsgi_string_list *vassals_includes_before; struct uwsgi_string_list *vassals_set; // true if loyal to the emperor int loyal; // emperor hook (still in development) char *vassals_start_hook; char *vassals_stop_hook; struct uwsgi_string_list *additional_headers; struct uwsgi_string_list *remove_headers; struct uwsgi_string_list *collect_headers; // set cpu affinity int cpu_affinity; int reload_mercy; int worker_reload_mercy; // map reloads to death int exit_on_reload; // store options int dirty_config; int option_index; int (*logic_opt) (char *, char *); char *logic_opt_arg; char *logic_opt_data; int logic_opt_running; int logic_opt_cycles; struct uwsgi_option *options; struct option *long_options; char *short_options; struct uwsgi_opt **exported_opts; int exported_opts_cnt; struct uwsgi_custom_option *custom_options; // dump the whole set of options int dump_options; // show ini representation of the current config int show_config; // enable strict mode (only registered options can be used) int strict; // list loaded features int cheaper_algo_list; #ifdef UWSGI_ROUTING int router_list; #endif int imperial_monitor_list; int plugins_list; int loggers_list; int loop_list; int clock_list; int alarms_list; struct wsgi_request *wsgi_req; char *remap_modifier; // enable zerg mode int *zerg; char *zerg_server; struct uwsgi_string_list *zerg_node; int zerg_fallback; int zerg_server_fd; // security char *chroot; gid_t gid; uid_t uid; char *uidname; char *gidname; int no_initgroups; struct uwsgi_string_list *additional_gids; #ifdef UWSGI_CAP cap_value_t *cap; int cap_count; cap_value_t *emperor_cap; int emperor_cap_count; #endif #ifdef __linux__ int unshare; int unshare2; int emperor_clone; char *pivot_root; char *setns_socket; struct uwsgi_string_list *setns_socket_skip; char *setns; int setns_socket_fd; int setns_preopen; int setns_fds[64]; int setns_fds_count; #endif char *emperor_wrapper; int jailed; #if defined(__FreeBSD__) || defined(__GNU_kFreeBSD__) char *jail; struct uwsgi_string_list *jail_ip4; #ifdef AF_INET6 struct uwsgi_string_list *jail_ip6; #endif struct uwsgi_string_list *jail2; char *jidfile; char *jail_attach; #endif int refork; int refork_as_root; int refork_post_jail; int ignore_sigpipe; int ignore_write_errors; uint64_t write_errors_tolerance; int write_errors_exception_only; int disable_write_exception; // still working on it char *profiler; // the weight of the instance, used by various cluster/lb components uint64_t weight; int auto_weight; // mostly useless char *mode; // binary patch the worker image char *worker_exec; char *worker_exec2; // this must be UN-shared struct uwsgi_gateway_socket *gateway_sockets; int ignore_script_name; int manage_script_name; int reload_on_exception; int catch_exceptions; struct uwsgi_string_list *reload_on_exception_type; struct uwsgi_string_list *reload_on_exception_value; struct uwsgi_string_list *reload_on_exception_repr; struct uwsgi_exception_handler *exception_handlers; struct uwsgi_string_list *exception_handlers_instance; struct uwsgi_thread *exception_handler_thread; uint64_t exception_handler_msg_size; int no_default_app; // exit if no-app is loaded int need_app; int forkbomb_delay; int logdate; int log_micros; char *log_strftime; int honour_stdin; struct termios termios; int restore_tc; // honour the HTTP Range header int honour_range; // route all of the logs to the master process int req_log_master; int log_master; char *log_master_buf; size_t log_master_bufsize; int log_master_stream; int log_master_req_stream; int log_reopen; int log_truncate; uint64_t log_maxsize; char *log_backupname; int original_log_fd; int req_log_fd; // static file serving int file_serve_mode; int build_mime_dict; struct uwsgi_string_list *mime_file; struct uwsgi_hook *hooks; struct uwsgi_string_list *hook_touch; struct uwsgi_string_list *hook_asap; struct uwsgi_string_list *hook_pre_jail; struct uwsgi_string_list *hook_post_jail; struct uwsgi_string_list *hook_in_jail; struct uwsgi_string_list *hook_as_root; struct uwsgi_string_list *hook_as_user; struct uwsgi_string_list *hook_as_user_atexit; struct uwsgi_string_list *hook_pre_app; struct uwsgi_string_list *hook_post_app; struct uwsgi_string_list *hook_accepting; struct uwsgi_string_list *hook_accepting1; struct uwsgi_string_list *hook_accepting_once; struct uwsgi_string_list *hook_accepting1_once; struct uwsgi_string_list *hook_emperor_start; struct uwsgi_string_list *hook_master_start; struct uwsgi_string_list *hook_emperor_stop; struct uwsgi_string_list *hook_emperor_reload; struct uwsgi_string_list *hook_emperor_lost; struct uwsgi_string_list *hook_as_vassal; struct uwsgi_string_list *hook_as_emperor; struct uwsgi_string_list *hook_as_mule; struct uwsgi_string_list *hook_as_gateway; struct uwsgi_string_list *exec_asap; struct uwsgi_string_list *exec_pre_jail; struct uwsgi_string_list *exec_post_jail; struct uwsgi_string_list *exec_in_jail; struct uwsgi_string_list *exec_as_root; struct uwsgi_string_list *exec_as_user; struct uwsgi_string_list *exec_as_user_atexit; struct uwsgi_string_list *exec_pre_app; struct uwsgi_string_list *exec_post_app; struct uwsgi_string_list *exec_as_vassal; struct uwsgi_string_list *exec_as_emperor; struct uwsgi_string_list *call_asap; struct uwsgi_string_list *call_pre_jail; struct uwsgi_string_list *call_post_jail; struct uwsgi_string_list *call_in_jail; struct uwsgi_string_list *call_as_root; struct uwsgi_string_list *call_as_user; struct uwsgi_string_list *call_as_user_atexit; struct uwsgi_string_list *call_pre_app; struct uwsgi_string_list *call_post_app; struct uwsgi_string_list *call_as_vassal; struct uwsgi_string_list *call_as_vassal1; struct uwsgi_string_list *call_as_vassal3; struct uwsgi_string_list *call_as_emperor; struct uwsgi_string_list *call_as_emperor1; struct uwsgi_string_list *call_as_emperor2; struct uwsgi_string_list *call_as_emperor4; struct uwsgi_string_list *mount_asap; struct uwsgi_string_list *mount_pre_jail; struct uwsgi_string_list *mount_post_jail; struct uwsgi_string_list *mount_in_jail; struct uwsgi_string_list *mount_as_root; struct uwsgi_string_list *mount_as_vassal; struct uwsgi_string_list *mount_as_emperor; struct uwsgi_string_list *umount_asap; struct uwsgi_string_list *umount_pre_jail; struct uwsgi_string_list *umount_post_jail; struct uwsgi_string_list *umount_in_jail; struct uwsgi_string_list *umount_as_root; struct uwsgi_string_list *umount_as_vassal; struct uwsgi_string_list *umount_as_emperor; struct uwsgi_string_list *after_request_hooks; struct uwsgi_string_list *wait_for_interface; int wait_for_interface_timeout; char *privileged_binary_patch; char *unprivileged_binary_patch; char *privileged_binary_patch_arg; char *unprivileged_binary_patch_arg; struct uwsgi_logger *loggers; struct uwsgi_logger *choosen_logger; struct uwsgi_logger *choosen_req_logger; struct uwsgi_string_list *requested_logger; struct uwsgi_string_list *requested_req_logger; struct uwsgi_log_encoder *log_encoders; struct uwsgi_string_list *requested_log_encoders; struct uwsgi_string_list *requested_log_req_encoders; #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) int pcre_jit; struct uwsgi_regexp_list *log_drain_rules; struct uwsgi_regexp_list *log_filter_rules; struct uwsgi_regexp_list *log_route; struct uwsgi_regexp_list *log_req_route; #endif int use_abort; int alarm_freq; uint64_t alarm_msg_size; struct uwsgi_string_list *alarm_list; struct uwsgi_string_list *alarm_logs_list; struct uwsgi_alarm_fd *alarm_fds; struct uwsgi_string_list *alarm_fd_list; struct uwsgi_string_list *alarm_segfault; struct uwsgi_string_list *alarm_backlog; struct uwsgi_alarm *alarms; struct uwsgi_alarm_instance *alarm_instances; struct uwsgi_alarm_log *alarm_logs; struct uwsgi_thread *alarm_thread; int threaded_logger; pthread_mutex_t threaded_logger_lock; int *safe_fds; int safe_fds_cnt; int daemons_honour_stdin; struct uwsgi_daemon *daemons; int daemons_cnt; #ifdef UWSGI_SSL char *subscriptions_sign_check_dir; int subscriptions_sign_check_tolerance; const EVP_MD *subscriptions_sign_check_md; struct uwsgi_string_list *subscriptions_sign_skip_uid; #endif struct uwsgi_string_list *subscriptions_credentials_check_dir; int subscriptions_use_credentials; struct uwsgi_dyn_dict *static_maps; struct uwsgi_dyn_dict *static_maps2; struct uwsgi_dyn_dict *check_static; struct uwsgi_dyn_dict *mimetypes; struct uwsgi_string_list *static_skip_ext; struct uwsgi_string_list *static_index; struct uwsgi_string_list *static_safe; struct uwsgi_hash_algo *hash_algos; int use_static_cache_paths; char *static_cache_paths_name; struct uwsgi_cache *static_cache_paths; int cache_expire_freq; int cache_report_freed_items; int cache_no_expire; uint64_t cache_max_items; uint64_t cache_blocksize; char *cache_store; int cache_store_sync; struct uwsgi_string_list *cache2; int cache_setup; int locking_setup; int cache_use_last_modified; struct uwsgi_dyn_dict *static_expires_type; struct uwsgi_dyn_dict *static_expires_type_mtime; struct uwsgi_dyn_dict *static_expires; struct uwsgi_dyn_dict *static_expires_mtime; struct uwsgi_dyn_dict *static_expires_uri; struct uwsgi_dyn_dict *static_expires_uri_mtime; struct uwsgi_dyn_dict *static_expires_path_info; struct uwsgi_dyn_dict *static_expires_path_info_mtime; int static_gzip_all; struct uwsgi_string_list *static_gzip_dir; struct uwsgi_string_list *static_gzip_ext; #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) struct uwsgi_regexp_list *static_gzip; #endif struct uwsgi_offload_engine *offload_engines; struct uwsgi_offload_engine *offload_engine_sendfile; struct uwsgi_offload_engine *offload_engine_transfer; struct uwsgi_offload_engine *offload_engine_memory; struct uwsgi_offload_engine *offload_engine_pipe; int offload_threads; int offload_threads_events; struct uwsgi_thread **offload_thread; int check_static_docroot; int disable_sendfile; char *daemonize; char *daemonize2; int do_not_change_umask; char *logfile; int logfile_chown; // enable vhost mode int vhost; int vhost_host; // async commodity struct wsgi_request **async_waiting_fd_table; struct wsgi_request **async_proto_fd_table; struct uwsgi_async_request *async_runqueue; struct uwsgi_async_request *async_runqueue_last; struct uwsgi_rbtree *rb_async_timeouts; int async_queue_unused_ptr; struct wsgi_request **async_queue_unused; // store rlimit struct rlimit rl; struct rlimit rl_nproc; size_t limit_post; // set process priority int prio; // funny reload systems int force_get_memusage; rlim_t reload_on_as; rlim_t reload_on_rss; rlim_t evil_reload_on_as; rlim_t evil_reload_on_rss; struct uwsgi_string_list *reload_on_fd; struct uwsgi_string_list *brutal_reload_on_fd; struct uwsgi_string_list *touch_reload; struct uwsgi_string_list *touch_chain_reload; struct uwsgi_string_list *touch_workers_reload; struct uwsgi_string_list *touch_gracefully_stop; struct uwsgi_string_list *touch_logrotate; struct uwsgi_string_list *touch_logreopen; struct uwsgi_string_list *touch_exec; struct uwsgi_string_list *touch_signal; struct uwsgi_string_list *fs_reload; struct uwsgi_string_list *fs_brutal_reload; struct uwsgi_string_list *fs_signal; struct uwsgi_fsmon *fsmon; struct uwsgi_string_list *signal_timers; struct uwsgi_string_list *rb_signal_timers; struct uwsgi_string_list *mountpoints_check; int propagate_touch; // enable grunt mode int grunt; // store the binary path char *binary_path; int is_a_reload; char *udp_socket; int multicast_ttl; int multicast_loop; char *multicast_group; struct uwsgi_spooler *spoolers; int spooler_numproc; struct uwsgi_spooler *i_am_a_spooler; char *spooler_chdir; int spooler_max_tasks; int spooler_ordered; int spooler_quiet; int spooler_frequency; int snmp; char *snmp_addr; char *snmp_community; struct uwsgi_lock_item *snmp_lock; int snmp_fd; int udp_fd; uint16_t buffer_size; int signal_bufsize; // post buffering size_t post_buffering; int post_buffering_harakiri; size_t post_buffering_bufsize; size_t body_read_warning; int master_process; int master_queue; int master_interval; // mainly useful for broodlord mode int vassal_sos_backlog; int no_defer_accept; int so_keepalive; int so_send_timeout; uint64_t so_sndbuf; uint64_t so_rcvbuf; int page_size; int cpus; char *pidfile; char *pidfile2; char *flock2; char *flock_wait2; int backtrace_depth; int harakiri_verbose; int harakiri_no_arh; int magic_table_first_round; char *magic_table[256]; int numproc; int async; int async_running; int async_queue; int async_nevents; time_t async_queue_is_full; int max_vars; int vec_size; // shared area struct uwsgi_string_list *sharedareas_list; int sharedareas_cnt; struct uwsgi_sharedarea **sharedareas; // avoid thundering herd in threaded modes pthread_mutex_t thunder_mutex; pthread_mutex_t lock_static; int use_thunder_lock; struct uwsgi_lock_item *the_thunder_lock; /* the list of workers */ struct uwsgi_worker *workers; int max_apps; /* the list of mules */ struct uwsgi_string_list *mules_patches; struct uwsgi_mule *mules; struct uwsgi_string_list *farms_list; struct uwsgi_farm *farms; int mule_msg_size; pid_t mypid; int mywid; int muleid; int mules_cnt; int farms_cnt; rlim_t requested_max_fd; rlim_t max_fd; struct timeval start_tv; int abstract_socket; #ifdef __linux__ int freebind; #endif int chmod_socket; char *chown_socket; mode_t chmod_socket_value; mode_t chmod_logfile_value; int listen_queue; char *fallback_config; #ifdef UWSGI_ROUTING struct uwsgi_router *routers; struct uwsgi_route *routes; struct uwsgi_route *final_routes; struct uwsgi_route *error_routes; struct uwsgi_route *response_routes; struct uwsgi_route_condition *route_conditions; struct uwsgi_route_var *route_vars; #endif struct uwsgi_string_list *error_page_403; struct uwsgi_string_list *error_page_404; struct uwsgi_string_list *error_page_500; int single_interpreter; struct uwsgi_shared *shared; int no_orphans; int skip_zero; int skip_atexit; char *force_cwd; char *chdir; char *chdir2; struct uwsgi_string_list *binsh; int vacuum; int no_server; int command_mode; int xml_round2; char *cwd; // conditional logging int log_slow_requests; int log_zero_headers; int log_empty_body; int log_high_memory; #ifdef __linux__ struct uwsgi_string_list *cgroup; struct uwsgi_string_list *cgroup_opt; char *cgroup_dir_mode; char *ns; char *ns_net; struct uwsgi_string_list *ns_keep_mount; #endif struct uwsgi_string_list *file_write_list; char *protocol; int signal_socket; int my_signal_socket; struct uwsgi_protocol *protocols; struct uwsgi_socket *sockets; struct uwsgi_socket *shared_sockets; int is_et; struct uwsgi_string_list *map_socket; struct uwsgi_cron *crons; time_t cron_harakiri; time_t respawn_delta; struct uwsgi_string_list *mounts; int cores; int threads; pthread_attr_t threads_attr; size_t threads_stacksize; //this key old the u_request structure per core / thread pthread_key_t tur_key; struct wsgi_request *(*current_wsgi_req) (void); void (*notify) (char *); void (*notify_ready) (void); int notification_fd; void *notification_object; // usedby suspend/resume loops void (*schedule_to_main) (struct wsgi_request *); void (*schedule_to_req) (void); void (*schedule_fix) (struct wsgi_request *); void (*gbcw_hook) (void); int close_on_exec; int close_on_exec2; int tcp_nodelay; char *loop; struct uwsgi_loop *loops; struct uwsgi_plugin *p[256]; struct uwsgi_plugin *gp[MAX_GENERIC_PLUGINS]; int gp_cnt; char *allowed_modifiers; char *upload_progress; struct uwsgi_lock_item *registered_locks; struct uwsgi_lock_ops lock_ops; char *lock_engine; char *ftok; char *lock_id; size_t lock_size; size_t rwlock_size; struct uwsgi_string_list *add_cache_item; struct uwsgi_string_list *load_file_in_cache; #ifdef UWSGI_ZLIB struct uwsgi_string_list *load_file_in_cache_gzip; #endif char *use_check_cache; struct uwsgi_cache *check_cache; struct uwsgi_cache *caches; struct uwsgi_string_list *cache_udp_server; struct uwsgi_string_list *cache_udp_node; char *cache_sync; // the stats server char *stats; int stats_fd; int stats_http; int stats_minified; struct uwsgi_string_list *requested_stats_pushers; struct uwsgi_stats_pusher *stats_pushers; struct uwsgi_stats_pusher_instance *stats_pusher_instances; int stats_pusher_default_freq; uint64_t queue_size; uint64_t queue_blocksize; void *queue; struct uwsgi_queue_header *queue_header; char *queue_store; size_t queue_filesize; int queue_store_sync; int locks; int persistent_ipcsem; struct uwsgi_lock_item *queue_lock; struct uwsgi_lock_item **user_lock; struct uwsgi_lock_item *signal_table_lock; struct uwsgi_lock_item *fmon_table_lock; struct uwsgi_lock_item *timer_table_lock; struct uwsgi_lock_item *rb_timer_table_lock; struct uwsgi_lock_item *cron_table_lock; struct uwsgi_lock_item *rpc_table_lock; struct uwsgi_lock_item *sa_lock; struct uwsgi_lock_item *metrics_lock; // rpc uint64_t rpc_max; struct uwsgi_rpc *rpc_table; // subscription client int subscriptions_blocked; int subscribe_freq; int subscription_tolerance; int unsubscribe_on_graceful_reload; struct uwsgi_string_list *subscriptions; struct uwsgi_string_list *subscriptions2; struct uwsgi_subscribe_node *(*subscription_algo) (struct uwsgi_subscribe_slot *, struct uwsgi_subscribe_node *); int subscription_dotsplit; int never_swap; #ifdef UWSGI_SSL int ssl_initialized; int ssl_verbose; char *ssl_sessions_use_cache; int ssl_sessions_timeout; struct uwsgi_cache *ssl_sessions_cache; char *ssl_tmp_dir; #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) struct uwsgi_regexp_list *sni_regexp; #endif struct uwsgi_string_list *sni; char *sni_dir; char *sni_dir_ciphers; #endif #ifdef UWSGI_SSL struct uwsgi_legion *legions; struct uwsgi_legion_action *legion_actions; int legion_queue; int legion_freq; int legion_tolerance; int legion_skew_tolerance; uint16_t legion_scroll_max_size; uint64_t legion_scroll_list_max_size; int legion_death_on_lord_error; #endif #ifdef __linux__ #ifdef MADV_MERGEABLE int linux_ksm; int ksm_buffer_size; char *ksm_mappings_last; char *ksm_mappings_current; size_t ksm_mappings_last_size; size_t ksm_mappings_current_size; #endif #endif struct uwsgi_buffer *websockets_ping; struct uwsgi_buffer *websockets_pong; struct uwsgi_buffer *websockets_close; int websockets_ping_freq; int websockets_pong_tolerance; uint64_t websockets_max_size; int chunked_input_timeout; uint64_t chunked_input_limit; struct uwsgi_metric *metrics; struct uwsgi_metric_collector *metric_collectors; int has_metrics; char *metrics_dir; int metrics_dir_restore; uint64_t metrics_cnt; struct uwsgi_string_list *additional_metrics; struct uwsgi_string_list *metrics_threshold; int (*wait_write_hook) (int, int); int (*wait_read_hook) (int, int); int (*wait_milliseconds_hook) (int); int (*wait_read2_hook) (int, int, int, int *); struct uwsgi_string_list *schemes; // inject text files (useful for advanced templating) struct uwsgi_string_list *inject_before; struct uwsgi_string_list *inject_after; // this is a unix socket receiving external notifications (like subscription replies) char *notify_socket; int notify_socket_fd; char *subscription_notify_socket; //uWSGI 2.0.5 int mule_reload_mercy; int alarm_cheap; int emperor_no_blacklist; int metrics_no_cores; int stats_no_cores; int stats_no_metrics; // uWSGI 2.0.7 int vassal_sos; // uWSGI 2.0.8 struct uwsgi_string_list *wait_for_fs; struct uwsgi_string_list *wait_for_dir; struct uwsgi_string_list *wait_for_file; int wait_for_fs_timeout; struct uwsgi_string_list *wait_for_mountpoint; #ifdef UWSGI_SSL int sslv3; struct uwsgi_string_list *ssl_options; #endif struct uwsgi_string_list *hook_post_fork; // uWSGI 2.0.9 char *subscribe_with_modifier1; struct uwsgi_string_list *pull_headers; // uWSGI 2.0.10 struct uwsgi_string_list *emperor_wrapper_override; struct uwsgi_string_list *emperor_wrapper_fallback; // uWSGI 2.0.11 struct uwsgi_string_list *wait_for_socket; int wait_for_socket_timeout; int mem_collector_freq; // uWSGI 2.0.14 struct uwsgi_string_list *touch_mules_reload; struct uwsgi_string_list *touch_spoolers_reload; int spooler_reload_mercy; int skip_atexit_teardown; // uWSGI 2.1 backport int new_argc; char **new_argv; // uWSGI 2.0.16 #ifdef UWSGI_SSL int ssl_verify_depth; #endif size_t response_header_limit; char *safe_pidfile; char *safe_pidfile2; // uWSGI 2.0.17 int shutdown_sockets; #ifdef UWSGI_SSL int tlsv1; #endif // uWSGI 2.0.19 int emperor_graceful_shutdown; int is_chrooted; struct uwsgi_buffer *websockets_continuation_buffer; uint64_t max_worker_lifetime_delta; // uWSGI 2.0.22 int harakiri_graceful_timeout; int harakiri_graceful_signal; int harakiri_queue_threshold; // uWSGI 2.0.27 // This pipe is used to stop event_queue_wait() in threaded workers. int loop_stop_pipe[2]; // uWSGI 2.0.29 uint64_t max_requests_delta; }; struct uwsgi_rpc { char name[UMAX8]; void *func; uint8_t args; uint8_t shared; struct uwsgi_plugin *plugin; }; struct uwsgi_signal_entry { int wid; uint8_t modifier1; char receiver[64]; void *handler; }; /* they are here for backwards compatibility */ #define SNMP_COUNTER32 0x41 #define SNMP_GAUGE 0x42 #define SNMP_COUNTER64 0x46 struct uwsgi_snmp_custom_value { uint8_t type; uint64_t val; }; int uwsgi_setup_snmp(void); struct uwsgi_snmp_server_value { uint8_t type; uint64_t *val; }; struct uwsgi_cron { int minute; int hour; int day; int month; int week; time_t last_job; uint8_t sig; char *command; void (*func)(struct uwsgi_cron *, time_t); time_t started_at; // next harakiri timestamp time_t harakiri; // number of seconds to wait before calling harakiri on cron int mercy; uint8_t unique; pid_t pid; struct uwsgi_cron *next; #ifdef UWSGI_SSL char *legion; #endif }; struct uwsgi_shared { //vga 80 x25 specific ! char warning_message[81]; off_t logsize; char snmp_community[72 + 1]; struct uwsgi_snmp_server_value snmp_gvalue[100]; struct uwsgi_snmp_custom_value snmp_value[100]; int worker_signal_pipe[2]; int spooler_frequency; int spooler_signal_pipe[2]; int mule_signal_pipe[2]; int mule_queue_pipe[2]; // 256 items * (uwsgi.numproc + 1) struct uwsgi_signal_entry *signal_table; struct uwsgi_fmon files_monitored[64]; int files_monitored_cnt; struct uwsgi_timer timers[MAX_TIMERS]; int timers_cnt; struct uwsgi_signal_rb_timer rb_timers[MAX_TIMERS]; int rb_timers_cnt; uint64_t *rpc_count; int worker_log_pipe[2]; // used for request logging int worker_req_log_pipe[2]; uint64_t load; uint64_t max_load; struct uwsgi_cron cron[MAX_CRONS]; int cron_cnt; uint64_t backlog; uint64_t backlog_errors; // gateways struct uwsgi_gateway gateways[MAX_GATEWAYS]; int gateways_cnt; time_t gateways_harakiri[MAX_GATEWAYS]; uint64_t routed_signals; uint64_t unrouted_signals; uint64_t busy_workers; uint64_t idle_workers; uint64_t overloaded; int ready; }; struct uwsgi_core { //time_t harakiri; uint64_t requests; uint64_t failed_requests; uint64_t static_requests; uint64_t routed_requests; uint64_t offloaded_requests; uint64_t write_errors; uint64_t read_errors; uint64_t exceptions; pthread_t thread_id; int offload_rr; // one ts-perapp void **ts; int in_request; char *buffer; struct iovec *hvec; char *post_buf; struct wsgi_request req; }; struct uwsgi_worker { int id; pid_t pid; uint64_t status; time_t last_spawn; uint64_t respawn_count; uint64_t requests; uint64_t delta_requests; uint64_t failed_requests; time_t harakiri; time_t user_harakiri; uint64_t harakiri_count; int pending_harakiri; uint64_t vsz_size; uint64_t rss_size; uint64_t running_time; int manage_next_request; int destroy; int apps_cnt; struct uwsgi_app *apps; uint64_t tx; int hijacked; uint64_t hijacked_count; int cheaped; int suspended; int sig; uint8_t signum; time_t cursed_at; time_t no_mercy_at; // signals managed by this worker uint64_t signals; int signal_pipe[2]; uint64_t avg_response_time; struct uwsgi_core *cores; int accepting; char name[0xff]; int shutdown_sockets; }; struct uwsgi_mule { int id; pid_t pid; int signal_pipe[2]; int queue_pipe[2]; time_t last_spawn; uint64_t respawn_count; char *patch; // signals managed by this mule uint64_t signals; int sig; uint8_t signum; time_t harakiri; time_t user_harakiri; char name[0xff]; time_t cursed_at; time_t no_mercy_at; }; struct uwsgi_mule_farm { struct uwsgi_mule *mule; struct uwsgi_mule_farm *next; }; struct uwsgi_farm { int id; char name[0xff]; int signal_pipe[2]; int queue_pipe[2]; struct uwsgi_mule_farm *mules; }; char *uwsgi_get_cwd(void); void warn_pipe(void); void what_i_am_doing(void); void goodbye_cruel_world(void); void gracefully_kill(int); void reap_them_all(int); void kill_them_all(int); void grace_them_all(int); void end_me(int); int bind_to_unix(char *, int, int, int); int bind_to_tcp(char *, int, char *); int bind_to_udp(char *, int, int); int bind_to_unix_dgram(char *); int timed_connect(struct pollfd *, const struct sockaddr *, int, int, int); int uwsgi_connect(char *, int, int); int uwsgi_connect_udp(char *); int uwsgi_connectn(char *, uint16_t, int, int); void daemonize(char *); void logto(char *); void log_request(struct wsgi_request *); void get_memusage(uint64_t *, uint64_t *); void harakiri(void); void stats(int); #ifdef UWSGI_XML void uwsgi_xml_config(char *, struct wsgi_request *, char *[]); #endif void uwsgi_500(struct wsgi_request *); void uwsgi_403(struct wsgi_request *); void uwsgi_404(struct wsgi_request *); void uwsgi_405(struct wsgi_request *); void uwsgi_redirect_to_slash(struct wsgi_request *); void manage_snmp(int, uint8_t *, int, struct sockaddr_in *); void snmp_init(void); void uwsgi_master_manage_snmp(int); char *uwsgi_spool_request(struct wsgi_request *, char *, size_t, char *, size_t); void spooler(struct uwsgi_spooler *); pid_t spooler_start(struct uwsgi_spooler *); int uwsgi_spooler_read_header(char *, int, struct uwsgi_header *); int uwsgi_spooler_read_content(int, char *, char **, size_t *, struct uwsgi_header *, struct stat *); #if defined(_GNU_SOURCE) || defined(__UCLIBC__) #define uwsgi_versionsort versionsort #else int uwsgi_versionsort(const struct dirent **da, const struct dirent **db); #endif void uwsgi_curse(int, int); void uwsgi_curse_mule(int, int); void uwsgi_destroy_processes(void); void set_harakiri(int); void set_user_harakiri(int); void set_mule_harakiri(int); void set_spooler_harakiri(int); void inc_harakiri(int); #ifdef __BIG_ENDIAN__ uint16_t uwsgi_swap16(uint16_t); uint32_t uwsgi_swap32(uint32_t); uint64_t uwsgi_swap64(uint64_t); #endif int uwsgi_parse_request(int, struct wsgi_request *, int); int uwsgi_parse_vars(struct wsgi_request *); int uwsgi_enqueue_message(char *, int, uint8_t, uint8_t, char *, int, int); void manage_opt(int, char *); int uwsgi_ping_node(int, struct wsgi_request *); void uwsgi_async_init(void); void async_loop(); struct wsgi_request *find_first_available_wsgi_req(void); struct wsgi_request *find_first_accepting_wsgi_req(void); struct wsgi_request *find_wsgi_req_by_fd(int); struct wsgi_request *find_wsgi_req_by_id(int); void async_schedule_to_req_green(void); void async_schedule_to_req(void); int async_add_fd_write(struct wsgi_request *, int, int); int async_add_fd_read(struct wsgi_request *, int, int); void async_reset_request(struct wsgi_request *); struct wsgi_request *next_wsgi_req(struct wsgi_request *); void async_add_timeout(struct wsgi_request *, int); void uwsgi_as_root(void); void uwsgi_close_request(struct wsgi_request *); void wsgi_req_setup(struct wsgi_request *, int, struct uwsgi_socket *); int wsgi_req_recv(int, struct wsgi_request *); int wsgi_req_async_recv(struct wsgi_request *); int wsgi_req_accept(int, struct wsgi_request *); int wsgi_req_simple_accept(struct wsgi_request *, int); #define current_wsgi_req() (*uwsgi.current_wsgi_req)() void sanitize_args(void); void env_to_arg(char *, char *); void parse_sys_envs(char **); void uwsgi_log(const char *, ...); void uwsgi_log_verbose(const char *, ...); void uwsgi_logfile_write(const char *, ...); void *uwsgi_load_plugin(int, char *, char *); int unconfigured_hook(struct wsgi_request *); void uwsgi_ini_config(char *, char *[]); #ifdef UWSGI_YAML void uwsgi_yaml_config(char *, char *[]); #endif #ifdef UWSGI_JSON void uwsgi_json_config(char *, char *[]); #endif int uwsgi_strncmp(char *, int, char *, int); int uwsgi_strnicmp(char *, int, char *, int); int uwsgi_startswith(char *, char *, int); char *uwsgi_concat(int, ...); char *uwsgi_concatn(int, ...); char *uwsgi_concat2(char *, char *); char *uwsgi_concat2n(char *, int, char *, int); char *uwsgi_concat2nn(char *, int, char *, int, int *); char *uwsgi_concat3(char *, char *, char *); char *uwsgi_concat3n(char *, int, char *, int, char *, int); char *uwsgi_concat4(char *, char *, char *, char *); char *uwsgi_concat4n(char *, int, char *, int, char *, int, char *, int); int uwsgi_get_app_id(struct wsgi_request *, char *, uint16_t, int); char *uwsgi_strncopy(char *, int); int master_loop(char **, char **); int find_worker_id(pid_t); void simple_loop(); void *simple_loop_run(void *); int uwsgi_count_options(struct uwsgi_option *); struct wsgi_request *simple_current_wsgi_req(void); struct wsgi_request *threaded_current_wsgi_req(void); void build_options(void); int uwsgi_postbuffer_do_in_disk(struct wsgi_request *); int uwsgi_postbuffer_do_in_mem(struct wsgi_request *); void uwsgi_register_loop(char *, void (*)(void)); void *uwsgi_get_loop(char *); void add_exported_option(char *, char *, int); void add_exported_option_do(char *, char *, int, int); ssize_t uwsgi_send_empty_pkt(int, char *, uint8_t, uint8_t); int uwsgi_waitfd_event(int, int, int); #define uwsgi_waitfd(a, b) uwsgi_waitfd_event(a, b, POLLIN) #define uwsgi_waitfd_write(a, b) uwsgi_waitfd_event(a, b, POLLOUT) int uwsgi_hooked_parse_dict_dgram(int, char *, size_t, uint8_t, uint8_t, void (*)(char *, uint16_t, char *, uint16_t, void *), void *); int uwsgi_hooked_parse(char *, size_t, void (*)(char *, uint16_t, char *, uint16_t, void *), void *); int uwsgi_hooked_parse_array(char *, size_t, void (*) (uint16_t, char *, uint16_t, void *), void *); int uwsgi_get_dgram(int, struct wsgi_request *); int uwsgi_string_sendto(int, uint8_t, uint8_t, struct sockaddr *, socklen_t, char *, size_t); void uwsgi_stdin_sendto(char *, uint8_t, uint8_t); char *generate_socket_name(char *); #define UMIN(a,b) ((a)>(b)?(b):(a)) #define UMAX(a,b) ((a)<(b)?(b):(a)) ssize_t uwsgi_send_message(int, uint8_t, uint8_t, char *, uint16_t, int, ssize_t, int); int uwsgi_cache_set2(struct uwsgi_cache *, char *, uint16_t, char *, uint64_t, uint64_t, uint64_t); int uwsgi_cache_del2(struct uwsgi_cache *, char *, uint16_t, uint64_t, uint16_t); char *uwsgi_cache_get2(struct uwsgi_cache *, char *, uint16_t, uint64_t *); char *uwsgi_cache_get3(struct uwsgi_cache *, char *, uint16_t, uint64_t *, uint64_t *); char *uwsgi_cache_get4(struct uwsgi_cache *, char *, uint16_t, uint64_t *, uint64_t *); uint32_t uwsgi_cache_exists2(struct uwsgi_cache *, char *, uint16_t); struct uwsgi_cache *uwsgi_cache_create(char *); struct uwsgi_cache *uwsgi_cache_by_name(char *); struct uwsgi_cache *uwsgi_cache_by_namelen(char *, uint16_t); void uwsgi_cache_create_all(void); void uwsgi_cache_sync_from_nodes(struct uwsgi_cache *); void uwsgi_cache_setup_nodes(struct uwsgi_cache *); int64_t uwsgi_cache_num2(struct uwsgi_cache *, char *, uint16_t); void uwsgi_cache_sync_all(void); void uwsgi_cache_start_sweepers(void); void uwsgi_cache_start_sync_servers(void); void *uwsgi_malloc(size_t); void *uwsgi_calloc(size_t); int event_queue_init(void); void *event_queue_alloc(int); int event_queue_add_fd_read(int, int); int event_queue_add_fd_write(int, int); int event_queue_del_fd(int, int, int); int event_queue_wait(int, int, int *); int event_queue_wait_multi(int, int, void *, int); int event_queue_interesting_fd(void *, int); int event_queue_interesting_fd_has_error(void *, int); int event_queue_fd_write_to_read(int, int); int event_queue_fd_read_to_write(int, int); int event_queue_fd_readwrite_to_read(int, int); int event_queue_fd_readwrite_to_write(int, int); int event_queue_fd_read_to_readwrite(int, int); int event_queue_fd_write_to_readwrite(int, int); int event_queue_interesting_fd_is_read(void *, int); int event_queue_interesting_fd_is_write(void *, int); int event_queue_add_timer(int, int *, int); struct uwsgi_timer *event_queue_ack_timer(int); int event_queue_add_file_monitor(int, char *, int *); struct uwsgi_fmon *event_queue_ack_file_monitor(int, int); int uwsgi_register_signal(uint8_t, char *, void *, uint8_t); int uwsgi_add_file_monitor(uint8_t, char *); int uwsgi_add_timer(uint8_t, int); int uwsgi_signal_add_rb_timer(uint8_t, int, int); int uwsgi_signal_handler(uint8_t); void uwsgi_route_signal(uint8_t); int uwsgi_start(void *); int uwsgi_register_rpc(char *, struct uwsgi_plugin *, uint8_t, void *); uint64_t uwsgi_rpc(char *, uint8_t, char **, uint16_t *, char **); char *uwsgi_do_rpc(char *, char *, uint8_t, char **, uint16_t *, uint64_t *); void uwsgi_rpc_init(void); char *uwsgi_cheap_string(char *, int); int uwsgi_parse_array(char *, uint16_t, char **, uint16_t *, uint8_t *); struct uwsgi_gateway *register_gateway(char *, void (*)(int, void *), void *); void gateway_respawn(int); void uwsgi_gateway_go_cheap(char *, int, int *); char *uwsgi_open_and_read(char *, size_t *, int, char *[]); char *uwsgi_get_last_char(char *, char); char *uwsgi_get_last_charn(char *, size_t, char); void uwsgi_spawn_daemon(struct uwsgi_daemon *); void uwsgi_detach_daemons(); void emperor_loop(void); char *uwsgi_num2str(int); char *uwsgi_float2str(float); char *uwsgi_64bit2str(int64_t); char *uwsgi_size2str(size_t); char *magic_sub(char *, size_t, size_t *, char *[]); void init_magic_table(char *[]); char *uwsgi_req_append(struct wsgi_request *, char *, uint16_t, char *, uint16_t); int uwsgi_req_append_path_info_with_index(struct wsgi_request *, char *, uint16_t); int is_unix(char *, int); int is_a_number(char *); char *uwsgi_resolve_ip(char *); void uwsgi_init_queue(void); char *uwsgi_queue_get(uint64_t, uint64_t *); char *uwsgi_queue_pull(uint64_t *); int uwsgi_queue_push(char *, uint64_t); char *uwsgi_queue_pop(uint64_t *); int uwsgi_queue_set(uint64_t, char *, uint64_t); struct uwsgi_subscribe_req { char *key; uint16_t keylen; char *address; uint16_t address_len; char *auth; uint16_t auth_len; uint8_t modifier1; uint8_t modifier2; uint64_t cores; uint64_t load; uint64_t weight; char *sign; uint16_t sign_len; time_t unix_check; char *base; uint16_t base_len; char *sni_key; uint16_t sni_key_len; char *sni_crt; uint16_t sni_crt_len; char *sni_ca; uint16_t sni_ca_len; pid_t pid; uid_t uid; gid_t gid; char *notify; uint16_t notify_len; }; void uwsgi_nuclear_blast(); void uwsgi_unix_signal(int, void (*)(int)); char *uwsgi_get_exported_opt(char *); char *uwsgi_manage_placeholder(char *); int uwsgi_signal_add_cron(uint8_t, int, int, int, int, int); int uwsgi_cron_task_needs_execution(struct tm *, int, int, int, int, int); char *uwsgi_get_optname_by_index(int); int uwsgi_list_has_num(char *, int); int uwsgi_list_has_str(char *, char *); void uwsgi_cache_fix(struct uwsgi_cache *); struct uwsgi_async_request { struct wsgi_request *wsgi_req; struct uwsgi_async_request *prev; struct uwsgi_async_request *next; }; int event_queue_read(void); int event_queue_write(void); void uwsgi_help(char *, char *, void *); void uwsgi_print_sym(char *, char *, void *); int uwsgi_str2_num(char *); int uwsgi_str3_num(char *); int uwsgi_str4_num(char *); #ifdef __linux__ #if !defined(__ia64__) void linux_namespace_start(void *); void linux_namespace_jail(void); #endif void uwsgi_master_manage_setns(int); void uwsgi_setns(char *); void uwsgi_setns_preopen(void); #endif int uwsgi_amqp_consume_queue(int, char *, char *, char *, char *, char *, char *); char *uwsgi_amqp_consume(int, uint64_t *, char **); int uwsgi_file_serve(struct wsgi_request *, char *, uint16_t, char *, uint16_t, int); int uwsgi_starts_with(char *, int, char *, int); int uwsgi_static_want_gzip(struct wsgi_request *, char *, size_t *, struct stat *); #ifdef __sun__ time_t timegm(struct tm *); #endif uint64_t uwsgi_str_num(char *, int); size_t uwsgi_str_occurence(char *, size_t, char); int uwsgi_proto_base_write(struct wsgi_request *, char *, size_t); int uwsgi_proto_base_writev(struct wsgi_request *, struct iovec *, size_t *); #ifdef UWSGI_SSL int uwsgi_proto_ssl_write(struct wsgi_request *, char *, size_t); #endif int uwsgi_proto_base_write_header(struct wsgi_request *, char *, size_t); ssize_t uwsgi_proto_base_read_body(struct wsgi_request *, char *, size_t); ssize_t uwsgi_proto_noop_read_body(struct wsgi_request *, char *, size_t); #ifdef UWSGI_SSL ssize_t uwsgi_proto_ssl_read_body(struct wsgi_request *, char *, size_t); #endif int uwsgi_proto_base_accept(struct wsgi_request *, int); void uwsgi_proto_base_close(struct wsgi_request *); #ifdef UWSGI_SSL int uwsgi_proto_ssl_accept(struct wsgi_request *, int); void uwsgi_proto_ssl_close(struct wsgi_request *); #endif uint16_t proto_base_add_uwsgi_header(struct wsgi_request *, char *, uint16_t, char *, uint16_t); uint16_t proto_base_add_uwsgi_var(struct wsgi_request *, char *, uint16_t, char *, uint16_t); // protocols void uwsgi_proto_uwsgi_setup(struct uwsgi_socket *); void uwsgi_proto_puwsgi_setup(struct uwsgi_socket *); void uwsgi_proto_raw_setup(struct uwsgi_socket *); void uwsgi_proto_http_setup(struct uwsgi_socket *); void uwsgi_proto_http11_setup(struct uwsgi_socket *); #ifdef UWSGI_SSL void uwsgi_proto_https_setup(struct uwsgi_socket *); void uwsgi_proto_suwsgi_setup(struct uwsgi_socket *); #endif #ifdef UWSGI_ZEROMQ void uwsgi_proto_zmq_setup(struct uwsgi_socket *); #endif void uwsgi_proto_fastcgi_setup(struct uwsgi_socket *); void uwsgi_proto_fastcgi_nph_setup(struct uwsgi_socket *); void uwsgi_proto_scgi_setup(struct uwsgi_socket *); void uwsgi_proto_scgi_nph_setup(struct uwsgi_socket *); int uwsgi_num2str2(int, char *); void uwsgi_add_socket_from_fd(struct uwsgi_socket *, int); char *uwsgi_split3(char *, size_t, char, char **, size_t *, char **, size_t *, char **, size_t *); char *uwsgi_split4(char *, size_t, char, char **, size_t *, char **, size_t *, char **, size_t *, char **, size_t *); char *uwsgi_netstring(char *, size_t, char **, size_t *); char *uwsgi_str_split_nget(char *, size_t, char, size_t, size_t *); int uwsgi_get_socket_num(struct uwsgi_socket *); struct uwsgi_socket *uwsgi_new_socket(char *); struct uwsgi_socket *uwsgi_new_shared_socket(char *); struct uwsgi_socket *uwsgi_del_socket(struct uwsgi_socket *); void uwsgi_close_all_sockets(void); void uwsgi_shutdown_all_sockets(void); void uwsgi_close_all_unshared_sockets(void); struct uwsgi_string_list *uwsgi_string_new_list(struct uwsgi_string_list **, char *); #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) struct uwsgi_regexp_list *uwsgi_regexp_custom_new_list(struct uwsgi_regexp_list **, char *, char *); #define uwsgi_regexp_new_list(x, y) uwsgi_regexp_custom_new_list(x, y, NULL); #endif void uwsgi_string_del_list(struct uwsgi_string_list **, struct uwsgi_string_list *); void uwsgi_init_all_apps(void); void uwsgi_init_worker_mount_apps(void); void uwsgi_socket_nb(int); void uwsgi_socket_b(int); int uwsgi_write_nb(int, char *, size_t, int); int uwsgi_read_nb(int, char *, size_t, int); ssize_t uwsgi_read_true_nb(int, char *, size_t, int); int uwsgi_read_whole_true_nb(int, char *, size_t, int); int uwsgi_read_uh(int fd, struct uwsgi_header *, int); int uwsgi_proxy_nb(struct wsgi_request *, char *, struct uwsgi_buffer *, size_t, int); int uwsgi_read_with_realloc(int, char **, size_t *, int, uint8_t *, uint8_t *); int uwsgi_write_true_nb(int, char *, size_t, int); void uwsgi_destroy_request(struct wsgi_request *); void uwsgi_systemd_init(char *); void uwsgi_sig_pause(void); void uwsgi_ignition(void); int uwsgi_respawn_worker(int); socklen_t socket_to_in_addr(char *, char *, int, struct sockaddr_in *); socklen_t socket_to_un_addr(char *, struct sockaddr_un *); socklen_t socket_to_in_addr6(char *, char *, int, struct sockaddr_in6 *); int uwsgi_get_shared_socket_fd_by_num(int); struct uwsgi_socket *uwsgi_get_shared_socket_by_num(int); struct uwsgi_socket *uwsgi_get_socket_by_num(int); int uwsgi_get_shared_socket_num(struct uwsgi_socket *); #ifdef __linux__ void uwsgi_set_cgroup(void); long uwsgi_num_from_file(char *, int); #endif void uwsgi_add_sockets_to_queue(int, int); void uwsgi_del_sockets_from_queue(int); int uwsgi_run_command_and_wait(char *, char *); int uwsgi_run_command_putenv_and_wait(char *, char *, char **, unsigned int); int uwsgi_call_symbol(char *); void uwsgi_manage_signal_cron(time_t); pid_t uwsgi_run_command(char *, int *, int); void uwsgi_manage_command_cron(time_t); int *uwsgi_attach_fd(int, int *, char *, size_t); int uwsgi_count_sockets(struct uwsgi_socket *); int uwsgi_file_exists(char *); int uwsgi_signal_registered(uint8_t); int uwsgi_endswith(char *, char *); void uwsgi_chown(char *, char *); char *uwsgi_get_binary_path(char *); char *uwsgi_lower(char *, size_t); int uwsgi_num2str2n(int, char *, int); void create_logpipe(void); char *uwsgi_str_contains(char *, int, char); int uwsgi_simple_parse_vars(struct wsgi_request *, char *, char *); void uwsgi_build_mime_dict(char *); struct uwsgi_dyn_dict *uwsgi_dyn_dict_new(struct uwsgi_dyn_dict **, char *, int, char *, int); void uwsgi_dyn_dict_del(struct uwsgi_dyn_dict *); void uwsgi_apply_config_pass(char symbol, char *(*)(char *)); void uwsgi_mule(int); char *uwsgi_string_get_list(struct uwsgi_string_list **, int, size_t *); void uwsgi_fixup_fds(int, int, struct uwsgi_gateway *); void uwsgi_set_processname(char *); void http_url_decode(char *, uint16_t *, char *); void http_url_encode(char *, uint16_t *, char *); pid_t uwsgi_fork(char *); struct uwsgi_mule *get_mule_by_id(int); struct uwsgi_mule_farm *uwsgi_mule_farm_new(struct uwsgi_mule_farm **, struct uwsgi_mule *); int uwsgi_farm_has_mule(struct uwsgi_farm *, int); struct uwsgi_farm *get_farm_by_name(char *); struct uwsgi_subscribe_node { char name[0xff]; uint16_t len; uint8_t modifier1; uint8_t modifier2; time_t last_check; // absolute number of requests uint64_t requests; // number of requests since last subscription ping uint64_t last_requests; uint64_t tx; uint64_t rx; int death_mark; uint64_t reference; uint64_t cores; uint64_t load; uint64_t failcnt; uint64_t weight; uint64_t wrr; time_t unix_check; // used by unix credentials pid_t pid; uid_t uid; gid_t gid; char notify[102]; struct uwsgi_subscribe_slot *slot; struct uwsgi_subscribe_node *next; }; struct uwsgi_subscribe_slot { char key[0xff]; uint16_t keylen; uint32_t hash; uint64_t hits; struct uwsgi_subscribe_node *nodes; struct uwsgi_subscribe_slot *prev; struct uwsgi_subscribe_slot *next; #ifdef UWSGI_SSL EVP_PKEY *sign_public_key; EVP_MD_CTX *sign_ctx; uint8_t sni_enabled; #endif }; int mule_send_msg(int, char *, size_t); uint32_t djb33x_hash(char *, uint64_t); void create_signal_pipe(int *); void create_msg_pipe(int *, int); struct uwsgi_subscribe_slot *uwsgi_get_subscribe_slot(struct uwsgi_subscribe_slot **, char *, uint16_t); struct uwsgi_subscribe_node *uwsgi_get_subscribe_node_by_name(struct uwsgi_subscribe_slot **, char *, uint16_t, char *, uint16_t); struct uwsgi_subscribe_node *uwsgi_get_subscribe_node(struct uwsgi_subscribe_slot **, char *, uint16_t); int uwsgi_remove_subscribe_node(struct uwsgi_subscribe_slot **, struct uwsgi_subscribe_node *); struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slot **, struct uwsgi_subscribe_req *); ssize_t uwsgi_mule_get_msg(int, int, char *, size_t, int); int uwsgi_signal_wait(int); struct uwsgi_app *uwsgi_add_app(int, uint8_t, char *, int, void *, void *); int uwsgi_signal_send(int, uint8_t); int uwsgi_remote_signal_send(char *, uint8_t); void uwsgi_configure(); int uwsgi_read_response(int, struct uwsgi_header *, int, char **); char *uwsgi_simple_file_read(char *); void uwsgi_send_subscription(char *, char *, size_t, uint8_t, uint8_t, uint8_t, char *, char *, char *, char *, char *); void uwsgi_send_subscription_from_fd(int, char *, char *, size_t, uint8_t, uint8_t, uint8_t, char *, char *, char *, char *, char *); void uwsgi_subscribe(char *, uint8_t); void uwsgi_subscribe2(char *, uint8_t); int uwsgi_is_bad_connection(int); int uwsgi_long2str2n(unsigned long long, char *, int); #ifdef __linux__ void uwsgi_build_unshare(char *, int *); #ifdef MADV_MERGEABLE void uwsgi_linux_ksm_map(void); #endif #endif #ifdef UWSGI_CAP int uwsgi_build_cap(char *, cap_value_t **); void uwsgi_apply_cap(cap_value_t *, int); #endif void uwsgi_register_logger(char *, ssize_t(*func) (struct uwsgi_logger *, char *, size_t)); void uwsgi_append_logger(struct uwsgi_logger *); void uwsgi_append_req_logger(struct uwsgi_logger *); struct uwsgi_logger *uwsgi_get_logger(char *); struct uwsgi_logger *uwsgi_get_logger_from_id(char *); char *uwsgi_getsockname(int); char *uwsgi_get_var(struct wsgi_request *, char *, uint16_t, uint16_t *); struct uwsgi_gateway_socket *uwsgi_new_gateway_socket(char *, char *); struct uwsgi_gateway_socket *uwsgi_new_gateway_socket_from_fd(int, char *); void escape_shell_arg(char *, size_t, char *); void escape_json(char *, size_t, char *); void *uwsgi_malloc_shared(size_t); void *uwsgi_calloc_shared(size_t); struct uwsgi_spooler *uwsgi_new_spooler(char *); struct uwsgi_spooler *uwsgi_get_spooler_by_name(char *, size_t); int uwsgi_zerg_attach(char *); int uwsgi_manage_opt(char *, char *); void uwsgi_opt_print(char *, char *, void *); void uwsgi_opt_true(char *, char *, void *); void uwsgi_opt_false(char *, char *, void *); void uwsgi_opt_set_str(char *, char *, void *); void uwsgi_opt_custom(char *, char *, void *); void uwsgi_opt_set_null(char *, char *, void *); void uwsgi_opt_set_logger(char *, char *, void *); void uwsgi_opt_set_req_logger(char *, char *, void *); void uwsgi_opt_set_str_spaced(char *, char *, void *); void uwsgi_opt_add_string_list(char *, char *, void *); void uwsgi_opt_add_addr_list(char *, char *, void *); void uwsgi_opt_add_string_list_custom(char *, char *, void *); void uwsgi_opt_add_dyn_dict(char *, char *, void *); void uwsgi_opt_binary_append_data(char *, char *, void *); #if defined(UWSGI_PCRE) || defined(UWSGI_PCRE2) void uwsgi_opt_pcre_jit(char *, char *, void *); void uwsgi_opt_add_regexp_dyn_dict(char *, char *, void *); void uwsgi_opt_add_regexp_list(char *, char *, void *); void uwsgi_opt_add_regexp_custom_list(char *, char *, void *); #endif void uwsgi_opt_set_int(char *, char *, void *); void uwsgi_opt_uid(char *, char *, void *); void uwsgi_opt_gid(char *, char *, void *); void uwsgi_opt_set_rawint(char *, char *, void *); void uwsgi_opt_set_16bit(char *, char *, void *); void uwsgi_opt_set_64bit(char *, char *, void *); void uwsgi_opt_set_megabytes(char *, char *, void *); void uwsgi_opt_set_dyn(char *, char *, void *); void uwsgi_opt_set_placeholder(char *, char *, void *); void uwsgi_opt_add_shared_socket(char *, char *, void *); void uwsgi_opt_add_socket(char *, char *, void *); #ifdef UWSGI_SSL void uwsgi_opt_add_ssl_socket(char *, char *, void *); #endif void uwsgi_opt_add_socket_no_defer(char *, char *, void *); void uwsgi_opt_add_lazy_socket(char *, char *, void *); void uwsgi_opt_add_cron(char *, char *, void *); void uwsgi_opt_add_cron2(char *, char *, void *); void uwsgi_opt_add_unique_cron(char *, char *, void *); void uwsgi_opt_load_plugin(char *, char *, void *); void uwsgi_opt_load_dl(char *, char *, void *); void uwsgi_opt_load(char *, char *, void *); void uwsgi_opt_safe_fd(char *, char *, void *); #ifdef UWSGI_SSL void uwsgi_opt_add_legion_cron(char *, char *, void *); void uwsgi_opt_add_unique_legion_cron(char *, char *, void *); void uwsgi_opt_sni(char *, char *, void *); struct uwsgi_string_list *uwsgi_ssl_add_sni_item(char *, char *, char *, char *, char *); void uwsgi_ssl_del_sni_item(char *, uint16_t); char *uwsgi_write_pem_to_file(char *, char *, size_t, char *); #endif void uwsgi_opt_flock(char *, char *, void *); void uwsgi_opt_flock_wait(char *, char *, void *); void uwsgi_opt_load_ini(char *, char *, void *); #ifdef UWSGI_XML void uwsgi_opt_load_xml(char *, char *, void *); #endif #ifdef UWSGI_YAML void uwsgi_opt_load_yml(char *, char *, void *); #endif #ifdef UWSGI_JSON void uwsgi_opt_load_json(char *, char *, void *); #endif void uwsgi_opt_set_umask(char *, char *, void *); void uwsgi_opt_add_spooler(char *, char *, void *); void uwsgi_opt_add_daemon(char *, char *, void *); void uwsgi_opt_add_daemon2(char *, char *, void *); void uwsgi_opt_set_uid(char *, char *, void *); void uwsgi_opt_set_gid(char *, char *, void *); void uwsgi_opt_set_immediate_uid(char *, char *, void *); void uwsgi_opt_set_immediate_gid(char *, char *, void *); void uwsgi_opt_set_env(char *, char *, void *); void uwsgi_opt_unset_env(char *, char *, void *); void uwsgi_opt_pidfile_signal(char *, char *, void *); void uwsgi_opt_check_static(char *, char *, void *); void uwsgi_opt_fileserve_mode(char *, char *, void *); void uwsgi_opt_static_map(char *, char *, void *); void uwsgi_opt_add_mule(char *, char *, void *); void uwsgi_opt_add_mules(char *, char *, void *); void uwsgi_opt_add_farm(char *, char *, void *); void uwsgi_opt_signal(char *, char *, void *); void uwsgi_opt_snmp(char *, char *, void *); void uwsgi_opt_snmp_community(char *, char *, void *); void uwsgi_opt_logfile_chmod(char *, char *, void *); void uwsgi_opt_log_date(char *, char *, void *); void uwsgi_opt_chmod_socket(char *, char *, void *); void uwsgi_opt_max_vars(char *, char *, void *); void uwsgi_opt_deprecated(char *, char *, void *); void uwsgi_opt_noop(char *, char *, void *); void uwsgi_opt_logic(char *, char *, void *); int uwsgi_logic_opt_for(char *, char *); int uwsgi_logic_opt_for_glob(char *, char *); int uwsgi_logic_opt_for_times(char *, char *); int uwsgi_logic_opt_for_readline(char *, char *); int uwsgi_logic_opt_if_env(char *, char *); int uwsgi_logic_opt_if_not_env(char *, char *); int uwsgi_logic_opt_if_opt(char *, char *); int uwsgi_logic_opt_if_not_opt(char *, char *); int uwsgi_logic_opt_if_exists(char *, char *); int uwsgi_logic_opt_if_not_exists(char *, char *); int uwsgi_logic_opt_if_file(char *, char *); int uwsgi_logic_opt_if_not_file(char *, char *); int uwsgi_logic_opt_if_dir(char *, char *); int uwsgi_logic_opt_if_not_dir(char *, char *); int uwsgi_logic_opt_if_reload(char *, char *); int uwsgi_logic_opt_if_not_reload(char *, char *); int uwsgi_logic_opt_if_plugin(char *, char *); int uwsgi_logic_opt_if_not_plugin(char *, char *); int uwsgi_logic_opt_if_hostname(char *, char *); int uwsgi_logic_opt_if_not_hostname(char *, char *); int uwsgi_logic_opt_if_hostname_match(char *, char *); int uwsgi_logic_opt_if_not_hostname_match(char *, char *); void uwsgi_opt_resolve(char *, char *, void *); #ifdef UWSGI_CAP void uwsgi_opt_set_cap(char *, char *, void *); void uwsgi_opt_set_emperor_cap(char *, char *, void *); #endif #ifdef __linux__ void uwsgi_opt_set_unshare(char *, char *, void *); #endif int uwsgi_tmpfd(); FILE *uwsgi_tmpfile(); #ifdef UWSGI_ROUTING struct uwsgi_router *uwsgi_register_router(char *, int (*)(struct uwsgi_route *, char *)); void uwsgi_opt_add_route(char *, char *, void *); int uwsgi_apply_routes(struct wsgi_request *); void uwsgi_apply_final_routes(struct wsgi_request *); int uwsgi_apply_error_routes(struct wsgi_request *); int uwsgi_apply_response_routes(struct wsgi_request *); int uwsgi_apply_routes_do(struct uwsgi_route *, struct wsgi_request *, char *, uint16_t); void uwsgi_register_embedded_routers(void); void uwsgi_routing_dump(); struct uwsgi_buffer *uwsgi_routing_translate(struct wsgi_request *, struct uwsgi_route *, char *, uint16_t, char *, size_t); int uwsgi_route_api_func(struct wsgi_request *, char *, char *); struct uwsgi_route_condition *uwsgi_register_route_condition(char *, int (*) (struct wsgi_request *, struct uwsgi_route *)); void uwsgi_fixup_routes(struct uwsgi_route *); #endif void uwsgi_reload(char **); char *uwsgi_chomp(char *); char *uwsgi_chomp2(char *); int uwsgi_file_to_string_list(char *, struct uwsgi_string_list **); void uwsgi_backtrace(int); void uwsgi_check_logrotate(void); char *uwsgi_check_touches(struct uwsgi_string_list *); void uwsgi_manage_zerg(int, int, int *); time_t uwsgi_now(void); int uwsgi_calc_cheaper(void); int uwsgi_cheaper_algo_spare(int); int uwsgi_cheaper_algo_backlog(int); int uwsgi_cheaper_algo_backlog2(int); int uwsgi_cheaper_algo_manual(int); int uwsgi_master_log(void); int uwsgi_master_req_log(void); void uwsgi_flush_logs(void); void uwsgi_register_cheaper_algo(char *, int (*)(int)); void uwsgi_setup_locking(void); int uwsgi_fcntl_lock(int); int uwsgi_fcntl_is_locked(int); void uwsgi_emulate_cow_for_apps(int); char *uwsgi_read_fd(int, size_t *, int); void uwsgi_setup_post_buffering(void); struct uwsgi_lock_item *uwsgi_lock_ipcsem_init(char *); void uwsgi_write_pidfile(char *); void uwsgi_write_pidfile_explicit(char *, pid_t); int uwsgi_write_intfile(char *, int); void uwsgi_protected_close(int); ssize_t uwsgi_protected_read(int, void *, size_t); int uwsgi_socket_uniq(struct uwsgi_socket *, struct uwsgi_socket *); int uwsgi_socket_is_already_bound(char *name); char *uwsgi_expand_path(char *, int, char *); int uwsgi_try_autoload(char *); uint64_t uwsgi_micros(void); uint64_t uwsgi_millis(void); int uwsgi_is_file(char *); int uwsgi_is_file2(char *, struct stat *); int uwsgi_is_dir(char *); int uwsgi_is_link(char *); void uwsgi_receive_signal(int, char *, int); void uwsgi_exec_atexit(void); struct uwsgi_stats { char *base; off_t pos; size_t tabs; size_t chunk; size_t size; int minified; int dirty; }; struct uwsgi_stats_pusher_instance; struct uwsgi_stats_pusher { char *name; void (*func) (struct uwsgi_stats_pusher_instance *, time_t, char *, size_t); int raw; struct uwsgi_stats_pusher *next; }; struct uwsgi_stats_pusher_instance { struct uwsgi_stats_pusher *pusher; char *arg; void *data; int raw; int configured; int freq; time_t last_run; // retries int needs_retry; int retries; int max_retries; int retry_delay; time_t next_retry; struct uwsgi_stats_pusher_instance *next; }; struct uwsgi_thread; void uwsgi_stats_pusher_loop(struct uwsgi_thread *); void uwsgi_stats_pusher_setup(void); void uwsgi_send_stats(int, struct uwsgi_stats *(*func) (void)); struct uwsgi_stats *uwsgi_master_generate_stats(void); struct uwsgi_stats_pusher * uwsgi_register_stats_pusher(char *, void (*)(struct uwsgi_stats_pusher_instance *, time_t, char *, size_t)); struct uwsgi_stats *uwsgi_stats_new(size_t); int uwsgi_stats_symbol(struct uwsgi_stats *, char); int uwsgi_stats_comma(struct uwsgi_stats *); int uwsgi_stats_object_open(struct uwsgi_stats *); int uwsgi_stats_object_close(struct uwsgi_stats *); int uwsgi_stats_list_open(struct uwsgi_stats *); int uwsgi_stats_list_close(struct uwsgi_stats *); int uwsgi_stats_keyval(struct uwsgi_stats *, char *, char *); int uwsgi_stats_keyval_comma(struct uwsgi_stats *, char *, char *); int uwsgi_stats_keyvalnum(struct uwsgi_stats *, char *, char *, unsigned long long); int uwsgi_stats_keyvalnum_comma(struct uwsgi_stats *, char *, char *, unsigned long long); int uwsgi_stats_keyvaln(struct uwsgi_stats *, char *, char *, int); int uwsgi_stats_keyvaln_comma(struct uwsgi_stats *, char *, char *, int); int uwsgi_stats_key(struct uwsgi_stats *, char *); int uwsgi_stats_keylong(struct uwsgi_stats *, char *, unsigned long long); int uwsgi_stats_keylong_comma(struct uwsgi_stats *, char *, unsigned long long); int uwsgi_stats_keyslong(struct uwsgi_stats *, char *, long long); int uwsgi_stats_keyslong_comma(struct uwsgi_stats *, char *, long long); int uwsgi_stats_str(struct uwsgi_stats *, char *); char *uwsgi_substitute(char *, char *, char *); void uwsgi_opt_add_custom_option(char *, char *, void *); void uwsgi_opt_cflags(char *, char *, void *); void uwsgi_opt_build_plugin(char *, char *, void *); void uwsgi_opt_dot_h(char *, char *, void *); void uwsgi_opt_config_py(char *, char *, void *); void uwsgi_opt_connect_and_read(char *, char *, void *); void uwsgi_opt_extract(char *, char *, void *); char *uwsgi_get_dot_h(); char *uwsgi_get_config_py(); char *uwsgi_get_cflags(); struct uwsgi_string_list *uwsgi_string_list_has_item(struct uwsgi_string_list *, char *, size_t); void trigger_harakiri(int); void uwsgi_setup_systemd(); void uwsgi_setup_upstart(); void uwsgi_setup_zerg(); void uwsgi_setup_inherited_sockets(); void uwsgi_setup_emperor(); #ifdef UWSGI_SSL void uwsgi_ssl_init(void); SSL_CTX *uwsgi_ssl_new_server_context(char *, char *, char *, char *, char *); char *uwsgi_rsa_sign(char *, char *, size_t, unsigned int *); char *uwsgi_sanitize_cert_filename(char *, char *, uint16_t); void uwsgi_opt_scd(char *, char *, void *); int uwsgi_subscription_sign_check(struct uwsgi_subscribe_slot *, struct uwsgi_subscribe_req *); char *uwsgi_sha1(char *, size_t, char *); char *uwsgi_sha1_2n(char *, size_t, char *, size_t, char *); char *uwsgi_md5(char *, size_t, char *); #endif void uwsgi_opt_ssa(char *, char *, void *); int uwsgi_no_subscriptions(struct uwsgi_subscribe_slot **); void uwsgi_deadlock_check(pid_t); struct uwsgi_logchunk { char *name; char *ptr; size_t len; int vec; long pos; long pos_len; int type; int free; ssize_t(*func) (struct wsgi_request *, char **); struct uwsgi_logchunk *next; }; void uwsgi_build_log_format(char *); void uwsgi_add_logchunk(int, int, char *, size_t); struct uwsgi_logchunk *uwsgi_register_logchunk(char *, ssize_t (*)(struct wsgi_request *, char **), int); void uwsgi_logit_simple(struct wsgi_request *); void uwsgi_logit_lf(struct wsgi_request *); void uwsgi_logit_lf_strftime(struct wsgi_request *); struct uwsgi_logvar *uwsgi_logvar_get(struct wsgi_request *, char *, uint8_t); void uwsgi_logvar_add(struct wsgi_request *, char *, uint8_t, char *, uint8_t); // scanners are instances of 'imperial_monitor' struct uwsgi_emperor_scanner { char *arg; int fd; void *data; void (*event_func) (struct uwsgi_emperor_scanner *); struct uwsgi_imperial_monitor *monitor; struct uwsgi_emperor_scanner *next; }; void uwsgi_register_imperial_monitor(char *, void (*)(struct uwsgi_emperor_scanner *), void (*)(struct uwsgi_emperor_scanner *)); int uwsgi_emperor_is_valid(char *); // an instance (called vassal) is a uWSGI stack running // it is identified by the name of its config file // a vassal is 'loyal' as soon as it manages a request struct uwsgi_instance { struct uwsgi_instance *ui_prev; struct uwsgi_instance *ui_next; char name[0xff]; pid_t pid; int status; time_t born; time_t last_mod; time_t last_loyal; time_t last_accepting; time_t last_ready; time_t last_run; time_t first_run; time_t last_heartbeat; uint64_t respawns; int use_config; int pipe[2]; int pipe_config[2]; char *config; uint32_t config_len; int loyal; int zerg; int ready; int accepting; struct uwsgi_emperor_scanner *scanner; uid_t uid; gid_t gid; int on_demand_fd; char *socket_name; time_t cursed_at; }; struct uwsgi_instance *emperor_get_by_fd(int); struct uwsgi_instance *emperor_get(char *); void emperor_stop(struct uwsgi_instance *); void emperor_curse(struct uwsgi_instance *); void emperor_respawn(struct uwsgi_instance *, time_t); void emperor_add(struct uwsgi_emperor_scanner *, char *, time_t, char *, uint32_t, uid_t, gid_t, char *); void emperor_back_to_ondemand(struct uwsgi_instance *); void uwsgi_exec_command_with_args(char *); void uwsgi_imperial_monitor_glob_init(struct uwsgi_emperor_scanner *); void uwsgi_imperial_monitor_directory_init(struct uwsgi_emperor_scanner *); void uwsgi_imperial_monitor_directory(struct uwsgi_emperor_scanner *); void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *); void uwsgi_register_clock(struct uwsgi_clock *); void uwsgi_set_clock(char *name); void uwsgi_init_default(void); void uwsgi_setup_reload(void); void uwsgi_autoload_plugins_by_name(char *); void uwsgi_commandline_config(void); void uwsgi_setup_log(void); void uwsgi_setup_log_master(void); void uwsgi_setup_shared_sockets(void); void uwsgi_setup_mules_and_farms(void); void uwsgi_setup_workers(void); void uwsgi_map_sockets(void); void uwsgi_set_cpu_affinity(void); void uwsgi_emperor_start(void); void uwsgi_bind_sockets(void); void uwsgi_set_sockets_protocols(void); struct uwsgi_buffer *uwsgi_buffer_new(size_t); int uwsgi_buffer_append(struct uwsgi_buffer *, char *, size_t); int uwsgi_buffer_fix(struct uwsgi_buffer *, size_t); int uwsgi_buffer_ensure(struct uwsgi_buffer *, size_t); void uwsgi_buffer_destroy(struct uwsgi_buffer *); int uwsgi_buffer_u8(struct uwsgi_buffer *, uint8_t); int uwsgi_buffer_byte(struct uwsgi_buffer *, char); int uwsgi_buffer_u16le(struct uwsgi_buffer *, uint16_t); int uwsgi_buffer_u16be(struct uwsgi_buffer *, uint16_t); int uwsgi_buffer_u32be(struct uwsgi_buffer *, uint32_t); int uwsgi_buffer_u32le(struct uwsgi_buffer *, uint32_t); int uwsgi_buffer_u64le(struct uwsgi_buffer *, uint64_t); int uwsgi_buffer_f32be(struct uwsgi_buffer *, float); int uwsgi_buffer_u24be(struct uwsgi_buffer *, uint32_t); int uwsgi_buffer_u64be(struct uwsgi_buffer *, uint64_t); int uwsgi_buffer_f64be(struct uwsgi_buffer *, double); int uwsgi_buffer_num64(struct uwsgi_buffer *, int64_t); int uwsgi_buffer_append_keyval(struct uwsgi_buffer *, char *, uint16_t, char *, uint16_t); int uwsgi_buffer_append_keyval32(struct uwsgi_buffer *, char *, uint32_t, char *, uint32_t); int uwsgi_buffer_append_keynum(struct uwsgi_buffer *, char *, uint16_t, int64_t); int uwsgi_buffer_append_valnum(struct uwsgi_buffer *, int64_t); int uwsgi_buffer_append_ipv4(struct uwsgi_buffer *, void *); int uwsgi_buffer_append_keyipv4(struct uwsgi_buffer *, char *, uint16_t, void *); int uwsgi_buffer_decapitate(struct uwsgi_buffer *, size_t); int uwsgi_buffer_append_base64(struct uwsgi_buffer *, char *, size_t); int uwsgi_buffer_insert(struct uwsgi_buffer *, size_t, char *, size_t); int uwsgi_buffer_insert_chunked(struct uwsgi_buffer *, size_t, size_t); int uwsgi_buffer_append_chunked(struct uwsgi_buffer *, size_t); int uwsgi_buffer_append_json(struct uwsgi_buffer *, char *, size_t); int uwsgi_buffer_set_uh(struct uwsgi_buffer *, uint8_t, uint8_t); void uwsgi_buffer_map(struct uwsgi_buffer *, char *, size_t); struct uwsgi_buffer *uwsgi_buffer_from_file(char *); ssize_t uwsgi_buffer_write_simple(struct wsgi_request *, struct uwsgi_buffer *); struct uwsgi_buffer *uwsgi_to_http(struct wsgi_request *, char *, uint16_t, char *, uint16_t); struct uwsgi_buffer *uwsgi_to_http_dumb(struct wsgi_request *, char *, uint16_t, char *, uint16_t); ssize_t uwsgi_pipe(int, int, int); ssize_t uwsgi_pipe_sized(int, int, size_t, int); int uwsgi_buffer_send(struct uwsgi_buffer *, int); void uwsgi_master_cleanup_hooks(void); pid_t uwsgi_daemonize2(); void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *, char *, char *, time_t, uid_t, gid_t, char *); #if defined(__linux__) #define UWSGI_ELF char *uwsgi_elf_section(char *, char *, size_t *); #endif void uwsgi_alarm_log_check(char *, size_t); void uwsgi_alarm_run(struct uwsgi_alarm_instance *, char *, size_t); void uwsgi_register_alarm(char *, void (*)(struct uwsgi_alarm_instance *), void (*)(struct uwsgi_alarm_instance *, char *, size_t)); void uwsgi_register_embedded_alarms(); void uwsgi_alarms_init(); void uwsgi_alarm_trigger(char *, char *, size_t); struct uwsgi_thread { pthread_t tid; pthread_attr_t tattr; int pipe[2]; int queue; ssize_t rlen; void *data; char *buf; off_t pos; size_t len; uint64_t custom0; uint64_t custom1; uint64_t custom2; uint64_t custom3; // linked list for offloaded requests struct uwsgi_offload_request *offload_requests_head; struct uwsgi_offload_request *offload_requests_tail; void (*func) (struct uwsgi_thread *); }; struct uwsgi_thread *uwsgi_thread_new(void (*)(struct uwsgi_thread *)); struct uwsgi_thread *uwsgi_thread_new_with_data(void (*)(struct uwsgi_thread *), void *data); struct uwsgi_offload_request { // the request socket int s; // the peer int fd; int fd2; // if set the current request is expected to end leaving // the offload thread do its job uint8_t takeover; // internal state int status; // a filename, a socket... char *name; off_t pos; char *buf; off_t buf_pos; size_t to_write; size_t len; size_t written; // a uwsgi_buffer (will be destroyed at the end of the task) struct uwsgi_buffer *ubuf; struct uwsgi_offload_engine *engine; // this pipe is used for notifications int pipe[2]; struct uwsgi_offload_request *prev; struct uwsgi_offload_request *next; // added in 2.1 struct uwsgi_buffer *ubuf1; struct uwsgi_buffer *ubuf2; struct uwsgi_buffer *ubuf3; struct uwsgi_buffer *ubuf4; struct uwsgi_buffer *ubuf5; struct uwsgi_buffer *ubuf6; struct uwsgi_buffer *ubuf7; struct uwsgi_buffer *ubuf8; int64_t custom1; int64_t custom2; int64_t custom3; int64_t custom4; int64_t custom5; int64_t custom6; int64_t custom7; int64_t custom8; void *data; void (*free)(struct uwsgi_offload_request *); }; struct uwsgi_offload_engine { char *name; int (*prepare_func)(struct wsgi_request *, struct uwsgi_offload_request *); int (*event_func) (struct uwsgi_thread *, struct uwsgi_offload_request *, int); struct uwsgi_offload_engine *next; }; struct uwsgi_offload_engine *uwsgi_offload_engine_by_name(char *); struct uwsgi_offload_engine *uwsgi_offload_register_engine(char *, int (*)(struct wsgi_request *, struct uwsgi_offload_request *), int (*) (struct uwsgi_thread *, struct uwsgi_offload_request *, int)); void uwsgi_offload_setup(struct uwsgi_offload_engine *, struct uwsgi_offload_request *, struct wsgi_request *, uint8_t); int uwsgi_offload_run(struct wsgi_request *, struct uwsgi_offload_request *, int *); void uwsgi_offload_engines_register_all(void); struct uwsgi_thread *uwsgi_offload_thread_start(void); int uwsgi_offload_request_sendfile_do(struct wsgi_request *, int, size_t, size_t); int uwsgi_offload_request_net_do(struct wsgi_request *, char *, struct uwsgi_buffer *); int uwsgi_offload_request_memory_do(struct wsgi_request *, char *, size_t); int uwsgi_offload_request_pipe_do(struct wsgi_request *, int, size_t); int uwsgi_simple_sendfile(struct wsgi_request *, int, size_t, size_t); int uwsgi_simple_write(struct wsgi_request *, char *, size_t); void uwsgi_subscription_set_algo(char *); struct uwsgi_subscribe_slot **uwsgi_subscription_init_ht(void); int uwsgi_check_pidfile(char *); void uwsgi_daemons_spawn_all(); int uwsgi_daemon_check_pid_death(pid_t); int uwsgi_daemon_check_pid_reload(pid_t); void uwsgi_daemons_smart_check(); void uwsgi_setup_thread_req(long, struct wsgi_request *); void uwsgi_loop_cores_run(void *(*)(void *)); int uwsgi_kvlist_parse(char *, size_t, char, int, ...); int uwsgi_send_http_stats(int); ssize_t uwsgi_simple_request_read(struct wsgi_request *, char *, size_t); int uwsgi_plugin_modifier1(char *); void *cache_udp_server_loop(void *); int uwsgi_user_lock(int); int uwsgi_user_unlock(int); void simple_loop_run_int(int); char *uwsgi_strip(char *); #ifdef UWSGI_SSL void uwsgi_opt_legion(char *, char *, void *); void uwsgi_opt_legion_mcast(char *, char *, void *); struct uwsgi_legion *uwsgi_legion_register(char *, char *, char *, char *, char *); void uwsgi_opt_legion_node(char *, char *, void *); void uwsgi_legion_register_node(struct uwsgi_legion *, char *); void uwsgi_opt_legion_quorum(char *, char *, void *); void uwsgi_opt_legion_hook(char *, char *, void *); void uwsgi_legion_register_hook(struct uwsgi_legion *, char *, char *); void uwsgi_opt_legion_scroll(char *, char *, void *); void uwsgi_legion_add(struct uwsgi_legion *); void uwsgi_legion_announce_death(void); char *uwsgi_ssl_rand(size_t); void uwsgi_start_legions(void); int uwsgi_legion_announce(struct uwsgi_legion *); struct uwsgi_legion *uwsgi_legion_get_by_name(char *); struct uwsgi_legion_action *uwsgi_legion_action_get(char *); struct uwsgi_legion_action *uwsgi_legion_action_register(char *, int (*)(struct uwsgi_legion *, char *)); int uwsgi_legion_action_call(char *, struct uwsgi_legion *, struct uwsgi_string_list *); void uwsgi_legion_atexit(void); #endif struct uwsgi_option *uwsgi_opt_get(char *); int uwsgi_opt_exists(char *); int uwsgi_valid_fd(int); void uwsgi_close_all_fds(void); int check_hex(char *, int); void uwsgi_uuid(char *); int uwsgi_uuid_cmp(char *, char *); int uwsgi_legion_i_am_the_lord(char *); char *uwsgi_legion_lord_scroll(char *, uint16_t *); void uwsgi_additional_header_add(struct wsgi_request *, char *, uint16_t); void uwsgi_remove_header(struct wsgi_request *, char *, uint16_t); void uwsgi_proto_hooks_setup(void); char *uwsgi_base64_decode(char *, size_t, size_t *); char *uwsgi_base64_encode(char *, size_t, size_t *); void uwsgi_subscribe_all(uint8_t, int); #define uwsgi_unsubscribe_all() uwsgi_subscribe_all(1, 1) void uwsgi_websockets_init(void); int uwsgi_websocket_send(struct wsgi_request *, char *, size_t); int uwsgi_websocket_send_binary(struct wsgi_request *, char *, size_t); struct uwsgi_buffer *uwsgi_websocket_recv(struct wsgi_request *); struct uwsgi_buffer *uwsgi_websocket_recv_nb(struct wsgi_request *); char *uwsgi_chunked_read(struct wsgi_request *, size_t *, int, int); uint16_t uwsgi_be16(char *); uint32_t uwsgi_be32(char *); uint64_t uwsgi_be64(char *); int uwsgi_websocket_handshake(struct wsgi_request *, char *, uint16_t, char *, uint16_t, char *, uint16_t); int uwsgi_response_prepare_headers(struct wsgi_request *, char *, uint16_t); int uwsgi_response_prepare_headers_int(struct wsgi_request *, int); int uwsgi_response_add_header(struct wsgi_request *, char *, uint16_t, char *, uint16_t); int uwsgi_response_add_header_force(struct wsgi_request *, char *, uint16_t, char *, uint16_t); int uwsgi_response_commit_headers(struct wsgi_request *); int uwsgi_response_sendfile_do(struct wsgi_request *, int, size_t, size_t); int uwsgi_response_sendfile_do_can_close(struct wsgi_request *, int, size_t, size_t, int); struct uwsgi_buffer *uwsgi_proto_base_add_header(struct wsgi_request *, char *, uint16_t, char *, uint16_t); int uwsgi_simple_wait_write_hook(int, int); int uwsgi_simple_wait_read_hook(int, int); int uwsgi_simple_wait_read2_hook(int, int, int, int *); int uwsgi_simple_wait_milliseconds_hook(int); int uwsgi_response_write_headers_do(struct wsgi_request *); char *uwsgi_request_body_read(struct wsgi_request *, ssize_t , ssize_t *); char *uwsgi_request_body_readline(struct wsgi_request *, ssize_t, ssize_t *); void uwsgi_request_body_seek(struct wsgi_request *, off_t); struct uwsgi_buffer *uwsgi_proto_base_prepare_headers(struct wsgi_request *, char *, uint16_t); struct uwsgi_buffer *uwsgi_proto_base_cgi_prepare_headers(struct wsgi_request *, char *, uint16_t); int uwsgi_response_write_body_do(struct wsgi_request *, char *, size_t); int uwsgi_response_writev_body_do(struct wsgi_request *, struct iovec *, size_t); int uwsgi_proto_base_sendfile(struct wsgi_request *, int, size_t, size_t); #ifdef UWSGI_SSL int uwsgi_proto_ssl_sendfile(struct wsgi_request *, int, size_t, size_t); #endif ssize_t uwsgi_sendfile_do(int, int, size_t, size_t); int uwsgi_proto_base_fix_headers(struct wsgi_request *); int uwsgi_response_add_content_length(struct wsgi_request *, uint64_t); void uwsgi_fix_range_for_size(enum uwsgi_range*, int64_t*, int64_t*, int64_t); void uwsgi_request_fix_range_for_size(struct wsgi_request *, int64_t); int uwsgi_response_add_content_range(struct wsgi_request *, int64_t, int64_t, int64_t); int uwsgi_response_add_expires(struct wsgi_request *, uint64_t); int uwsgi_response_add_last_modified(struct wsgi_request *, uint64_t); int uwsgi_response_add_date(struct wsgi_request *, char *, uint16_t, uint64_t); const char *uwsgi_http_status_msg(char *, uint16_t *); int uwsgi_stats_dump_vars(struct uwsgi_stats *, struct uwsgi_core *); int uwsgi_stats_dump_request(struct uwsgi_stats *, struct uwsgi_core *); int uwsgi_contains_n(char *, size_t, char *, size_t); char *uwsgi_upload_progress_create(struct wsgi_request *, int *); int uwsgi_upload_progress_update(struct wsgi_request *, int, size_t); void uwsgi_upload_progress_destroy(char *, int); void uwsgi_time_bomb(int, int); void uwsgi_master_manage_emperor(void); void uwsgi_master_manage_udp(int); void uwsgi_threaded_logger_spawn(void); void uwsgi_master_check_idle(void); int uwsgi_master_check_workers_deadline(void); int uwsgi_master_check_gateways_deadline(void); int uwsgi_master_check_mules_deadline(void); int uwsgi_master_check_spoolers_deadline(void); int uwsgi_master_check_crons_deadline(void); int uwsgi_master_check_spoolers_death(int); int uwsgi_master_check_emperor_death(int); int uwsgi_master_check_mules_death(int); int uwsgi_master_check_gateways_death(int); int uwsgi_master_check_daemons_death(int); void uwsgi_master_check_death(void); int uwsgi_master_check_reload(char **); void uwsgi_master_commit_status(void); void uwsgi_master_check_chain(void); void uwsgi_master_fix_request_counters(void); int uwsgi_master_manage_events(int); void uwsgi_block_signal(int); void uwsgi_unblock_signal(int); int uwsgi_worker_is_busy(int); void uwsgi_post_accept(struct wsgi_request *); void uwsgi_tcp_nodelay(int); struct uwsgi_exception_handler_instance; struct uwsgi_exception_handler { char *name; int (*func)(struct uwsgi_exception_handler_instance *, char *, size_t); struct uwsgi_exception_handler *next; }; struct uwsgi_exception_handler_instance { struct uwsgi_exception_handler *handler; int configured; char *arg; uint32_t custom32; uint64_t custom64; void *custom_ptr; }; void uwsgi_exception_setup_handlers(void); struct uwsgi_exception_handler *uwsgi_exception_handler_by_name(char *); void uwsgi_manage_exception(struct wsgi_request *, int); int uwsgi_exceptions_catch(struct wsgi_request *); uint64_t uwsgi_worker_exceptions(int); struct uwsgi_exception_handler *uwsgi_register_exception_handler(char *, int (*)(struct uwsgi_exception_handler_instance *, char *, size_t)); char *proxy1_parse(char *ptr, char *watermark, char **src, uint16_t *src_len, char **dst, uint16_t *dst_len, char **src_port, uint16_t *src_port_len, char **dst_port, uint16_t *dst_port_len); void uwsgi_async_queue_is_full(time_t); char *uwsgi_get_header(struct wsgi_request *, char *, uint16_t, uint16_t *); void uwsgi_alarm_thread_start(void); void uwsgi_exceptions_handler_thread_start(void); #define uwsgi_response_add_connection_close(x) uwsgi_response_add_header(x, (char *)"Connection", 10, (char *)"close", 5) #define uwsgi_response_add_content_type(x, y, z) uwsgi_response_add_header(x, (char *)"Content-Type", 12, y, z) struct uwsgi_stats_pusher_instance *uwsgi_stats_pusher_add(struct uwsgi_stats_pusher *, char *); int plugin_already_loaded(const char *); struct uwsgi_plugin *uwsgi_plugin_get(const char *); struct uwsgi_cache_magic_context { char *cmd; uint16_t cmd_len; char *key; uint16_t key_len; uint64_t size; uint64_t expires; char *status; uint16_t status_len; char *cache; uint16_t cache_len; }; char *uwsgi_cache_magic_get(char *, uint16_t, uint64_t *, uint64_t *, char *); int uwsgi_cache_magic_set(char *, uint16_t, char *, uint64_t, uint64_t, uint64_t, char *); int uwsgi_cache_magic_del(char *, uint16_t, char *); int uwsgi_cache_magic_exists(char *, uint16_t, char *); int uwsgi_cache_magic_clear(char *); void uwsgi_cache_magic_context_hook(char *, uint16_t, char *, uint16_t, void *); char *uwsgi_legion_scrolls(char *, uint64_t *); int uwsgi_emperor_vassal_start(struct uwsgi_instance *); #ifdef UWSGI_ZLIB #include int uwsgi_deflate_init(z_stream *, char *, size_t); int uwsgi_inflate_init(z_stream *, char *, size_t); char *uwsgi_deflate(z_stream *, char *, size_t, size_t *); void uwsgi_crc32(uint32_t *, char *, size_t); struct uwsgi_buffer *uwsgi_gzip(char *, size_t); struct uwsgi_buffer *uwsgi_zlib_decompress(char *, size_t); int uwsgi_gzip_fix(z_stream *, uint32_t, struct uwsgi_buffer *, size_t); char *uwsgi_gzip_chunk(z_stream *, uint32_t *, char *, size_t, size_t *); int uwsgi_gzip_prepare(z_stream *, char *, size_t, uint32_t *); #endif char *uwsgi_get_cookie(struct wsgi_request *, char *, uint16_t, uint16_t *); char *uwsgi_get_qs(struct wsgi_request *, char *, uint16_t, uint16_t *); struct uwsgi_route_var *uwsgi_get_route_var(char *, uint16_t); struct uwsgi_route_var *uwsgi_register_route_var(char *, char *(*)(struct wsgi_request *, char *, uint16_t, uint16_t *)); char *uwsgi_get_mime_type(char *, int, size_t *); void config_magic_table_fill(char *, char *[]); int uwsgi_blob_to_response(struct wsgi_request *, char *, size_t); struct uwsgi_cron *uwsgi_cron_add(char *); int uwsgi_is_full_http(struct uwsgi_buffer *); int uwsgi_http_date(time_t t, char *); int uwsgi_apply_transformations(struct wsgi_request *wsgi_req, char *, size_t); int uwsgi_apply_final_transformations(struct wsgi_request *); void uwsgi_free_transformations(struct wsgi_request *); struct uwsgi_transformation *uwsgi_add_transformation(struct wsgi_request *wsgi_req, int (*func)(struct wsgi_request *, struct uwsgi_transformation *), void *); void uwsgi_file_write_do(struct uwsgi_string_list *); int uwsgi_fd_is_safe(int); void uwsgi_add_safe_fd(int); void uwsgi_ipcsem_clear(void); char *uwsgi_str_to_hex(char *, size_t); // this 3 functions have been added 1.9.10 to allow plugins take the control over processes void uwsgi_worker_run(void); void uwsgi_mule_run(void); void uwsgi_spooler_run(void); void uwsgi_takeover(void); char *uwsgi_binary_path(void); int uwsgi_is_again(); void uwsgi_disconnect(struct wsgi_request *); int uwsgi_ready_fd(struct wsgi_request *); void uwsgi_envdir(char *); void uwsgi_envdirs(struct uwsgi_string_list *); void uwsgi_opt_envdir(char *, char *, void *); void uwsgi_add_reload_fds(); void uwsgi_check_emperor(void); #ifdef UWSGI_AS_SHARED_LIBRARY int uwsgi_init(int, char **, char **); #endif int uwsgi_master_check_cron_death(int); struct uwsgi_fsmon *uwsgi_register_fsmon(char *, void (*)(struct uwsgi_fsmon *), void *data); int uwsgi_fsmon_event(int); void uwsgi_fsmon_setup(); void uwsgi_exit(int) __attribute__ ((__noreturn__)); void uwsgi_fallback_config(); struct uwsgi_cache_item *uwsgi_cache_keys(struct uwsgi_cache *, uint64_t *, struct uwsgi_cache_item **); void uwsgi_cache_rlock(struct uwsgi_cache *); void uwsgi_cache_rwunlock(struct uwsgi_cache *); char *uwsgi_cache_item_key(struct uwsgi_cache_item *); char *uwsgi_binsh(void); int uwsgi_file_executable(char *); int uwsgi_mount(char *, char *, char *, char *, char *); int uwsgi_umount(char *, char *); int uwsgi_mount_hook(char *); int uwsgi_umount_hook(char *); void uwsgi_hooks_run(struct uwsgi_string_list *, char *, int); void uwsgi_register_hook(char *, int (*)(char *)); struct uwsgi_hook *uwsgi_hook_by_name(char *); void uwsgi_register_base_hooks(void); void uwsgi_setup_log_encoders(void); void uwsgi_log_encoders_register_embedded(void); void uwsgi_register_log_encoder(char *, char *(*)(struct uwsgi_log_encoder *, char *, size_t, size_t *)); int uwsgi_accept(int); void suspend_resume_them_all(int); void uwsgi_master_fifo_prepare(); int uwsgi_master_fifo(); int uwsgi_master_fifo_manage(int); void uwsgi_log_do_rotate(char *, char *, off_t, int); void uwsgi_log_rotate(); void uwsgi_log_reopen(); void uwsgi_reload_workers(); void uwsgi_reload_mules(); void uwsgi_reload_spoolers(); void uwsgi_chain_reload(); void uwsgi_refork_master(); void uwsgi_update_pidfiles(); void gracefully_kill_them_all(int); void uwsgi_brutally_reload_workers(); void uwsgi_cheaper_increase(); void uwsgi_cheaper_decrease(); void uwsgi_go_cheap(); char **uwsgi_split_quoted(char *, size_t, char *, size_t *); void uwsgi_master_manage_emperor_proxy(); struct uwsgi_string_list *uwsgi_register_scheme(char *, char * (*)(char *, size_t *, int)); void uwsgi_setup_schemes(void); struct uwsgi_string_list *uwsgi_check_scheme(char *); void uwsgi_remap_fd(int, char *); void uwsgi_opt_exit(char *, char *, void *); int uwsgi_check_mountpoint(char *); void uwsgi_master_check_mountpoints(void); enum { UWSGI_METRIC_COUNTER, UWSGI_METRIC_GAUGE, UWSGI_METRIC_ABSOLUTE, UWSGI_METRIC_ALIAS, }; struct uwsgi_metric_child; struct uwsgi_metric_collector { char *name; int64_t (*func)(struct uwsgi_metric *); struct uwsgi_metric_collector *next; }; struct uwsgi_metric_threshold { int64_t value; uint8_t reset; int64_t reset_value; int32_t rate; char *alarm; char *msg; size_t msg_len; time_t last_alarm; struct uwsgi_metric_threshold *next; }; struct uwsgi_metric { char *name; char *oid; size_t name_len; size_t oid_len; // pre-computed snmp representation char *asn; size_t asn_len; // ABSOLUTE/COUNTER/GAUGE uint8_t type; // this could be taken from a file storage and must be always added to value by the collector (default 0) int64_t initial_value; // the value of the metric (point to a shared memory area) int64_t *value; // a custom blob you can attach to a metric void *custom; // the collection frequency uint32_t freq; time_t last_update; // run this function to collect the value struct uwsgi_metric_collector *collector; // take the value from this pointer to a 64bit value int64_t *ptr; // get the initial value from this file, and store each update in it char *filename; // pointer to memory mapped storage char *map; // arguments for collectors char *arg1; char *arg2; char *arg3; int64_t arg1n; int64_t arg2n; int64_t arg3n; struct uwsgi_metric_child *children; struct uwsgi_metric_threshold *thresholds; struct uwsgi_metric *next; // allow to reset metrics after each push uint8_t reset_after_push; }; struct uwsgi_metric_child { struct uwsgi_metric *um; struct uwsgi_metric_child *next; }; void uwsgi_setup_metrics(void); void uwsgi_metrics_start_collector(void); int uwsgi_metric_set(char *, char *, int64_t); int uwsgi_metric_inc(char *, char *, int64_t); int uwsgi_metric_dec(char *, char *, int64_t); int uwsgi_metric_mul(char *, char *, int64_t); int uwsgi_metric_div(char *, char *, int64_t); int64_t uwsgi_metric_get(char *, char *); int64_t uwsgi_metric_getn(char *, size_t, char *, size_t); int uwsgi_metric_set_max(char *, char *, int64_t); int uwsgi_metric_set_min(char *, char *, int64_t); struct uwsgi_metric_collector *uwsgi_register_metric_collector(char *, int64_t (*)(struct uwsgi_metric *)); struct uwsgi_metric *uwsgi_register_metric(char *, char *, uint8_t, char *, void *, uint32_t, void *); void uwsgi_metrics_collectors_setup(void); struct uwsgi_metric *uwsgi_metric_find_by_name(char *); struct uwsgi_metric *uwsgi_metric_find_by_namen(char *, size_t); struct uwsgi_metric_child *uwsgi_metric_add_child(struct uwsgi_metric *, struct uwsgi_metric *); struct uwsgi_metric *uwsgi_metric_find_by_oid(char *); struct uwsgi_metric *uwsgi_metric_find_by_oidn(char *, size_t); struct uwsgi_metric *uwsgi_metric_find_by_asn(char *, size_t); int uwsgi_base128(struct uwsgi_buffer *, uint64_t, int); struct wsgi_request *find_wsgi_req_proto_by_fd(int); struct uwsgi_protocol *uwsgi_register_protocol(char *, void (*)(struct uwsgi_socket *)); void uwsgi_protocols_register(void); void uwsgi_build_plugin(char *dir); void uwsgi_sharedareas_init(); struct uwsgi_sharedarea *uwsgi_sharedarea_init(int); struct uwsgi_sharedarea *uwsgi_sharedarea_init_ptr(char *, uint64_t); struct uwsgi_sharedarea *uwsgi_sharedarea_init_fd(int, uint64_t, off_t); int64_t uwsgi_sharedarea_read(int, uint64_t, char *, uint64_t); int uwsgi_sharedarea_write(int, uint64_t, char *, uint64_t); int uwsgi_sharedarea_read64(int, uint64_t, int64_t *); int uwsgi_sharedarea_write64(int, uint64_t, int64_t *); int uwsgi_sharedarea_read8(int, uint64_t, int8_t *); int uwsgi_sharedarea_write8(int, uint64_t, int8_t *); int uwsgi_sharedarea_read16(int, uint64_t, int16_t *); int uwsgi_sharedarea_write16(int, uint64_t, int16_t *); int uwsgi_sharedarea_read32(int, uint64_t, int32_t *); int uwsgi_sharedarea_write32(int, uint64_t, int32_t *); int uwsgi_sharedarea_inc8(int, uint64_t, int8_t); int uwsgi_sharedarea_inc16(int, uint64_t, int16_t); int uwsgi_sharedarea_inc32(int, uint64_t, int32_t); int uwsgi_sharedarea_inc64(int, uint64_t, int64_t); int uwsgi_sharedarea_dec8(int, uint64_t, int8_t); int uwsgi_sharedarea_dec16(int, uint64_t, int16_t); int uwsgi_sharedarea_dec32(int, uint64_t, int32_t); int uwsgi_sharedarea_dec64(int, uint64_t, int64_t); int uwsgi_sharedarea_wait(int, int, int); int uwsgi_sharedarea_unlock(int); int uwsgi_sharedarea_rlock(int); int uwsgi_sharedarea_wlock(int); int uwsgi_sharedarea_update(int); struct uwsgi_sharedarea *uwsgi_sharedarea_get_by_id(int, uint64_t); int uwsgi_websocket_send_from_sharedarea(struct wsgi_request *, int, uint64_t, uint64_t); int uwsgi_websocket_send_binary_from_sharedarea(struct wsgi_request *, int, uint64_t, uint64_t); void uwsgi_register_logchunks(void); void uwsgi_setup(int, char **, char **); int uwsgi_run(void); int uwsgi_is_connected(int); int uwsgi_pass_cred(int, char *, size_t); int uwsgi_pass_cred2(int, char *, size_t, struct sockaddr *, size_t); int uwsgi_recv_cred(int, char *, size_t, pid_t *, uid_t *, gid_t *); ssize_t uwsgi_recv_cred2(int, char *, size_t, pid_t *, uid_t *, gid_t *); int uwsgi_socket_passcred(int); void uwsgi_dump_worker(int, char *); mode_t uwsgi_mode_t(char *, int *); int uwsgi_notify_socket_manage(int); int uwsgi_notify_msg(char *, char *, size_t); void vassal_sos(); int uwsgi_wait_for_fs(char *, int); int uwsgi_wait_for_mountpoint(char *); int uwsgi_wait_for_socket(char *); #ifdef __cplusplus } #endif uwsgi-2.0.29/uwsgi_main.c000066400000000000000000000002061477626554400152720ustar00rootroot00000000000000int uwsgi_init(int, char **, char **); int main(int argc, char *argv[], char **environ) { return uwsgi_init(argc, argv, environ); } uwsgi-2.0.29/uwsgiconfig.py000066400000000000000000001722601477626554400156740ustar00rootroot00000000000000# uWSGI build system uwsgi_version = '2.0.29' import os import re import time uwsgi_os = os.uname()[0] uwsgi_os_k = re.split('[-+_]', os.uname()[2])[0] uwsgi_os_v = os.uname()[3] uwsgi_cpu = os.uname()[4] import sys import subprocess import sysconfig from threading import Thread, Lock from optparse import OptionParser try: from queue import Queue except ImportError: from Queue import Queue try: import ConfigParser except ImportError: import configparser as ConfigParser try: from shlex import quote except ImportError: from pipes import quote PY3 = sys.version_info[0] == 3 if uwsgi_os == 'Darwin': GCC = os.environ.get('CC', 'clang') else: GCC = os.environ.get('CC', sysconfig.get_config_var('CC')) if not GCC: GCC = 'gcc' def get_preprocessor(): if 'clang' in GCC: return 'clang -xc core/clang_fake.c' return 'cpp' CPP = os.environ.get('CPP', get_preprocessor()) try: CPUCOUNT = int(os.environ.get('CPUCOUNT', -1)) except: CPUCOUNT = -1 if CPUCOUNT < 1: try: import multiprocessing CPUCOUNT = multiprocessing.cpu_count() except: try: CPUCOUNT = int(os.sysconf('SC_NPROCESSORS_ONLN')) except: CPUCOUNT = 1 # force single cpu in cygwin mode if uwsgi_os.startswith('CYGWIN'): CPUCOUNT=1 binary_list = [] started_at = time.time() # this is used for reporting (at the end of the build) # the server configuration report = { 'kernel': False, 'execinfo': False, 'ifaddrs': False, 'locking': False, 'event': False, 'timer': False, 'filemonitor': False, 'pcre': False, 'routing': False, 'capabilities': False, 'yaml': False, 'json': False, 'ssl': False, 'xml': False, 'debug': False, 'plugin_dir': False, 'zlib': False, 'ucontext': False, } verbose_build = False def print_compilation_output(default_str, verbose_str): if verbose_build: print(verbose_str) elif default_str is not None: print(default_str) compile_queue = None print_lock = None thread_compilers = [] def thread_compiler(num): while True: (objfile, cmdline) = compile_queue.get() if objfile: print_lock.acquire() print_compilation_output("[thread %d][%s] %s" % (num, GCC, objfile), "[thread %d] %s" % (num, cmdline)) print_lock.release() ret = subprocess.call(cmdline, shell=True) if ret != 0: os._exit(1) elif cmdline: print_lock.acquire() print(cmdline) print_lock.release() else: return def binarize(name): return name.replace('/', '_').replace('.','_').replace('-','_') def spcall(cmd): p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,stderr=open('uwsgibuild.log','w')) if p.wait() == 0: if sys.version_info[0] > 2: return p.stdout.read().rstrip().decode() return p.stdout.read().rstrip() else: return None # commodity function to remove -W* duplicates def uniq_warnings(elements): new_elements = [] for element in elements: if element.startswith('-W'): if not element in new_elements: new_elements.append(element) else: new_elements.append(element) return new_elements if uwsgi_version.endswith('-dev') and os.path.exists('%s/.git' % os.path.dirname(os.path.abspath( __file__ ))): try: uwsgi_version += '+%s' % spcall('git rev-parse --short HEAD') except: pass def spcall2(cmd): p = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE) if p.wait() == 0: if sys.version_info[0] > 2: return p.stderr.read().rstrip().decode() return p.stderr.read().rstrip() else: return None def test_snippet(snippet): """Compile a C snippet to see if features are available at build / link time.""" if sys.version_info[0] >= 3 or (sys.version_info[0] == 2 and sys.version_info[1] > 5): if not isinstance(snippet, bytes): if PY3: snippet = bytes(snippet, sys.getdefaultencoding()) else: snippet = bytes(snippet) cmd = "{0} -xc - -o /dev/null".format(GCC) else: cmd = GCC + " -xc - -o /dev/null" p = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE) p.communicate(snippet) return p.returncode == 0 def has_usable_ucontext(): if uwsgi_os in ('OpenBSD', 'Haiku'): return False if uwsgi_os.startswith('CYGWIN'): return False if uwsgi_os == 'Darwin' and uwsgi_os_k.startswith('8'): return False if uwsgi_cpu[0:3] == 'arm': return False # check for ucontext.h functions definitions, musl has only declarations return test_snippet("""#include int main() { ucontext_t uc; getcontext(&uc); return 0; }""") def spcall3(cmd): p = subprocess.Popen(cmd, shell=True, stdin=open('/dev/null'), stderr=subprocess.PIPE, stdout=subprocess.PIPE) (out, err) = p.communicate() if p.returncode == 0: if sys.version_info[0] > 2: return err.rstrip().decode() return err.rstrip() else: return None def add_o(x): if x == 'uwsgi': x = 'main' elif x.endswith('.a') or x.endswith('.o'): return x x = x + '.o' return x def push_print(msg): if not compile_queue: print(msg) else: compile_queue.put((None, msg)) def push_command(objfile, cmdline): if not compile_queue: print_compilation_output("[%s] %s" % (GCC, objfile), cmdline) ret = subprocess.call(cmdline, shell=True) if ret != 0: sys.exit(1) else: compile_queue.put((objfile, cmdline)) def uwsgi_compile(cflags, last_cflags_ts, objfile, srcfile): source_stat = os.stat(srcfile) header_stat = os.stat('uwsgi.h') try: if os.environ.get('UWSGI_FORCE_REBUILD', None): raise if source_stat[8] >= last_cflags_ts: raise if header_stat[8] >= last_cflags_ts: raise object_stat = os.stat(objfile) if object_stat[8] <= source_stat[8]: raise if object_stat[8] <= header_stat[8]: raise for profile in os.listdir('buildconf'): profile_stat = os.stat('buildconf/%s' % profile) if object_stat[8] <= profile_stat[8]: raise print("%s is up to date" % objfile) return except: pass cmdline = "%s -c %s -o %s %s" % (GCC, cflags, objfile, srcfile) push_command(objfile, cmdline) def build_uwsgi(uc, print_only=False, gcll=None): global print_lock, compile_queue, thread_compilers if CPUCOUNT > 1: print_lock = Lock() compile_queue = Queue(maxsize=CPUCOUNT) for i in range(0,CPUCOUNT): t = Thread(target=thread_compiler,args=(i,)) t.daemon = True t.start() thread_compilers.append(t) if not gcll: gcc_list, cflags, ldflags, libs = uc.get_gcll() else: gcc_list, cflags, ldflags, libs = gcll if 'UWSGI_EMBED_PLUGINS' in os.environ: ep = uc.get('embedded_plugins') if ep: uc.set('embedded_plugins', ep + ',' + os.environ['UWSGI_EMBED_PLUGINS']) else: uc.set('embedded_plugins', os.environ['UWSGI_EMBED_PLUGINS']) if uc.get('embedded_plugins'): ep = uc.get('embedded_plugins').split(',') epc = "-DUWSGI_DECLARE_EMBEDDED_PLUGINS=\"" eplc = "-DUWSGI_LOAD_EMBEDDED_PLUGINS=\"" for item in ep: # allow name=path syntax kv = item.split('=') p = kv[0] p = p.strip() if not p or p == 'None': continue if p == 'ugreen': if not report['ucontext']: continue epc += "UDEP(%s);" % p eplc += "ULEP(%s);" % p epc += "\"" eplc += "\"" cflags.append(epc) cflags.append(eplc) if print_only: print(' '.join(cflags)) sys.exit(0) if 'APPEND_CFLAGS' in os.environ: cflags += os.environ['APPEND_CFLAGS'].split() print("detected CPU cores: %d" % CPUCOUNT) print("configured CFLAGS: %s" % ' '.join(cflags)) if sys.version_info[0] >= 3: import binascii uwsgi_cflags = binascii.b2a_hex(' '.join(cflags).encode('ascii')).decode('ascii') else: uwsgi_cflags = ' '.join(cflags).encode('hex') last_cflags_ts = 0 if os.path.exists('uwsgibuild.lastcflags'): ulc = open('uwsgibuild.lastcflags','r') last_cflags = ulc.read() ulc.close() if uwsgi_cflags != last_cflags: os.environ['UWSGI_FORCE_REBUILD'] = '1' else: last_cflags_ts = os.stat('uwsgibuild.lastcflags')[8] ulc = open('uwsgibuild.lastcflags','w') ulc.write(uwsgi_cflags) ulc.close() # embed uwsgi.h in the server binary. It increases the binary size, but will be very useful # for various tricks (like cffi integration) # if possibile, the blob is compressed if sys.version_info[0] >= 3: uwsgi_dot_h_content = open('uwsgi.h', 'rb').read() else: uwsgi_dot_h_content = open('uwsgi.h').read() if report['zlib']: import zlib # maximum level of compression uwsgi_dot_h_content = zlib.compress(uwsgi_dot_h_content, 9) if sys.version_info[0] >= 3: import binascii uwsgi_dot_h = binascii.b2a_hex(uwsgi_dot_h_content).decode('ascii') else: uwsgi_dot_h = uwsgi_dot_h_content.encode('hex') open('core/dot_h.c', 'w').write('char *uwsgi_dot_h = "%s";\n' % uwsgi_dot_h); gcc_list.append('core/dot_h') # embed uwsgiconfig.py in the server binary. It increases the binary size, but will be very useful # if possibile, the blob is compressed if sys.version_info[0] >= 3: uwsgi_config_py_content = open('uwsgiconfig.py', 'rb').read() else: uwsgi_config_py_content = open('uwsgiconfig.py').read() if report['zlib']: import zlib # maximum level of compression uwsgi_config_py_content = zlib.compress(uwsgi_config_py_content, 9) if sys.version_info[0] >= 3: import binascii uwsgi_config_py = binascii.b2a_hex(uwsgi_config_py_content).decode('ascii') else: uwsgi_config_py = uwsgi_config_py_content.encode('hex') open('core/config_py.c', 'w').write('char *uwsgi_config_py = "%s";\n' % uwsgi_config_py); gcc_list.append('core/config_py') additional_sources = os.environ.get('UWSGI_ADDITIONAL_SOURCES') if not additional_sources: additional_sources = uc.get('additional_sources') if additional_sources: for item in additional_sources.split(','): gcc_list.append(item) if uc.filename.endswith('coverity.ini'): cflags.append('-DUWSGI_CFLAGS=\\"\\"') else: cflags.append('-DUWSGI_CFLAGS=\\"%s\\"' % uwsgi_cflags) build_date = int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) cflags.append('-DUWSGI_BUILD_DATE="\\"%s\\""' % time.strftime("%d %B %Y %H:%M:%S", time.gmtime(build_date))) post_build = [] push_print("*** uWSGI compiling server core ***") for file in gcc_list: objfile = file if objfile == 'uwsgi': objfile = 'main' if not objfile.endswith('.a') and not objfile.endswith('.o'): if objfile.endswith('.c') or objfile.endswith('.cc') or objfile.endswith('.m') or objfile.endswith('.go'): if objfile.endswith('.go'): cflags.append('-Wno-error') uwsgi_compile(' '.join(cflags), last_cflags_ts, objfile + '.o', file) if objfile.endswith('.go'): cflags.pop() else: if objfile == 'core/dot_h': cflags.append('-g') uwsgi_compile(' '.join(cflags), last_cflags_ts, objfile + '.o', file + '.c') if objfile == 'core/dot_h': cflags.pop() if uc.get('embedded_plugins'): ep = uc.get('embedded_plugins').split(',') if len(ep) > 0: push_print("*** uWSGI compiling embedded plugins ***") for item in ep: # allows name=path syntax kv = item.split('=') if len(kv) > 1: p = kv[1] p = p.strip() if p.startswith('http://') or p.startswith('https://') or p.startswith('git://') or p.startswith('ssh://'): git_dir = p.split('/').pop() if not os.path.isdir(git_dir): if os.system('git clone %s' % p) != 0: sys.exit(1) else: if os.system('cd %s ; git pull' % git_dir) != 0: sys.exit(1) p = git_dir path = os.path.abspath(p) else: p = kv[0] p = p.strip() path = 'plugins/%s' % p if not p or p == 'None': continue if p == 'ugreen': if not report['ucontext']: continue path = path.rstrip('/') up = {} if os.path.isfile(path): bname = os.path.basename(path) # override path path = os.path.dirname(path) up['GCC_LIST'] = [bname] up['NAME'] = bname.split('.')[0] if not path: path = '.' elif os.path.isdir(path): try: execfile('%s/uwsgiplugin.py' % path, up) except: f = open('%s/uwsgiplugin.py' % path) exec(f.read(), up) f.close() else: print("Error: plugin '%s' not found" % p) sys.exit(1) p_cflags = cflags[:] try: p_cflags += up['CFLAGS'] except: pass if uwsgi_os.startswith('CYGWIN'): try: p_cflags.remove('-fstack-protector') except: pass if GCC in ('clang',): try: p_cflags.remove('-fno-fast-math') p_cflags.remove('-ggdb3') except: pass try: p_cflags.remove('-Wdeclaration-after-statement') except: pass try: p_cflags.remove('-Werror=declaration-after-statement') except: pass try: p_cflags.remove('-Wwrite-strings') except: pass try: p_cflags.remove('-Werror=write-strings') except: pass try: if up['post_build']: post_build.append(up['post_build']) except: pass for cfile in up['GCC_LIST']: if cfile.endswith('.a'): gcc_list.append(cfile) elif cfile.endswith('.o'): gcc_list.append('%s/%s' % (path, cfile)) elif not cfile.endswith('.c') and not cfile.endswith('.cc') and not cfile.endswith('.go') and not cfile.endswith('.m'): uwsgi_compile(' '.join(uniq_warnings(p_cflags)), last_cflags_ts, path + '/' + cfile + '.o', path + '/' + cfile + '.c') gcc_list.append('%s/%s' % (path, cfile)) else: if cfile.endswith('.go'): p_cflags.append('-Wno-error') uwsgi_compile(' '.join(uniq_warnings(p_cflags)), last_cflags_ts, path + '/' + cfile + '.o', path + '/' + cfile) gcc_list.append('%s/%s' % (path, cfile)) for bfile in up.get('BINARY_LIST', []): try: binary_link_cmd = "ld -z noexecstack -r -b binary -o %s/%s.o %s/%s" % (path, bfile[1], path, bfile[1]) print(binary_link_cmd) if subprocess.call(binary_link_cmd, shell=True) != 0: raise Exception('unable to link binary file') for kind in ('start', 'end'): objcopy_cmd = "objcopy --redefine-sym _binary_%s_%s=%s_%s %s/%s.o" % (binarize('%s/%s' % (path, bfile[1])), kind, bfile[0], kind, path, bfile[1]) print(objcopy_cmd) if subprocess.call(objcopy_cmd, shell=True) != 0: raise Exception('unable to link binary file') gcc_list.append('%s/%s.o' % (path, bfile[1])) except: pass try: libs += up['LIBS'] except: pass if not 'LDFLAGS' in up: up['LDFLAGS'] = [] if uwsgi_os == 'Darwin': found_arch = False sanitized_ldflags = [] for flag in up['LDFLAGS']: if flag == '-arch': found_arch = True continue if found_arch: found_arch = False continue sanitized_ldflags.append(flag) ldflags += sanitized_ldflags else: ldflags += up['LDFLAGS'] if uc.get('plugins'): plugins = uc.get('plugins').split(',') if len(plugins) > 0: push_print("*** uWSGI building plugins ***") for p in plugins: p = p.strip() push_print("*** building plugin: %s ***" % p) build_plugin("plugins/%s" % p, uc, cflags, ldflags, libs) bin_name = os.environ.get('UWSGI_BIN_NAME', uc.get('bin_name')) if uc.embed_config: gcc_list.append("%s.o" % binarize(uc.embed_config)) for ef in binary_list: gcc_list.append("%s.o" % ef) if compile_queue: for t in thread_compilers: compile_queue.put((None, None)) for t in thread_compilers: t.join() print("*** uWSGI linking ***") ldline = "%s -o %s %s %s %s" % (GCC, quote(bin_name), ' '.join(uniq_warnings(ldflags)), ' '.join(map(add_o, gcc_list)), ' '.join(uniq_warnings(libs))) print(ldline) ret = subprocess.call(ldline, shell=True) if ret != 0: print("*** error linking uWSGI ***") sys.exit(1) print("################# uWSGI configuration #################") print("") for report_key in report: print("%s = %s" % (report_key, report[report_key])) print("") print("############## end of uWSGI configuration #############") print("total build time: %d seconds" % (time.time() - started_at)) if bin_name.find("/") < 0: bin_name = './' + bin_name if uc.get('as_shared_library'): print("*** uWSGI shared library (%s) is ready, move it to a library directory ***" % bin_name) else: print("*** uWSGI is ready, launch it with %s ***" % bin_name) for pb in post_build: pb(uc) def open_profile(filename): if filename.startswith('http://') or filename.startswith('https://') or filename.startswith('ftp://'): wrapped = False try: import urllib2 except: import urllib.request wrapped = True if wrapped: import io return io.TextIOWrapper(urllib.request.urlopen(filename), encoding='utf-8') return urllib2.urlopen(filename) return open(filename) class uConf(object): def __init__(self, filename, mute=False): global GCC self.filename = filename self.config = ConfigParser.ConfigParser() if not mute: print("using profile: %s" % filename) if os.path.exists('uwsgibuild.lastprofile'): ulp = open('uwsgibuild.lastprofile','r') last_profile = ulp.read() ulp.close() if last_profile != filename: os.environ['UWSGI_FORCE_REBUILD'] = '1' ulp = open('uwsgibuild.lastprofile', 'w') ulp.write(filename) ulp.close() if hasattr(self.config, 'read_file'): self.config.read_file(open_profile(filename)) else: self.config.readfp(open_profile(filename)) self.gcc_list = ['core/utils', 'core/protocol', 'core/socket', 'core/logging', 'core/master', 'core/master_utils', 'core/emperor', 'core/notify', 'core/mule', 'core/subscription', 'core/stats', 'core/sendfile', 'core/async', 'core/master_checks', 'core/fifo', 'core/offload', 'core/io', 'core/static', 'core/websockets', 'core/spooler', 'core/snmp', 'core/exceptions', 'core/config', 'core/setup_utils', 'core/clock', 'core/init', 'core/buffer', 'core/reader', 'core/writer', 'core/alarm', 'core/cron', 'core/hooks', 'core/plugins', 'core/lock', 'core/cache', 'core/daemons', 'core/errors', 'core/hash', 'core/master_events', 'core/chunked', 'core/queue', 'core/event', 'core/signal', 'core/strings', 'core/progress', 'core/timebomb', 'core/ini', 'core/fsmon', 'core/mount', 'core/metrics', 'core/plugins_builder', 'core/sharedarea', 'core/rpc', 'core/gateway', 'core/loop', 'core/cookie', 'core/querystring', 'core/rb_timers', 'core/transformations', 'core/uwsgi'] # add protocols self.gcc_list.append('proto/base') self.gcc_list.append('proto/uwsgi') self.gcc_list.append('proto/http') self.gcc_list.append('proto/fastcgi') self.gcc_list.append('proto/scgi') self.gcc_list.append('proto/puwsgi') self.include_path = [] if 'UWSGI_INCLUDES' in os.environ: self.include_path += os.environ['UWSGI_INCLUDES'].split(',') cflags = [ '-O2', '-I.', '-Wall', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64' ] self.cflags = cflags + os.environ.get("CFLAGS", "").split() + self.get('cflags', '').split() report['kernel'] = uwsgi_os if uwsgi_os == 'Linux': if uwsgi_cpu != 'ia64': self.gcc_list.append('lib/linux_ns') try: lk_ver = uwsgi_os_k.split('.') if int(lk_ver[0]) <= 2 and int(lk_ver[1]) <= 6 and int(lk_ver[2]) <= 9: self.cflags.append('-DOBSOLETE_LINUX_KERNEL') report['kernel'] = 'Old Linux' except: pass if uwsgi_os == 'GNU': self.cflags.append('-D__HURD__') gcc_version = spcall("%s -dumpfullversion -dumpversion" % GCC) if not gcc_version and GCC.startswith('gcc'): if uwsgi_os == 'Darwin': GCC = 'llvm-' + GCC else: GCC = 'gcc' gcc_version = spcall("%s -dumpfullversion -dumpversion" % GCC) try: add_it = False cpp_include_list = str(spcall3("%s -v" % CPP)).split("\n") for line in cpp_include_list: if line.startswith('#include <...> search starts here:'): add_it = True elif line.startswith('End of search list.'): add_it = False elif add_it: self.include_path.append(line.strip().split()[0]) if not self.include_path: raise except: self.include_path = ['/usr/include', '/usr/local/include'] additional_include_paths = self.get('additional_include_paths') if additional_include_paths: for ipath in additional_include_paths.split(): self.include_path.append(ipath) if 'UWSGI_REMOVE_INCLUDES' in os.environ: for inc in os.environ['UWSGI_REMOVE_INCLUDES'].split(','): try: self.include_path.remove(inc) except: pass if not mute: print("detected include path: %s" % self.include_path) try: gcc_version_components = gcc_version.split('.') gcc_major = int(gcc_version_components[0]) if len(gcc_version_components) > 1: gcc_minor = int(gcc_version_components[1]) else: # gcc 5.0 is represented as simply "5" gcc_minor = 0 except: raise Exception("you need a C compiler to build uWSGI") if (sys.version_info[0] == 2) or (gcc_major < 4) or (gcc_major == 4 and gcc_minor < 3): self.cflags = self.cflags + ['-fno-strict-aliasing'] # add -fno-strict-aliasing only on python2 and gcc < 4.3 if gcc_major >= 4: self.cflags = self.cflags + [ '-Wextra', '-Wno-unused-parameter', '-Wno-missing-field-initializers' ] if gcc_major == 4 and gcc_minor < 9: self.cflags.append('-Wno-format -Wno-format-security') if "gcc" in GCC and gcc_major >= 5: self.cflags.append('-Wformat-signedness') self.ldflags = os.environ.get("LDFLAGS", "").split() self.libs = ['-lpthread', '-lm', '-rdynamic'] if uwsgi_os in ('Linux', 'GNU', 'GNU/kFreeBSD'): self.libs.append('-ldl') if uwsgi_os == 'GNU/kFreeBSD': self.cflags.append('-D__GNU_kFreeBSD__') self.libs.append('-lbsd') # check for inherit option inherit = self.get('inherit') if inherit: if not '/' in inherit: inherit = 'buildconf/%s' % inherit if not inherit.endswith('.ini'): inherit = '%s.ini' % inherit interpolations = {} for option in self.config.options('uwsgi'): interpolations[option] = self.get(option, default='') iconfig = ConfigParser.ConfigParser(interpolations) if hasattr(self.config, 'read_file'): iconfig.read_file(open_profile(inherit)) else: iconfig.readfp(open_profile(inherit)) for opt in iconfig.options('uwsgi'): if not self.config.has_option('uwsgi', opt): self.set(opt, iconfig.get('uwsgi', opt)) elif self.get(opt): if self.get(opt).startswith('+'): self.set(opt, iconfig.get('uwsgi', opt) + self.get(opt)[1:]) elif self.get(opt) == 'null': self.config.remove_option('uwsgi', opt) def set(self, key, value): self.config.set('uwsgi',key, value) def get(self,key,default=None): try: value = self.config.get('uwsgi', key) if value == "" or value == "false": return default return value except: if default is not None: return default return None def depends_on(self, what, dep): for d in dep: if not self.get(d): print("%s needs %s support." % (what, d)) sys.exit(1) def has_include(self, what): for include in self.include_path: if os.path.exists("%s/%s" %(include, what)): return True return False def get_gcll(self): global uwsgi_version kvm_list = ['FreeBSD', 'OpenBSD', 'NetBSD', 'DragonFly'] if 'UWSGI_PROFILE_OVERRIDE' in os.environ: for item in os.environ['UWSGI_PROFILE_OVERRIDE'].split(';'): k,v = item.split('=', 1) self.set(k, v) if 'UWSGI_AS_LIB' in os.environ: self.set('as_shared_library', 'true') self.set('bin_name', os.environ['UWSGI_AS_LIB']) if self.has_include('ifaddrs.h'): self.cflags.append('-DUWSGI_HAS_IFADDRS') report['ifaddrs'] = True if uwsgi_os in ('FreeBSD', 'DragonFly', 'OpenBSD'): if self.has_include('execinfo.h') or os.path.exists('/usr/local/include/execinfo.h'): if os.path.exists('/usr/local/include/execinfo.h'): self.cflags.append('-I/usr/local/include') self.ldflags.append('-L/usr/local/lib') self.cflags.append('-DUWSGI_HAS_EXECINFO') self.libs.append('-lexecinfo') report['execinfo'] = True if uwsgi_os == 'GNU/kFreeBSD': if self.has_include('execinfo.h'): self.cflags.append('-DUWSGI_HAS_EXECINFO') report['execinfo'] = True if self.has_include('zlib.h'): self.cflags.append('-DUWSGI_ZLIB') self.libs.append('-lz') self.gcc_list.append('core/zlib') report['zlib'] = True if uwsgi_os == 'OpenBSD': try: obsd_major = uwsgi_os_k.split('.')[0] obsd_minor = uwsgi_os_k.split('.')[1] obsd_ver = int(obsd_major + obsd_minor) if obsd_ver > 50: self.cflags.append('-DUWSGI_NEW_OPENBSD') report['kernel'] = 'New OpenBSD' except: pass if uwsgi_os == 'SunOS': self.libs.append('-lsendfile') self.libs.append('-lrt') self.gcc_list.append('lib/sun_fixes') self.ldflags.append('-L/lib') if not uwsgi_os_v.startswith('Nexenta'): self.libs.remove('-rdynamic') if uwsgi_os == 'GNU/kFreeBSD': if self.has_include('kvm.h'): kvm_list.append('GNU/kFreeBSD') if uwsgi_os in kvm_list: self.libs.append('-lkvm') if uwsgi_os == 'Haiku': self.libs.remove('-rdynamic') self.libs.remove('-lpthread') self.libs.append('-lroot') if uwsgi_os == 'Darwin': if uwsgi_os_k.startswith('8'): self.cflags.append('-DUNSETENV_VOID') self.cflags.append('-DNO_SENDFILE') self.cflags.append('-DNO_EXECINFO') self.cflags.append('-DOLD_REALPATH') self.cflags.append('-mmacosx-version-min=10.5') if GCC in ('clang',): self.libs.remove('-rdynamic') # compile extras extras = self.get('extras', None) if extras: for extra in extras.split(','): self.gcc_list.append(extra) # check for usable ucontext report['ucontext'] = has_usable_ucontext() # set locking subsystem locking_mode = self.get('locking','auto') if locking_mode == 'auto': if uwsgi_os == 'Linux' or uwsgi_os == 'SunOS': locking_mode = 'pthread_mutex' # FreeBSD umtx is still not ready for process shared locking # starting from FreeBSD 9 posix semaphores can be shared between processes elif uwsgi_os in ('FreeBSD', 'GNU/kFreeBSD'): try: fbsd_major = int(uwsgi_os_k.split('.')[0]) if fbsd_major >= 9: locking_mode = 'posix_sem' except: pass elif uwsgi_os == 'GNU': locking_mode = 'posix_sem' elif uwsgi_os == 'Darwin': locking_mode = 'osx_spinlock' elif uwsgi_os.startswith('CYGWIN'): locking_mode = 'windows_mutex' if locking_mode == 'pthread_mutex': self.cflags.append('-DUWSGI_LOCK_USE_MUTEX') # FreeBSD umtx is still not ready for process shared locking elif locking_mode == 'posix_sem': self.cflags.append('-DUWSGI_LOCK_USE_POSIX_SEM') elif locking_mode == 'osx_spinlock': self.cflags.append('-DUWSGI_LOCK_USE_OSX_SPINLOCK') elif locking_mode == 'windows_mutex': self.cflags.append('-DUWSGI_LOCK_USE_WINDOWS_MUTEX') else: self.cflags.append('-DUWSGI_IPCSEM_ATEXIT') if locking_mode == 'auto': report['locking'] = 'sysv semaphores' else: report['locking'] = locking_mode # set event subsystem event_mode = self.get('event','auto') if event_mode == 'auto': if uwsgi_os == 'Linux': event_mode = 'epoll' if uwsgi_os == 'SunOS': event_mode = 'devpoll' sun_major, sun_minor = uwsgi_os_k.split('.') if int(sun_major) >= 5: if int(sun_minor) >= 10: event_mode = 'port' elif uwsgi_os in ('Darwin', 'FreeBSD', 'GNU/kFreeBSD', 'OpenBSD', 'NetBSD', 'DragonFly'): event_mode = 'kqueue' elif uwsgi_os.startswith('CYGWIN') or uwsgi_os == 'GNU': event_mode = 'poll' if event_mode == 'epoll': self.cflags.append('-DUWSGI_EVENT_USE_EPOLL') elif event_mode == 'kqueue': self.cflags.append('-DUWSGI_EVENT_USE_KQUEUE') elif event_mode == 'devpoll': self.cflags.append('-DUWSGI_EVENT_USE_DEVPOLL') elif event_mode == 'port': self.cflags.append('-DUWSGI_EVENT_USE_PORT') elif event_mode == 'poll': self.cflags.append('-DUWSGI_EVENT_USE_POLL') report['event'] = event_mode # set timer subsystem timer_mode = self.get('timer','auto') if timer_mode == 'auto': if uwsgi_os == 'Linux': k_all = uwsgi_os_k.split('.') k_base = k_all[0] k_major = k_all[1] if len(k_all) > 2: k_minor = k_all[2] else: k_minor = 0 if int(k_base) > 2: timer_mode = 'timerfd' elif int(k_minor) >= 25: timer_mode = 'timerfd' else: timer_mode = 'none' elif uwsgi_os == 'SunOS': sun_major, sun_minor = uwsgi_os_k.split('.') if int(sun_major) >= 5: if int(sun_minor) >= 10: timer_mode = 'port' elif uwsgi_os in ('Darwin', 'FreeBSD', 'GNU/kFreeBSD', 'OpenBSD', 'NetBSD', 'DragonFly'): timer_mode = 'kqueue' if timer_mode == 'timerfd': self.cflags.append('-DUWSGI_EVENT_TIMER_USE_TIMERFD') if not self.has_include('sys/timerfd.h'): self.cflags.append('-DUWSGI_EVENT_TIMER_USE_TIMERFD_NOINC') elif timer_mode == 'kqueue': self.cflags.append('-DUWSGI_EVENT_TIMER_USE_KQUEUE') elif timer_mode == 'port': self.cflags.append('-DUWSGI_EVENT_TIMER_USE_PORT') else: self.cflags.append('-DUWSGI_EVENT_TIMER_USE_NONE') report['timer'] = timer_mode # set filemonitor subsystem filemonitor_mode = self.get('filemonitor','auto') if filemonitor_mode == 'auto': if uwsgi_os == 'Linux': filemonitor_mode = 'inotify' elif uwsgi_os == 'SunOS': sun_major, sun_minor = uwsgi_os_k.split('.') if int(sun_major) >= 5: if int(sun_minor) >= 10: filemonitor_mode = 'port' elif uwsgi_os in ('Darwin', 'FreeBSD', 'GNU/kFreeBSD', 'OpenBSD', 'NetBSD', 'DragonFly'): filemonitor_mode = 'kqueue' if filemonitor_mode == 'inotify': self.cflags.append('-DUWSGI_EVENT_FILEMONITOR_USE_INOTIFY') elif filemonitor_mode == 'kqueue': self.cflags.append('-DUWSGI_EVENT_FILEMONITOR_USE_KQUEUE') elif filemonitor_mode == 'port': self.cflags.append('-DUWSGI_EVENT_FILEMONITOR_USE_PORT') else: self.cflags.append('-DUWSGI_EVENT_FILEMONITOR_USE_NONE') report['filemonitor'] = filemonitor_mode if self.get('malloc_implementation') != 'libc': if self.get('malloc_implementation') == 'tcmalloc': self.libs.append('-ltcmalloc') if self.get('malloc_implementation') == 'jemalloc': self.libs.append('-ljemalloc') report['malloc'] = self.get('malloc_implementation') if self.get('as_shared_library'): self.ldflags.append('-shared') # on cygwin we do not need PIC (it is implicit) if not uwsgi_os.startswith('CYGWIN'): self.ldflags.append('-fPIC') self.cflags.append('-fPIC') self.cflags.append('-DUWSGI_AS_SHARED_LIBRARY') if uwsgi_os == 'Darwin': self.ldflags.append('-dynamiclib') self.ldflags.append('-undefined dynamic_lookup') if self.get('blacklist'): self.cflags.append('-DUWSGI_BLACKLIST="\\"%s\\""' % self.get('blacklist')) if self.get('whitelist'): self.cflags.append('-DUWSGI_WHITELIST="\\"%s\\""' % self.get('whitelist')) has_pcre = False required_pcre = self.get('pcre') if required_pcre: pcre_libs = spcall('pcre2-config --libs8') if pcre_libs: pcre_cflags = spcall("pcre2-config --cflags") pcre_define = "-DUWSGI_PCRE2" else: pcre_libs = spcall('pcre-config --libs') pcre_cflags = spcall("pcre-config --cflags") pcre_define = "-DUWSGI_PCRE" else: pcre_libs = None if required_pcre: if required_pcre != 'auto' and pcre_libs is None: print("*** libpcre headers unavailable. uWSGI build is interrupted. You have to install pcre development package or disable pcre") sys.exit(1) if pcre_libs: self.libs.append(pcre_libs) self.cflags.append(pcre_cflags) self.gcc_list.append('core/regexp') self.cflags.append(pcre_define) has_pcre = True if has_pcre: report['pcre'] = True if self.get('routing'): if self.get('routing') == 'auto': if has_pcre: self.gcc_list.append('core/routing') self.cflags.append("-DUWSGI_ROUTING") report['routing'] = True else: self.gcc_list.append('core/routing') self.cflags.append("-DUWSGI_ROUTING") report['routing'] = True if self.has_include('sys/capability.h') and uwsgi_os == 'Linux': self.cflags.append("-DUWSGI_CAP") self.libs.append('-lcap') report['capabilities'] = True if self.has_include('uuid/uuid.h'): self.cflags.append("-DUWSGI_UUID") if uwsgi_os in ('Linux', 'GNU', 'GNU/kFreeBSD') or uwsgi_os.startswith('CYGWIN') or os.path.exists('/usr/lib/libuuid.so') or os.path.exists('/usr/local/lib/libuuid.so') or os.path.exists('/usr/lib64/libuuid.so') or os.path.exists('/usr/local/lib64/libuuid.so'): self.libs.append('-luuid') if self.get('append_version'): if not self.get('append_version').startswith('-'): uwsgi_version += '-' uwsgi_version += self.get('append_version') if uwsgi_os in ('FreeBSD','GNU/kFreeBSD') and self.has_include('jail.h'): self.cflags.append('-DUWSGI_HAS_FREEBSD_LIBJAIL') self.libs.append('-ljail') self.embed_config = None if uwsgi_os not in ('Darwin',): self.embed_config = os.environ.get('UWSGI_EMBED_CONFIG') if not self.embed_config: self.embed_config = self.get('embed_config') if self.embed_config: binary_link_cmd = "ld -z noexecstack -r -b binary -o %s.o %s" % (binarize(self.embed_config), self.embed_config) print(binary_link_cmd) subprocess.call(binary_link_cmd, shell=True) self.cflags.append("-DUWSGI_EMBED_CONFIG=_binary_%s_start" % binarize(self.embed_config)) self.cflags.append("-DUWSGI_EMBED_CONFIG_END=_binary_%s_end" % binarize(self.embed_config)) embed_files = os.environ.get('UWSGI_EMBED_FILES') if not embed_files: embed_files = self.get('embed_files') if embed_files: for ef in embed_files.split(','): ef_parts = ef.split('=') symbase = None if len(ef_parts) > 1: ef = ef_parts[1] symbase = ef_parts[0] if os.path.isdir(ef): for directory, directories, files in os.walk(ef): for f in files: fname = "%s/%s" % (directory, f) binary_link_cmd = "ld -z noexecstack -r -b binary -o %s.o %s" % (binarize(fname), fname) print(binary_link_cmd) subprocess.call(binary_link_cmd, shell=True) if symbase: for kind in ('start','end'): objcopy_cmd = "objcopy --redefine-sym _binary_%s_%s=_binary_%s%s_%s build/%s.o" % (binarize(fname), kind, binarize(symbase), binarize(fname[len(ef):]), kind, binarize(fname)) print(objcopy_cmd) subprocess.call(objcopy_cmd, shell=True) binary_list.append(binarize(fname)) else: binary_link_cmd = "ld -z noexecstack -r -b binary -o %s.o %s" % (binarize(ef), ef) print(binary_link_cmd) subprocess.call(binary_link_cmd, shell=True) binary_list.append(binarize(ef)) if symbase: for kind in ('start','end'): objcopy_cmd = "objcopy --redefine-sym _binary_%s_%s=_binary_%s_%s build/%s.o" % (binarize(ef), kind, binarize(symbase), kind, binarize(ef)) print(objcopy_cmd) subprocess.call(objcopy_cmd, shell=True) self.cflags.append('-DUWSGI_VERSION="\\"' + uwsgi_version + '\\""') uver_whole = uwsgi_version.split('-', 1) if len(uver_whole) == 1: uver_custom = '' else: uver_custom = uver_whole[1] uver_dots = uver_whole[0].split('.') uver_base = uver_dots[0] uver_maj = uver_dots[1] uver_min = '0' uver_rev = '0' if len(uver_dots) > 2: uver_min = uver_dots[2] if len(uver_dots) > 3: uver_rev = uver_dots[3] self.cflags.append('-DUWSGI_VERSION_BASE="' + uver_base + '"') self.cflags.append('-DUWSGI_VERSION_MAJOR="' + uver_maj + '"') self.cflags.append('-DUWSGI_VERSION_MINOR="' + uver_min + '"') self.cflags.append('-DUWSGI_VERSION_REVISION="' + uver_rev + '"') self.cflags.append('-DUWSGI_VERSION_CUSTOM="\\"' + uver_custom + '\\""') if self.get('yaml'): self.cflags.append("-DUWSGI_YAML") self.gcc_list.append('core/yaml') report['yaml'] = 'embedded' if self.get('yaml') == 'libyaml': self.cflags.append("-DUWSGI_LIBYAML") self.libs.append('-lyaml') report['yaml'] = 'libyaml' if self.get('json'): if self.get('json') in ('auto', 'true'): jsonconf = spcall("pkg-config --cflags jansson") if jsonconf: self.cflags.append(jsonconf) self.cflags.append("-DUWSGI_JSON") self.gcc_list.append('core/json') self.libs.append(spcall("pkg-config --libs jansson")) report['json'] = 'jansson' elif self.has_include('jansson.h'): self.cflags.append("-DUWSGI_JSON") self.gcc_list.append('core/json') self.libs.append('-ljansson') report['json'] = 'jansson' else: jsonconf = spcall("pkg-config --cflags yajl") if jsonconf: if jsonconf.endswith('include/yajl'): jsonconf = jsonconf.rstrip('yajl') self.cflags.append(jsonconf) self.cflags.append("-DUWSGI_JSON") self.gcc_list.append('core/json') self.libs.append(spcall("pkg-config --libs yajl")) self.cflags.append("-DUWSGI_JSON_YAJL") report['json'] = 'yajl' elif self.get('json') == 'true': print("*** jansson and yajl headers unavailable. uWSGI build is interrupted. You have to install jansson or yajl development headers or disable JSON") sys.exit(1) elif self.get('json') == 'jansson': jsonconf = spcall("pkg-config --cflags jansson") if jsonconf: self.cflags.append(jsonconf) self.cflags.append("-DUWSGI_JSON") self.gcc_list.append('core/json') self.libs.append(spcall("pkg-config --libs jansson")) report['json'] = 'jansson' elif self.has_include('jansson.h'): self.cflags.append("-DUWSGI_JSON") self.gcc_list.append('core/json') self.libs.append('-ljansson') report['json'] = 'jansson' else: print("*** jansson headers unavailable. uWSGI build is interrupted. You have to install jansson development package or use yajl or disable JSON") sys.exit(1) elif self.get('json') == 'yajl': jsonconf = spcall("pkg-config --cflags yajl") if jsonconf: self.cflags.append(jsonconf) self.cflags.append("-DUWSGI_JSON") self.gcc_list.append('core/json') self.libs.append(spcall("pkg-config --libs yajl")) self.cflags.append("-DUWSGI_JSON_YAJL") report['json'] = 'yajl' elif self.has_include('yajl/yajl_tree.h'): self.cflags.append("-DUWSGI_JSON") self.gcc_list.append('core/json') self.libs.append('-lyajl') self.cflags.append("-DUWSGI_JSON_YAJL") report['json'] = 'yajl' elif self.has_include('yajl/yajl_parse.h'): self.cflags.append("-DUWSGI_JSON") self.gcc_list.append('core/json') self.libs.append('-lyajl') self.cflags.append("-DUWSGI_JSON_YAJL_OLD") report['json'] = 'yajl_old' else: print("*** yajl headers unavailable. uWSGI build is interrupted. You have to install yajl development package or use jansson or disable JSON") sys.exit(1) if self.get('ssl'): if self.get('ssl') == 'auto': if self.has_include('openssl/ssl.h'): self.cflags.append("-DUWSGI_SSL") self.libs.append('-lssl') self.libs.append('-lcrypto') self.gcc_list.append('core/ssl') self.gcc_list.append('core/legion') report['ssl'] = True else: self.cflags.append("-DUWSGI_SSL") self.libs.append('-lssl') self.libs.append('-lcrypto') self.gcc_list.append('core/ssl') self.gcc_list.append('core/legion') report['ssl'] = True if self.get('xml'): if self.get('xml') == 'auto': xmlconf = spcall('xml2-config --libs') if xmlconf and uwsgi_os != 'Darwin': self.libs.append(xmlconf) xmlconf = spcall("xml2-config --cflags") self.cflags.append(xmlconf) self.cflags.append("-DUWSGI_XML -DUWSGI_XML_LIBXML2") self.gcc_list.append('core/xmlconf') report['xml'] = 'libxml2' elif self.has_include('expat.h'): self.cflags.append("-DUWSGI_XML -DUWSGI_XML_EXPAT") self.libs.append('-lexpat') self.gcc_list.append('core/xmlconf') report['xml'] = 'expat' elif self.get('xml') == 'libxml2': xmlconf = spcall('xml2-config --libs') if xmlconf is None: print("*** libxml2 headers unavailable. uWSGI build is interrupted. You have to install libxml2 development package or use libexpat or disable XML") sys.exit(1) else: self.libs.append(xmlconf) xmlconf = spcall("xml2-config --cflags") if xmlconf is None: print("*** libxml2 headers unavailable. uWSGI build is interrupted. You have to install libxml2 development package or use libexpat or disable XML") sys.exit(1) else: self.cflags.append(xmlconf) self.cflags.append("-DUWSGI_XML -DUWSGI_XML_LIBXML2") self.gcc_list.append('core/xmlconf') report['xml'] = 'libxml2' elif self.get('xml') == 'expat': self.cflags.append("-DUWSGI_XML -DUWSGI_XML_EXPAT") self.libs.append('-lexpat') self.gcc_list.append('core/xmlconf') report['xml'] = 'expat' if self.get('plugin_dir'): self.cflags.append('-DUWSGI_PLUGIN_DIR="\\"%s\\""' % self.get('plugin_dir')) report['plugin_dir'] = self.get('plugin_dir') if self.get('debug'): self.cflags.append("-DUWSGI_DEBUG") self.cflags.append("-g") report['debug'] = True if self.get('unbit'): self.cflags.append("-DUNBIT") return self.gcc_list, self.cflags, self.ldflags, self.libs def build_plugin(path, uc, cflags, ldflags, libs, name = None): path = path.rstrip('/') plugin_started_at = time.time() up = {} if path.startswith('http://') or path.startswith('https://') or path.startswith('git://') or path.startswith('ssh://'): git_dir = path.split('/').pop() if not os.path.isdir(git_dir): if os.system('git clone %s' % path) != 0: sys.exit(1) else: if os.system('cd %s ; git pull' % git_dir) != 0: sys.exit(1) path = os.path.abspath(git_dir) if os.path.isfile(path): bname = os.path.basename(path) # override path path = os.path.dirname(path) up['GCC_LIST'] = [bname] up['NAME'] = bname.split('.')[0] if not path: path = '.' elif os.path.isdir(path): try: execfile('%s/uwsgiplugin.py' % path, up) except: f = open('%s/uwsgiplugin.py' % path) exec(f.read(), up) f.close() else: print("Error: unable to find directory '%s'" % path) sys.exit(1) requires = [] p_cflags = cflags[:] p_ldflags = ldflags[:] try: p_cflags += up['CFLAGS'] except: pass try: p_ldflags += up['LDFLAGS'] except: pass try: p_libs = up['LIBS'] except: p_libs = [] post_build = None try: requires = up['REQUIRES'] except: pass try: post_build = up['post_build'] except: pass p_cflags.insert(0, '-I.') if name is None: name = up['NAME'] else: p_cflags.append("-D%s_plugin=%s_plugin" % (up['NAME'], name)) try: for opt in uc.config.options(name): p_cflags.append('-DUWSGI_PLUGIN_%s_%s="%s"' % (name.upper(), opt.upper(), uc.config.get(name, opt, '1'))) except: pass if uc: plugin_dest = uc.get('plugin_build_dir', uc.get('plugin_dir')) + '/' + name + '_plugin' else: plugin_dest = name + '_plugin' shared_flag = '-shared' gcc_list = [] if uwsgi_os == 'Darwin': shared_flag = '-dynamiclib -undefined dynamic_lookup' for cfile in up['GCC_LIST']: if cfile.endswith('.a'): gcc_list.append(cfile) elif not cfile.endswith('.c') and not cfile.endswith('.cc') and not cfile.endswith('.m') and not cfile.endswith('.go') and not cfile.endswith('.o'): gcc_list.append(path + '/' + cfile + '.c') else: if cfile.endswith('.go'): p_cflags.append('-Wno-error') gcc_list.append(path + '/' + cfile) for bfile in up.get('BINARY_LIST', []): try: binary_link_cmd = "ld -r -b binary -o %s/%s.o %s/%s" % (path, bfile[1], path, bfile[1]) print(binary_link_cmd) if subprocess.call(binary_link_cmd, shell=True) != 0: raise Exception('unable to link binary file') for kind in ('start','end'): objcopy_cmd = "objcopy --redefine-sym _binary_%s_%s=%s_%s %s/%s.o" % (binarize('%s/%s' % (path, bfile[1])), kind, bfile[0], kind, path, bfile[1]) print(objcopy_cmd) if subprocess.call(objcopy_cmd, shell=True) != 0: raise Exception('unable to link binary file') gcc_list.append('%s/%s.o' % (path, bfile[1])) except: pass try: p_ldflags.remove('-Wl,--no-undefined') except: pass try: p_cflags.remove('-Wwrite-strings') except: pass try: p_cflags.remove('-Werror=write-strings') except: pass try: p_cflags.remove('-Wdeclaration-after-statement') except: pass try: p_cflags.remove('-Werror=declaration-after-statement') except: pass try: p_cflags.remove('-Winline') except: pass try: p_cflags.remove('-pie') except: pass if GCC in ('clang',): try: p_cflags.remove('-fno-fast-math') p_cflags.remove('-ggdb3') except: pass if uwsgi_os.startswith('CYGWIN'): try: p_cflags.remove('-fstack-protector') p_ldflags.remove('-fstack-protector') except: pass need_pic = ' -fPIC' # on cygwin we do not need PIC if uwsgi_os.startswith('CYGWIN'): need_pic = ' -L. -luwsgi' gccline = "%s%s %s -o %s.so %s %s %s %s" % (GCC, need_pic, shared_flag, plugin_dest, ' '.join(uniq_warnings(p_cflags)), ' '.join(gcc_list), ' '.join(uniq_warnings(p_ldflags)), ' '.join(uniq_warnings(p_libs)) ) print_compilation_output("[%s] %s.so" % (GCC, plugin_dest), gccline) ret = subprocess.call(gccline, shell=True) if ret != 0: print("*** unable to build %s plugin ***" % name) sys.exit(1) try: if requires: f = open('.uwsgi_plugin_section', 'w') for rp in requires: f.write("requires=%s\n" % rp) f.close() objline = "objcopy %s.so --add-section uwsgi=.uwsgi_plugin_section %s.so" % (plugin_dest, plugin_dest) print_compilation_output(None, objline) subprocess.call(objline, shell=True) os.unlink('.uwsgi_plugin_section') except: pass if post_build: post_build(uc) print("build time: %d seconds" % (time.time() - plugin_started_at)) print("*** %s plugin built and available in %s ***" % (name, plugin_dest + '.so')) def vararg_callback(option, opt_str, value, parser): assert value is None value = [] for arg in parser.rargs: # stop on --foo like options if arg[:2] == "--" and len(arg) > 2: break # stop on -a, but not on -3 or -3.0 if arg[:1] == "-" and len(arg) > 1: break value.append(arg) del parser.rargs[:len(value)] setattr(parser.values, option.dest, value) if __name__ == "__main__": parser = OptionParser() parser.add_option("-b", "--build", action="callback", callback=vararg_callback, dest="build", help="build a specific profile if provided or default.ini", metavar="PROFILE") parser.add_option("-f", "--cflags", action="callback", callback=vararg_callback, dest="cflags", help="same as --build but less verbose", metavar="PROFILE") parser.add_option("-u", "--unbit", action="store_true", dest="unbit", help="build unbit profile") parser.add_option("-p", "--plugin", action="callback", callback=vararg_callback, dest="plugin", help="build a plugin as shared library, optionally takes a build profile name", metavar="PLUGIN [PROFILE]") parser.add_option("-x", "--extra-plugin", action="callback", callback=vararg_callback, dest="extra_plugin", help="build an external plugin as shared library, takes an optional include dir", metavar="PLUGIN [NAME]") parser.add_option("-c", "--clean", action="store_true", dest="clean", help="clean the build") parser.add_option("-e", "--check", action="store_true", dest="check", help="run cppcheck") parser.add_option("-v", "--verbose", action="store_true", dest="verbose", help="more verbose build") parser.add_option("-g", "--debug", action="store_true", dest="debug", help="build with debug symbols, affects only full build") parser.add_option("-a", "--asan", action="store_true", dest="asan", help="build with address sanitizer, it's a debug option and affects only full build") (options, args) = parser.parse_args() if options.verbose: verbose_build = True add_cflags = [] add_ldflags = [] if options.debug: add_cflags.append('-g') add_ldflags.append('-g') if options.asan: add_cflags.extend(['-g', '-fsanitize=address', '-fno-omit-frame-pointer']) add_ldflags.extend(['-g', '-fsanitize=address']) if options.build is not None or options.cflags is not None: is_cflags = options.cflags is not None try: if not is_cflags: bconf = options.build[0] else: bconf = options.cflags[0] except: bconf = os.environ.get('UWSGI_PROFILE','default.ini') if not bconf.endswith('.ini'): bconf += '.ini' if not '/' in bconf: bconf = 'buildconf/%s' % bconf uc = uConf(bconf, is_cflags) if add_cflags or add_ldflags: gcc_list, cflags, ldflags, libs = uc.get_gcll() if add_cflags: cflags.extend(add_cflags) if add_ldflags: ldflags.extend(add_ldflags) gcll = (gcc_list, cflags, ldflags, libs) else: gcll = None build_uwsgi(uc, is_cflags, gcll=gcll) elif options.unbit: build_uwsgi(uConf('buildconf/unbit.ini')) elif options.plugin: try: bconf = options.plugin[1] except: bconf = os.environ.get('UWSGI_PROFILE','default.ini') if not bconf.endswith('.ini'): bconf += '.ini' if not '/' in bconf: bconf = 'buildconf/%s' % bconf uc = uConf(bconf) gcc_list, cflags, ldflags, libs = uc.get_gcll() try: name = options.plugin[2] except: name = None print("*** uWSGI building and linking plugin %s ***" % options.plugin[0] ) build_plugin(options.plugin[0], uc, cflags, ldflags, libs, name) elif options.extra_plugin: print("*** uWSGI building and linking plugin from %s ***" % options.extra_plugin[0]) cflags = os.environ['UWSGI_PLUGINS_BUILDER_CFLAGS'].split() + os.environ.get("CFLAGS", "").split() cflags.append('-I.uwsgi_plugins_builder/') ldflags = os.environ.get("LDFLAGS", "").split() name = None try: name = options.extra_plugin[1] except: pass build_plugin(options.extra_plugin[0], None, cflags, ldflags, None, name) elif options.clean: subprocess.call("rm -f core/*.o", shell=True) subprocess.call("rm -f proto/*.o", shell=True) subprocess.call("rm -f lib/*.o", shell=True) subprocess.call("rm -f plugins/*/*.o", shell=True) subprocess.call("rm -f build/*.o", shell=True) subprocess.call("rm -f core/dot_h.c", shell=True) subprocess.call("rm -f core/config_py.c", shell=True) elif options.check: subprocess.call("cppcheck --max-configs=1000 --enable=all -q core/ plugins/ proto/ lib/ apache2/", shell=True) else: parser.print_help() sys.exit(1) uwsgi-2.0.29/uwsgidecorators.py000066400000000000000000000242301477626554400165650ustar00rootroot00000000000000from functools import partial import sys from threading import Thread try: import cPickle as pickle except: import pickle import uwsgi if uwsgi.masterpid() == 0: raise Exception( "you have to enable the uWSGI master process to use this module") spooler_functions = {} mule_functions = {} postfork_chain = [] # Python3 compatibility def _encode1(val): if sys.version_info >= (3, 0) and isinstance(val, str): return val.encode('utf-8') else: return val def _decode1(val): if sys.version_info >= (3, 0) and isinstance(val, bytes): return val.decode('utf-8') else: return val def _encode_to_spooler(vars): return dict((_encode1(K), _encode1(V)) for (K, V) in vars.items()) def _decode_from_spooler(vars): return dict((_decode1(K), _decode1(V)) for (K, V) in vars.items()) def get_free_signal(): for signum in range(0, 256): if not uwsgi.signal_registered(signum): return signum raise Exception("No free uwsgi signal available") def manage_spool_request(vars): # To check whether 'args' is in vals or not - decode the keys first, # because in python3 all keys in 'vals' are have 'byte' types vars = dict((_decode1(K), V) for (K, V) in vars.items()) if 'args' in vars: for k in ('args', 'kwargs'): vars[k] = pickle.loads(vars.pop(k)) vars = _decode_from_spooler(vars) f = spooler_functions[vars['ud_spool_func']] if 'args' in vars: ret = f(*vars['args'], **vars['kwargs']) else: ret = f(vars) return int(vars.get('ud_spool_ret', ret)) def postfork_chain_hook(): for f in postfork_chain: f() uwsgi.spooler = manage_spool_request uwsgi.post_fork_hook = postfork_chain_hook class postfork(object): def __init__(self, f): if callable(f): self.wid = 0 self.f = f else: self.f = None self.wid = f postfork_chain.append(self) def __call__(self, *args, **kwargs): if self.f: if self.wid > 0 and self.wid != uwsgi.worker_id(): return return self.f() self.f = args[0] class _spoolraw(object): def __call__(self, *args, **kwargs): arguments = self.base_dict.copy() if not self.pass_arguments: if len(args) > 0: arguments.update(args[0]) if kwargs: arguments.update(kwargs) else: spooler_args = {} for key in ('message_dict', 'spooler', 'priority', 'at', 'body'): if key in kwargs: spooler_args.update({key: kwargs.pop(key)}) arguments.update(spooler_args) arguments.update( {'args': pickle.dumps(args), 'kwargs': pickle.dumps(kwargs)}) return uwsgi.spool(_encode_to_spooler(arguments)) # For backward compatibility (uWSGI < 1.9.13) def spool(self, *args, **kwargs): return self.__class__.__call__(self, *args, **kwargs) def __init__(self, f, pass_arguments): if not 'spooler' in uwsgi.opt: raise Exception( "you have to enable the uWSGI spooler to use @%s decorator" % self.__class__.__name__) self.f = f spooler_functions[self.f.__name__] = self.f # For backward compatibility (uWSGI < 1.9.13) self.f.spool = self.__call__ self.pass_arguments = pass_arguments self.base_dict = {'ud_spool_func': self.f.__name__} class _spool(_spoolraw): def __call__(self, *args, **kwargs): self.base_dict['ud_spool_ret'] = str(uwsgi.SPOOL_OK) return _spoolraw.__call__(self, *args, **kwargs) class _spoolforever(_spoolraw): def __call__(self, *args, **kwargs): self.base_dict['ud_spool_ret'] = str(uwsgi.SPOOL_RETRY) return _spoolraw.__call__(self, *args, **kwargs) def spool_decorate(f=None, pass_arguments=False, _class=_spoolraw): if not f: return partial(_class, pass_arguments=pass_arguments) return _class(f, pass_arguments) def spoolraw(f=None, pass_arguments=False): return spool_decorate(f, pass_arguments) def spool(f=None, pass_arguments=False): return spool_decorate(f, pass_arguments, _spool) def spoolforever(f=None, pass_arguments=False): return spool_decorate(f, pass_arguments, _spoolforever) class mulefunc(object): def __init__(self, f): if callable(f): self.fname = f.__name__ self.mule = 0 mule_functions[f.__name__] = f else: self.mule = f self.fname = None def real_call(self, *args, **kwargs): uwsgi.mule_msg(pickle.dumps( { 'service': 'uwsgi_mulefunc', 'func': self.fname, 'args': args, 'kwargs': kwargs } ), self.mule) def __call__(self, *args, **kwargs): if not self.fname: self.fname = args[0].__name__ mule_functions[self.fname] = args[0] return self.real_call return self.real_call(*args, **kwargs) def mule_msg_dispatcher(message): msg = pickle.loads(message) if msg['service'] == 'uwsgi_mulefunc': return mule_functions[msg['func']](*msg['args'], **msg['kwargs']) uwsgi.mule_msg_hook = mule_msg_dispatcher class rpc(object): def __init__(self, name): self.name = name def __call__(self, f): uwsgi.register_rpc(self.name, f) return f class farm_loop(object): def __init__(self, f, farm): self.f = f self.farm = farm def __call__(self): if uwsgi.mule_id() == 0: return if not uwsgi.in_farm(self.farm): return while True: message = uwsgi.farm_get_msg() if message: self.f(message) class farm(object): def __init__(self, name=None, **kwargs): self.name = name def __call__(self, f): postfork_chain.append(farm_loop(f, self.name)) class mule_brain(object): def __init__(self, f, num): self.f = f self.num = num def __call__(self): if uwsgi.mule_id() == self.num: try: self.f() except: exc = sys.exc_info() sys.excepthook(exc[0], exc[1], exc[2]) sys.exit(1) class mule_brainloop(mule_brain): def __call__(self): if uwsgi.mule_id() == self.num: while True: try: self.f() except: exc = sys.exc_info() sys.excepthook(exc[0], exc[1], exc[2]) sys.exit(1) class mule(object): def __init__(self, num): self.num = num def __call__(self, f): postfork_chain.append(mule_brain(f, self.num)) class muleloop(mule): def __call__(self, f): postfork_chain.append(mule_brainloop(f, self.num)) class mulemsg_loop(object): def __init__(self, f, num): self.f = f self.num = num def __call__(self): if uwsgi.mule_id() == self.num: while True: message = uwsgi.mule_get_msg() if message: self.f(message) class mulemsg(object): def __init__(self, num): self.num = num def __call__(self, f): postfork_chain.append(mulemsg_loop(f, self.num)) class signal(object): def __init__(self, num, **kwargs): self.num = num self.target = kwargs.get('target', '') def __call__(self, f): uwsgi.register_signal(self.num, self.target, f) return f class timer(object): def __init__(self, secs, **kwargs): self.num = kwargs.get('signum', get_free_signal()) self.secs = secs self.target = kwargs.get('target', '') def __call__(self, f): uwsgi.register_signal(self.num, self.target, f) uwsgi.add_timer(self.num, self.secs) return f class cron(object): def __init__(self, minute, hour, day, month, dayweek, **kwargs): self.num = kwargs.get('signum', get_free_signal()) self.minute = minute self.hour = hour self.day = day self.month = month self.dayweek = dayweek self.target = kwargs.get('target', '') def __call__(self, f): uwsgi.register_signal(self.num, self.target, f) uwsgi.add_cron(self.num, self.minute, self.hour, self.day, self.month, self.dayweek) return f class rbtimer(object): def __init__(self, secs, **kwargs): self.num = kwargs.get('signum', get_free_signal()) self.secs = secs self.target = kwargs.get('target', '') def __call__(self, f): uwsgi.register_signal(self.num, self.target, f) uwsgi.add_rb_timer(self.num, self.secs) return f class filemon(object): def __init__(self, fsobj, **kwargs): self.num = kwargs.get('signum', get_free_signal()) self.fsobj = fsobj self.target = kwargs.get('target', '') def __call__(self, f): uwsgi.register_signal(self.num, self.target, f) uwsgi.add_file_monitor(self.num, self.fsobj) return f class erlang(object): def __init__(self, name): self.name = name def __call__(self, f): uwsgi.erlang_register_process(self.name, f) return f class lock(object): def __init__(self, f): self.f = f def __call__(self, *args, **kwargs): # ensure the spooler will not call it if uwsgi.i_am_the_spooler(): return uwsgi.lock() try: return self.f(*args, **kwargs) finally: uwsgi.unlock() class thread(object): def __init__(self, f): self.f = f def __call__(self, *args): t = Thread(target=self.f, args=args) t.daemon = True t.start() return self.f class harakiri(object): def __init__(self, seconds): self.s = seconds def real_call(self, *args, **kwargs): uwsgi.set_user_harakiri(self.s) r = self.f(*args, **kwargs) uwsgi.set_user_harakiri(0) return r def __call__(self, f): self.f = f return self.real_call uwsgi-2.0.29/uwsgidsl.rb000066400000000000000000000054271477626554400151640ustar00rootroot00000000000000# based on uwsgidecorators.py if UWSGI.masterpid == 0 raise "you have to enable the uWSGI master process to use this module" end def get_free_signal() for signum in 0..255 if not UWSGI.signal_registered(signum) return signum end end end $postfork_chain = [] $mulefunc_list = [] $spoolfunc_list = [] module UWSGI module_function def post_fork_hook() $postfork_chain.each {|func| func.call } end module_function def spooler(args) $spoolfunc_list[args['ud_spool_func'].to_i].call(args) end module_function def mule_msg_hook(message) service = Marshal.load(message) if service['service'] == 'uwsgi_mulefunc' mulefunc_manager(service) end end end def timer(secs, target='', &block) freesig = get_free_signal UWSGI.register_signal(freesig, target, block) UWSGI.add_timer(freesig, secs) end def rbtimer(secs, target='', &block) freesig = get_free_signal UWSGI.register_signal(freesig, target, block) UWSGI.add_rb_timer(freesig, secs) end def filemon(file, target='', &block) freesig = get_free_signal UWSGI.register_signal(freesig, target, block) UWSGI.add_file_monitor(freesig, file) end def cron(minute, hour, day, month, dayweek, target='', &block) freesig = get_free_signal UWSGI.register_signal(freesig, target, block) UWSGI.add_cron(freesig, minute, hour, day, month, dayweek) end def signal(signum, target='', &block) UWSGI.register_signal(signum, target, block) end def postfork(&block) $postfork_chain << block end class SpoolProc < Proc def initialize(&block) @block = block @id = (($spoolfunc_list << block).length-1).to_s end def call(args) args['ud_spool_func'] = @id UWSGI::send_to_spooler(args) end end def rpc(name, &block) if block.arity <= 0 UWSGI.register_rpc(name, block, 0) else UWSGI.register_rpc(name, block, block.arity) end end def mulefunc_manager(service) $mulefunc_list[service['func']].real_call(service['args']) end class MuleFunc < Proc def initialize(id=0, &block) @id = id @block = block @func_pos = (($mulefunc_list << self).length)-1 end def real_call(*args) @block.call(*args) end def call(*args) UWSGI.mule_msg( Marshal.dump( { 'service' => 'uwsgi_mulefunc', 'func' => @func_pos, 'args'=> args }), @id) end end class MuleProc < Proc def initialize(id, block) @id = id @block = block end def call() if UWSGI.mule_id == @id @block.call end end end class MuleLoopProc < MuleProc def call() if UWSGI.mule_id == @id loop do @block.call end end end end def mule(id, &block) $postfork_chain << MuleProc.new(id, block) end def muleloop(id, &block) $postfork_chain << MuleLoopProc.new(id, block) end uwsgi-2.0.29/valgrind/000077500000000000000000000000001477626554400145745ustar00rootroot00000000000000uwsgi-2.0.29/valgrind/README000066400000000000000000000004741477626554400154610ustar00rootroot00000000000000valgrind-generate-sups.sh ========================= This script can be used to generate valgrind suppression file. Valgrind will show a lot of python related errors, to filter them out You can: ./valgrind-generate-sups.sh > valgrind.suppression valgrind --tool=memcheck --suppressions=valgrind.suppression [ARGS] uwsgi-2.0.29/valgrind/valgrind-generate-sups.sh000077500000000000000000000007101477626554400215170ustar00rootroot00000000000000#!/bin/bash pydir=${1:-/usr} gensup() { for SUP in Cond Free Leak Overlap Addr1 Addr2 Addr4 Addr8 Addr16 Value1 Value2 Value4 Value8 Value16 ; do echo " { Autogenerated $1 suppression Memcheck:${SUP} obj:$2 } " done } while read SO ; do gensup libpython "$SO" done < <(find ${pydir}/lib*/ -type f -name libpython*) while read SO ; do gensup python "$SO" done < <(find ${pydir}/lib*/python*/ -type f -name \*.so) uwsgi-2.0.29/vassals/000077500000000000000000000000001477626554400144425ustar00rootroot00000000000000uwsgi-2.0.29/vassals/broodlord.ini000066400000000000000000000004771477626554400171410ustar00rootroot00000000000000[uwsgi] socket = :3031 master = true vassal-sos-backlog = 10 module = werkzeug.testapp:test_app processes = 1 zerg-server = /tmp/broodlord.sock disable-logging = true [zerg] zerg = /tmp/broodlord.sock master = true module = werkzeug.testapp:test_app processes = 1 disable-logging = true idle = 30 die-on-idle = true uwsgi-2.0.29/vassals/cc.ini000066400000000000000000000002571477626554400155340ustar00rootroot00000000000000[uwsgi] trac = trac.web.main id = myapp socket = /tmp/%(id).sock socket = :0 env = TRAC_ENV=/opt/projects/%(id) module = %(trac):dispatch_request processes = 8 master = true uwsgi-2.0.29/vassals/multi.xml000066400000000000000000000007521477626554400163220ustar00rootroot00000000000000 app001 starting dir is %v %v/../ 127.0.0.1 %(localhost):3039 /tmp/%(id).sock2 4 werkzeug.testapp:test_app %(cpus) uwsgi-2.0.29/vhosttest/000077500000000000000000000000001477626554400150315ustar00rootroot00000000000000uwsgi-2.0.29/vhosttest/flask001/000077500000000000000000000000001477626554400163525ustar00rootroot00000000000000uwsgi-2.0.29/vhosttest/flask001/app1.py000066400000000000000000000001461477626554400175660ustar00rootroot00000000000000from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello World!" uwsgi-2.0.29/vhosttest/flask002/000077500000000000000000000000001477626554400163535ustar00rootroot00000000000000uwsgi-2.0.29/vhosttest/flask002/app2.py000066400000000000000000000001571477626554400175720ustar00rootroot00000000000000from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello World! app2 !!!" uwsgi-2.0.29/vhosttest/flask003/000077500000000000000000000000001477626554400163545ustar00rootroot00000000000000uwsgi-2.0.29/vhosttest/flask003/app3.py000066400000000000000000000001531477626554400175700ustar00rootroot00000000000000from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello World! app3" uwsgi-2.0.29/vhosttest/flask004/000077500000000000000000000000001477626554400163555ustar00rootroot00000000000000uwsgi-2.0.29/vhosttest/flask004/app4.py000066400000000000000000000001531477626554400175720ustar00rootroot00000000000000from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello World! app4" uwsgi-2.0.29/vhosttest/flask005/000077500000000000000000000000001477626554400163565ustar00rootroot00000000000000uwsgi-2.0.29/vhosttest/flask005/app5.py000066400000000000000000000001531477626554400175740ustar00rootroot00000000000000from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello World! app5" uwsgi-2.0.29/vhosttest/nginx.conf000066400000000000000000000013461477626554400170270ustar00rootroot00000000000000 worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; gzip on; upstream uwsgi_server { server 127.0.0.1:3031; } include uwsgi_params; uwsgi_param UWSGI_FILE $app; uwsgi_param UWSGI_PYHOME $virtualenv; server { listen 8026; server_name flask001; set $app vhosttest/flask001/app1.py; set $virtualenv vhosttest/venv001; location / { uwsgi_pass uwsgi_server; } } server { listen 8026; server_name flask002; set $app vhosttest/flask002/app2.py; set $virtualenv vhosttest/venv001; location / { uwsgi_pass uwsgi_server; } } }