Commit Graph

1283 Commits

Author SHA1 Message Date
Valentin Bartenev
a98de7f705 Added a "fallback" option to be used with the "share" action.
It allows proceeding to another action if a file isn't available.

An example:

    {
        "share": "/data/www/",

        "fallback": {
            "pass": "applications/php"
        }
    }

In the example above, an attempt is made first to serve a request with
a file from the "/data/www/" directory.  If there's no such file, the
request is passed to the "php" application.

Fallback actions may be nested:

    {
        "share": "/data/www/",

        "fallback": {
            "share": "/data/cache/",

            "fallback": {
                "proxy": "http://127.0.0.1:9000"
            }
        }
    }
2020-03-03 20:37:47 +03:00
Valentin Bartenev
a60f856ce2 Improved validation of the "action" object.
Now it enforces the mutual exclusivity of "pass", "proxy", and "share" options.
2020-03-03 20:37:47 +03:00
Tiago Natel de Moura
f99d20ad39 PHP: optimization to avoid surplus chdir(2) calls.
For each request, the worker calls the php_execute_script function
from libphp that changes to the script directory before doing its
work and then restores the process directory before returning.  The
chdir(2) calls it performs are unnecessary in Unit design.  In simple
benchmarks, profiling shows that the chdir syscall code path (syscall,
FS walk, etc.) is where the CPU spends most of its time.

PHP SAPI semantics requires the script to be run from the script
directory.  In Unit's PHP implementation, we have two use cases:

- script
- arbitrary path

The "script" configuration doesn't have much need for a working
directory change: it can be changed once at module initialization.
The module needs to chdir again only if the user's PHP script also
calls chdir to switch to another directory during execution.

If "script" is not used in Unit configuration, we must ensure the
script is run from its directory (thus calling chdir before exec),
but there's no need to restore the working directory later.

Our implementation disables mandatory chdir calls with the SAPI
option SAPI_OPTION_NO_CHDIR, instead calling chdir only when needed.

To detect the user's calls to chdir, a simple "unit" extension is
added that hooks the built-in chdir() PHP call.
2020-03-03 14:38:08 +00:00
Max Romanov
9e295fa314 Fixing request_app_link reference counting for delayed requests.
Router built with debug may stop with assertion during stalled requests
re-schedule.  This was caused by missing reference counting increment
before nxt_router_port_select() call.
2020-03-03 18:28:26 +03:00
Max Romanov
c74f3a6c56 Java: fixing Spring applications start.
This closes #403 issue on GitHub.
2020-03-03 18:28:20 +03:00
Max Romanov
004ab48a9e Node.js: fixing x86 warning about the signed/unsigned comparison. 2020-03-03 18:28:16 +03:00
Tiago Natel de Moura
98c0ce6cc4 PHP: fixed php >= 7.4 with zts enabled. 2020-02-25 15:55:31 +00:00
Valentin Bartenev
d198a105eb Configuration: removing UTF-8 BOM from the input JSON.
Some editors can add it to JSON files.
2020-02-20 17:58:24 +03:00
Valentin Bartenev
044b3afcda Configuration: stripping comments from the input JSON.
This allows to have JavaScript-like comments in the uploading JSON.
2020-02-20 17:58:24 +03:00
Tiago Natel de Moura
29d8b34244 Kept the value of c->socket.read_handler while data is available.
This closes #370 in GitHub.
2020-02-05 13:12:31 +00:00
Max Romanov
7c38650cd1 Removing duplicate macro definitions.
This issue was introduced in 2c7f79bf0a1f.
2020-02-04 11:39:16 +03:00
Max Romanov
8eba2e5c3d Initializing local buffer ctx_impl field for correct release.
Uninitialized ctx_impl field may cause crash in application process.

To reproduce the issue, need to trigger shared memory buffer send error on
application side.  In our case, send error caused by router process crash.

This issue was introduced in 2c7f79bf0a1f.
2020-02-03 11:21:21 +03:00
Max Romanov
7ea9ebc55a Fixed req_app_link reference counting on cancellation.
Re-scheduled req_app_link structures should have use_count exactly equal
to the number of references from the application and port list.  However,
there's one extra usage decrement that occurs after the req_app_link is
created because the use_count is initialised as 1.

This patch removes all excess instances of the usage decrement that caused
preliminary req_app_link release and router process crash.

To reproduce the issue need to cause request rescheduling between 2 app
processes.

This issue was introduced in 61e9f23a566d.
2020-02-03 11:20:59 +03:00
Max Romanov
8c0f2cebf5 Storing pointer to next buffer in chain before free the buffer.
This is required to avoid dereference of freed memory.

Found by Coverity (CID 353372).
2020-02-03 11:14:14 +03:00
Max Romanov
51120e06e3 Added missing stream argument to error message.
Found by Coverity (CID 353386).
2020-02-03 11:14:06 +03:00
Max Romanov
224549a578 Freeing memory allocated for engine structure in case of error.
Found by Coverity (CID 353389).
2020-02-03 11:13:55 +03:00
Valentin Bartenev
f860c20a96 PHP: added check for the ".php" extension.
A check for the ".php" extension is added to prevent execution of files
with arbitrary extensions in cases where "index" and "script" options
aren't used.
2020-01-28 19:18:26 +03:00
Axel Duch
4eb2d3086b Fixed missing IPv6 checking in route-addr and an unused variable.
This closes #363 issue on Github.
Thanks to to 洪志道 (Hong Zhi Dao).
2020-01-28 15:05:12 +00:00
Max Romanov
1451090d85 Node.js: suppress compilation warning. 2020-01-28 17:06:57 +03:00
Max Romanov
2f8b243fa4 Ruby: changing callback functions prototype for v2.7.
This closes #371 issue on GitHub.
2020-01-28 16:59:12 +03:00
Tiago Natel de Moura
eced72ba25 Using the 64-bit Linux capability mode when available.
For backward compatibility, the Linux capabilities macros exposes v1 semantics
(32-bit) by default.  We probe the version at runtime (because of pre-compiled
binaries) but the kernel syscall API is conservative and it doesn't return a
64-bit capability version if the input version is v1.

This patch suppress the kernel > 5.0 dmesg log below:

  capability: warning: 'unitd' uses 32-bit capabilities (legacy support in use)
2019-12-16 17:12:09 +00:00
Axel Duch
1a76371499 Router: introducing routing on listener address. 2019-12-24 13:59:58 +00:00
Axel Duch
8677bf8d41 Router: introducing routing on client address. 2019-12-24 13:58:10 +00:00
Max Romanov
763bdff401 Node.js: implementing output message drain using SHM_ACK feature.
ServerResponse.write() method tries to write data buffer using libunit
and stores buffers to write in a Server-wide output queue, which is
processed in response to SHM_ACK message from router.

As a side effect 'drain' event implemented and socket.writable flag
reflect current state.
2019-12-24 18:04:17 +03:00
Max Romanov
df7caf4650 Introducing port messages to notify about out of shared memory.
- OOSM (out of shared memory).  Sent by application process to router
  when application reaches the limit of allocated shared memory and
  needs more.
- SHM_ACK.  Sent by router to application when the application's shared
  memory is released and the OOSM flag is enabled for the segment.

This implements blocking mode (the library waits for SHM_ACK in case of
out of shared memory condition and retries allocating the required memory
amount) and non-blocking mode (the library notifies the application that
it's out of shared memory and returns control to the application module
that sets up the output queue and puts SHM_ACK in the main message loop).
2019-12-24 18:04:13 +03:00
Max Romanov
64f649f990 Adding "limits/shm" configuration validation and parsing. 2019-12-24 18:04:09 +03:00
Max Romanov
429c5a1c54 Renaming nxt_unit_mmap_buf_remove to nxt_unit_mmap_buf_unlink.
The function unchains the buffer from the buffer's linked list.
2019-12-24 18:04:05 +03:00
Max Romanov
806b3945fe Introducing write tail reference to avoid buffer chain iteration. 2019-12-24 18:04:00 +03:00
Max Romanov
faeb73a65e Using non-shared memory buffers for small messages.
Current shared memory buffer implementation uses fixed-size memory blocks,
allocating at least 16384 bytes.  When application sends data in a large
number of small chunks, it makes sense to buffer them or use plain
memory buffers to improve performance and reduce memory footprint.

This patch introduces minimum size limit (1024 bytes) for shared
memory buffers.
2019-12-24 18:03:56 +03:00
Max Romanov
f5a2984acf Go: moving source files to the root of the project.
This patch includes packaging changes related to files move.
2019-12-24 17:59:52 +03:00
Max Romanov
823f658c77 Go: linking against libunit. 2019-12-24 17:59:37 +03:00
Valentin Bartenev
51af6ac0a1 Python: pre-creation of objects for string constants.
This is an optimization to avoid creating them at runtime on each request.
2019-12-23 21:14:14 +03:00
Tiago Natel
411daeaa53 Isolation: allowed the use of credentials with unpriv userns.
The setuid/setgid syscalls requires root capabilities but if the kernel
supports unprivileged user namespace then the child process has the full
set of capabilities in the new namespace, then we can allow setting "user"
and "group" in such cases (this is a common security use case).

Tests were added to ensure user gets meaningful error messages for
uid/gid mapping misconfigurations.
2019-12-06 16:52:50 +00:00
Tiago Natel
ed2492a66a Moved credential-related code to nxt_credential.c.
This is required to avoid include cycles, as some nxt_clone_* functions
depend on the credential structures, but nxt_process depends on clone
structures.
2019-12-06 13:28:05 +00:00
Tiago Natel
417cc7be7c Refactor of process init.
Introduces the functions nxt_process_init_create() and
nxt_process_init_creds_set().
2019-11-26 16:26:24 +00:00
Tiago Natel
2f23923e44 Changed the group listing to run unprivileged when possible.
Now the nxt_user_groups_get() function uses getgrouplist(3) when available
(except MacOS, see below).  For some platforms, getgrouplist() supports
a method of probing how much groups the user has but the behavior is not
consistent.  The method used here consists of optimistically trying to get up
to min(256, NGROUPS_MAX) groups; only if ngroups returned exceeds the original
value, we do a second call.  This method can block main's process if LDAP/NDIS+
is in use.

MacOS has getgrouplist(3) but it's buggy.  It doesn't update ngroups if the
value passed is smaller than the number of groups the user has.  Some
projects (like Go stdlib) call getgrouplist() in a loop, increasing ngroups
until it exceeds the number of groups user belongs to or fail when a limit
is reached.  For performance reasons, this is to be avoided and MacOS is
handled in the fallback implementation.

The fallback implementation is the old Unit approach.  It saves main's
user groups (getgroups(2)) and then calls initgroups(3) to load application's
groups in main, then does a second getgroups(2) to store the gids and restore
main's groups in the end.  Because of initgroups(3)' call to setgroups(2),
this method requires root capabilities.  In the case of OSX, which has
small NGROUPS_MAX by default (16), it's not possible to restore main's groups
if it's large; if so, this method fallbacks again: user_cred gids aren't
stored, and the worker process calls initgroups() itself and may block for
some time if LDAP/NDIS+ is in use.
2019-11-26 16:15:23 +00:00
Max Romanov
4eecf1cb6a Refactoring reference counting of req_app_link.
The reason for the change is that the req_app_link reference count
was incorrect if the application crashed at start; in this case,
the nxt_request_app_link_update_peer() function was never called.

This closes #332 issue on GitHub.
2019-11-26 17:14:53 +03:00
Valentin Bartenev
c2976fb337 Python: avoiding buffering of exception backtraces.
A quote from the Python 3 documentation:

 | When interactive, stdout and stderr streams are line-buffered.
 | Otherwise, they are block-buffered like regular text files.

As a result, if an exception occurred and PyErr_Print() was called, its output
could be buffered but not printed to the log for a while (ultimately, until
the interpreter finalization).  If the application process crashed shortly,
the backtrace was completely lost.

Buffering can be disabled by redefining the sys.stderr stream object.
However, interference with standard environment objects was deemed undesirable.
Instead, sys.stderr.flush() is called every time after printing exceptions.
A potential advantage here is that lines from backtraces won't be mixed
with other lines in the log.
2019-11-14 17:48:48 +03:00
Valentin Bartenev
4e41d90006 Python: removed wrong PyErr_Print() call.
PyCallable_Check() doesn't produce errors.

The needless call was introduced in fdd6ed28e3b9.
2019-11-14 17:48:48 +03:00
Valentin Bartenev
b3db7a30c0 Python: optimized response object close() calling.
PyObject_HasAttrString() is just a wrapper over PyObject_GetAttrString(),
while PyObject_CallMethod() calls it as the first step.  As a result,
PyObject_GetAttrString() was called twice if close() was present.

To get rid of PyObject_HasAttrString() while keeping the same behaviour,
the PyObject_CallMethod() call has been decomposed into separate calls of
PyObject_GetAttrString() and PyObject_CallFunction().
2019-11-14 17:48:48 +03:00
Valentin Bartenev
75c2c23bb6 Python: fixed an object leak when response close() is called.
On success, PyObject_CallMethod() returns a new reference to
the result of the call, which previously got lost.

Also, error logging on failure was added.

The issue was introduced by b0148ec28c4d.
2019-11-14 17:48:48 +03:00
Valentin Bartenev
c667bb446d Python: refactored nxt_python_request_handler(). 2019-11-14 17:48:48 +03:00
Valentin Bartenev
cd6cb02be0 Python: fixed potential object leak in case of allocation error. 2019-11-14 17:48:48 +03:00
Valentin Bartenev
e9429324c2 Python: improved error handling if response object isn't iterable.
According to the documentation, PyObject_GetIter():

 | Raises TypeError and returns NULL if the object cannot be iterated.

Previously, this exception wasn't printed or cleared and remained unhandled.
2019-11-14 17:48:48 +03:00
Valentin Bartenev
e189d0a96c Python: fixed handling of errors on response object iteration.
According to the documentation, PyIter_Next():

 | If there are no remaining values, returns NULL with no exception set.
 | If an error occurs while retrieving the item, returns NULL and passes
 | along the exception.

Previously, this exception wasn't properly handled and the response was
finalized as successful.

This issue was introduced in b0148ec28c4d.

A check for PyErr_Occurred() located in the code below might print this
traceback or occasionally catch an exception from one of the two response
close() calls.

Albeit that exceptions from the close() calls also need to be catched,
it's clear that this particular check wasn't supposed to do so.  This is
another issue and it will be fixed later.
2019-11-14 17:48:48 +03:00
Igor Sysoev
02e197e978 Processing inconsistent proxied response length.
Keepalive connection is disabled if upstream response length
differs from specified in the "Content-Length" field value.
2019-11-14 16:40:02 +03:00
Igor Sysoev
ddde9c23cf Initial proxy support. 2019-11-14 16:39:54 +03:00
Igor Sysoev
57e326b411 Introduced chained buffer completion handlers. 2019-11-14 16:39:48 +03:00
Igor Sysoev
643c433f8e Using event engine memory buffers in HTTP/1 layer. 2019-11-14 16:39:48 +03:00
Igor Sysoev
1ec6353733 Introduced event engine memory buffers. 2019-11-14 16:39:48 +03:00