Commit Graph

2329 Commits

Author SHA1 Message Date
Zhidao HONG
4f16479482 HTTP: generalized uri encoding.
No functional changes.
2022-05-19 21:18:25 +08:00
Andrei Zeliankou
0d48fe73c4 Unit 1.27.0 release. 2022-06-02 13:37:14 +01:00
Andrei Zeliankou
3d1fa29f1d Generated Dockerfiles for Unit 1.27.0. 2022-06-02 12:31:55 +00:00
Andrei Zeliankou
cf9b5bdb35 Added version 1.27.0 CHANGES. 2022-06-02 13:30:52 +01:00
Andrei Zeliankou
bd80039e07 Node.js: fixed ES modules format in loader.mjs.
Before Node.js v16.14.0 the "format" value in defaultResolve
was ignored so error was hidden.  For more information see:
https://github.com/nodejs/node/pull/40980
2022-06-02 11:48:27 +01:00
Konstantin Pavlov
3d53bba5b3 Packaging: added support for RHEL 9. 2022-05-31 18:35:39 +04:00
Andrei Zeliankou
caa05887ff Logging a NULL pointer instead of passing it in the memcpy(). 2022-06-01 16:40:34 +01:00
Andrei Zeliankou
161230b955 Tests: improved test for $request_uri variable. 2022-06-01 16:40:27 +01:00
Artem Konev
0d5d81b271 Fixed minor issues in "changes.xml". 2022-06-01 14:54:13 +01:00
Andrei Zeliankou
880c8e51c3 Tests: removed deprecated ssl.PROTOCOL_TLSv1_2 constant. 2022-06-01 00:15:15 +01:00
Alejandro Colomar
aee8b9bfb2 Tests: Added tests for $request_uri. 2022-05-31 12:41:11 +02:00
Alejandro Colomar
9bf614cd08 Var: Added $request_uri (as in NGINX).
This supports a new variable $request_uri that contains the path
and the query (See RFC 3986, section 3).  Its contents are percent
encoded.  This is useful for example to redirect HTTP to HTTPS:

{
    "return": "301",
    "location": "https://$host$request_uri"
}

When <http://example.com/foo%23bar?baz> is requested, the server
redirects to <https://example.com/foo%23bar?baz>.

===

Testing:

//diff --git a/src/nxt_http_return.c b/src/nxt_http_return.c
//index 82c9156..adeb3a1 100644
//--- a/src/nxt_http_return.c
//+++ b/src/nxt_http_return.c
//@@ -196,6 +196,7 @@ nxt_http_return_send_ready(nxt_task_t *task,
    void *obj, void *data)
//         field->value = ctx->encoded.start;
//         field->value_length = ctx->encoded.length;
//     }
//+    fprintf(stderr, "ALX: target[%1$i]: <%2$.*1$s>\n",
    (int)r->target.length, r->target.start);
//
//     r->state = &nxt_http_return_send_state;
//

{
	"listeners": {
		"*:81": {
			"pass": "routes/ru"
		}
	},

	"routes": {
		"ru": [{
			"action": {
				"return": 301,
				"location": "$request_uri"
			}
		}]
	}
}

$ curl -i http://localhost:81/*foo%2Abar?baz#arg
HTTP/1.1 301 Moved Permanently
Location: /*foo%2Abar?baz
Server: Unit/1.27.0
Date: Mon, 30 May 2022 16:04:30 GMT
Content-Length: 0

$ sudo cat /usr/local/unit.log | grep ALX
ALX: target[15]: </*foo%2Abar?baz>
2022-05-31 12:40:02 +02:00
Alejandro Colomar
8027e7ce0f Tests: added tests for "index" (string) option. 2022-05-30 12:42:18 +02:00
Alejandro Colomar
9af5f36951 Static: supporting new "index" option.
This supports a new option "index" that configures a custom index
file name to be served when a directory is requested.  This
initial support only allows a single fixed string.  An example:

{
	"share": "/www/data/static/$uri",
	"index": "lookatthis.htm"
}

When <example.com/foo/bar/> is requested,
</www/data/static/foo/bar/lookatthis.html> is served.

Default is "index.html".

===

nxt_conf_validator.c:

Accept "index" as a member of "share", and make sure it's a string.

===

I tried this feature in my own computer, where I tried the
following:

- Setting "index" to "lookatthis.htm", and check that the correct
  file is being served (check both a different name and a
  different extension).
- Not setting "index", and check that <index.html> is being
  served.
- Settind "index" to an array of strings, and check that the
  configuration fails:

{
	"error": "Invalid configuration.",
	"detail": "The \"index\" value must be a string, but not an array."
}
2022-05-30 12:42:18 +02:00
Konstantin Pavlov
237ddbe177 Packaging: Go: use GO111MODULE=auto in build instructions. 2022-05-26 10:52:58 +04:00
Alejandro Colomar
02f50533c4 Static: returning 404 when "index" is a non-regular file.
Before this patch, if "index" was a file, but not a regular file
nor a directory, so it may have been for example a FIFO, Unit
returned 404.  But if "index" was a directory, Unit returned 301.

For consistency, this patch makes Unit return 404 for every
non-regular file, including directories.
2022-05-26 19:31:08 +02:00
Alejandro Colomar
27ca67f0df Added const to remove unnecessary casts.
Casts are usually very dangerous, disabling most compiler warnings
and basically removing type safety.  This change adds 'const' to a
pointer where we don't need to write, improving type safety, and
that also allows removing some casts.
2022-05-26 14:11:12 +02:00
Zhidao HONG
6271479610 HTTP: generalized argument and cookie parsing.
No functional changes.
2022-05-18 21:18:40 +08:00
Konstantin Pavlov
3e06ae3b34 Packages: ship README.md and CONTRIBUTING.md. 2022-05-16 17:22:40 +04:00
Alejandro Colomar
7662ec5f1b Wrapped debug code in '#if (NXT_DEBUG)'. 2022-05-17 12:41:18 +02:00
Alejandro Colomar
ba20fa3939 Fixed memcpy(dest, NULL, 0) Undefined Behavior.
nxt_str_null() setted the loc.start pointer to NULL, which was
being passed to memcpy(3) through nxt_debug().  That caused
Undefined Behavior, so we now pass an empty string.
2022-05-17 12:39:41 +02:00
Konstantin Pavlov
b512eff4ac Packages: added Ubuntu 22.04 "jammy" support. 2022-05-05 13:25:52 +04:00
Alejandro Colomar
c60f678485 Tests: Added tests for empty "location". 2022-05-16 12:57:37 +02:00
Alejandro Colomar
7066acb2ce Supporting empty Location URIs.
An empty string in Location was being handled specially by not sending a
Location header.  This may occur after variable resolution, so we need to
consider this scenario.

The obsolete RFC 2616 defined the Location header as consisting of an absolute
URI <https://www.rfc-editor.org/rfc/rfc2616#section-14.30>, which cannot be an
empty string.  However, the current RFC 7231 allows the Location to be a
relative URI <https://www.rfc-editor.org/rfc/rfc7231#section-7.1.2>, and a
relative URI may be an empty string <https://stackoverflow.com/a/43338457>.

Due to these considerations, this patch allows sending an empty Location header
without handling this case specially.  This behavior will probably be more
straightforward to users, too.  It also simplifies the code, which is now more
readable, fast, and conformant to the current RFC.  We're skipping an
allocation at request time in a common case such as "action": {"return": 404}
2022-05-16 12:57:37 +02:00
Artem Konev
bc639b50d1 Deleted extra line in README.md. 2022-05-16 11:16:08 +01:00
Alejandro Colomar
5302faace2 Renamed nxt_http_static_ctx_t field 'index' to 'share_idx'.
Having a configurable index filename will require adding an index
field to this structure.  The most natural name for that field is
'index', so the current index field should be renamed to allow for
that.  A sensible name is 'share_idx', since it's the index of the
shares array in 'nxt_http_static_conf_t'.

Instead of 'share_index' I opted for the shorter 'share_idx'.
Also, when 'index' allows an array of filenames in a following
commit, another similar variable 'index_idx' should be created,
and having a different prefix and suffix seems more readable than
for example 'index_index'.
2022-05-16 10:27:07 +02:00
Artem Konev
fa42d858a2 Adding GitHub-styled README and CONTRIBUTING files in Markdown. 2022-05-13 17:13:23 +01:00
Andrei Zeliankou
de0a0beb83 Tests: added tests for Ruby stream IO.close(). 2022-05-13 15:43:57 +01:00
Zhidao HONG
5883a2670f Ruby: added stream IO "close" required by Rack specification.
This closes #654 issue on Github.
2022-05-13 19:33:40 +08:00
Konstantin Pavlov
1fe389c2e2 Regenerated Dockerfiles. 2022-05-11 13:06:17 +04:00
Konstantin Pavlov
967fa8f78a Docker: bumped language versions. 2022-05-11 12:59:39 +04:00
Sergey Kandaurov
6cfa1c3970 Using SSL_OP_IGNORE_UNEXPECTED_EOF.
A new behaviour was introduced in OpenSSL 1.1.1e, when a peer does not send
close_notify before closing the connection.  Previously, it was to return
SSL_ERROR_SYSCALL with errno 0, known since at least OpenSSL 0.9.7, and is
handled gracefully in unitd.  Now it returns SSL_ERROR_SSL with a distinct
reason SSL_R_UNEXPECTED_EOF_WHILE_READING ("unexpected eof while reading").
This leads to critical errors seen in nginx within various routines such as
SSL_do_handshake(), SSL_read(), SSL_shutdown().  The behaviour was restored
in OpenSSL 1.1.1f, but presents in OpenSSL 3.0 by default.

Use of the SSL_OP_IGNORE_UNEXPECTED_EOF option added in OpenSSL 3.0 allows
setting a compatible behaviour to return SSL_ERROR_ZERO_RETURN:
https://git.openssl.org/?p=openssl.git;a=commitdiff;h=09b90e0

See for additional details: https://github.com/openssl/openssl/issues/11381
2022-05-12 12:04:54 +04:00
Sergey Kandaurov
5665838b68 Using OPENSSL_SUPPRESS_DEPRECATED.
The macro is used to suppress deprecation warnings with OpenSSL 3.0.

Unlike OPENSSL_API_COMPAT, it works well with OpenSSL built with no-deprecated.
In particular, it doesn't unhide various macros in OpenSSL includes, which are
meant to be hidden under OPENSSL_NO_DEPRECATED.
2022-05-12 12:04:47 +04:00
Andrei Zeliankou
1bffba6d1e Tests: added test for "SCRIPT_NAME" variable in Ruby. 2022-05-10 01:53:23 +01:00
Zhidao HONG
0032543fa6 Ruby: added the Rack environment parameter "SCRIPT_NAME". 2022-03-09 13:29:43 +08:00
Andrei Zeliankou
03a7701133 Tests: added more tests with reconfiguration. 2022-05-09 10:14:29 +01:00
Alejandro Colomar
9c276d4d60 Added .gitignore. 2022-05-03 12:41:36 +02:00
Alejandro Colomar
952bcc50bf Fixed #define style.
We had a mix of styles for declaring function-like macros:

Style A:
 #define                    \
 foo()                      \
     do {                   \
         ...                \
     } while (0)

Style B:
 #define foo()              \
     do {                   \
         ...                \
     } while (0)

We had a similar number of occurences of each style:

 $ grep -rnI '^\w*(.*\\' | wc -l
 244
 $ grep -rn 'define.*(.*)' | wc -l
 239

(Those regexes aren't perfect, but a very decent approximation.)

Real examples:

 $ find src -type f | xargs sed -n '/^nxt_double_is_zero/,/^$/p'
 nxt_double_is_zero(f)                                                         \
     (fabs(f) <= FLT_EPSILON)

 $ find src -type f | xargs sed -n '/define nxt_http_field_set/,/^$/p'
 #define nxt_http_field_set(_field, _name, _value)                             \
     do {                                                                      \
         (_field)->name_length = nxt_length(_name);                            \
         (_field)->value_length = nxt_length(_value);                          \
         (_field)->name = (u_char *) _name;                                    \
         (_field)->value = (u_char *) _value;                                  \
     } while (0)

I'd like to standardize on a single style for them, and IMO,
having the identifier in the same line as #define is a better
option for the following reasons:

- Programmers are used to `#define foo() ...` (readability).
- One less line of code.
- The program for finding them is really simple (see below).

 function grep_ngx_func()
 {
     if (($# != 1)); then
         >&2 echo "Usage: ${FUNCNAME[0]} <func>";
         return 1;
     fi;

     find src -type f \
     | grep '\.[ch]$' \
     | xargs grep -l "$1" \
     | sort \
     | xargs pcregrep -Mn "(?s)^\$[\w\s*]+?^$1\(.*?^}";

     find src -type f \
     | grep '\.[ch]$' \
     | xargs grep -l "$1" \
     | sort \
     | xargs pcregrep -Mn "(?s)define $1\(.*?^$" \
     | sed -E '1s/^[^:]+:[0-9]+:/&\n\n/';
 }

 $ grep_ngx_func
 Usage: grep_ngx_func <func>

 $ grep_ngx_func nxt_http_field_set
 src/nxt_http.h:98:

 #define nxt_http_field_set(_field, _name, _value)                             \
     do {                                                                      \
         (_field)->name_length = nxt_length(_name);                            \
         (_field)->value_length = nxt_length(_value);                          \
         (_field)->name = (u_char *) _name;                                    \
         (_field)->value = (u_char *) _value;                                  \
     } while (0)

 $ grep_ngx_func nxt_sprintf
 src/nxt_sprintf.c:56:

 u_char * nxt_cdecl
 nxt_sprintf(u_char *buf, u_char *end, const char *fmt, ...)
 {
     u_char   *p;
     va_list  args;

     va_start(args, fmt);
     p = nxt_vsprintf(buf, end, fmt, args);
     va_end(args);

     return p;
 }

................
Scripted change:
................

$ find src -type f \
  | grep '\.[ch]$' \
  | xargs sed -i '/define *\\$/{N;s/ *\\\n/ /;s/        //}'
2022-05-03 12:11:14 +02:00
Alejandro Colomar
d929fbe1a4 Tests: Added tests for variables in "location". 2022-04-28 20:40:01 +02:00
Alejandro Colomar
6d017dfbe4 Tests: Changed tests to accept variables in "location". 2022-04-28 20:40:01 +02:00
Alejandro Colomar
6fb7777ce7 Supporting variables in "location".
............
Description:
............

Before this commit, the encoded URI could be calculated at
configuration time.  Now, since variables can only be resolved at
request time, we have different situations:

- "location" contains no variables:

  In this case, we still encode the URI in the conf structure, at
  configuration time, and then we just copy the resulting string
  to the ctx structure at request time.

- "location" contains variables:

  In this case, we compile the var string at configure time, then
  when we resolve it at request time, and then we encode the
  string.

In both cases, as was being done before, if the string is empty,
either before or after resolving variables, we skip the encoding.

...........
Usefulness:
...........

An example of why this feature may be useful is redirecting HTTP
to HTTPS with something like:

"action": {
    "return": 301,
    "location": "https://${host}${uri}"
}

.....
Bugs:
.....

This feature conflicts with the relevant RFCs in the following:

'$' is used for Unit variables, but '$' is a reserved character in
a URI, to be used as a sub-delimiter.  However, it's almost never
used as that, and in fact, other parts of Unit already conflict
with '$' being a reserved character for use as a sub-delimiter, so
this is at least consistent in that sense.  VBart suggested an
easy workaround if we ever need it: adding a variable '$sign'
which resolves to a literal '$'.

......
Notes:
......

An empty string is handled as if "location" wasn't specified at
all, so no Location header is sent.

This is incorrect, and the code is slightly misleading.

The Location header consists of a URI-reference[1], which might be
a relative one, which itself might consist of an empty string[2].

[1]: <https://www.rfc-editor.org/rfc/rfc7231#section-7.1.2>
[2]: <https://stackoverflow.com/a/43338457>

Now that we have variables, it's more likely that an empty
Location header will be requested, and we should handle it
correctly.

I think in a future commit we should modify the code to allow
differentiating between an unset "location" and an empty one,
which should be treated as any other "location" string.

.................
Testing (manual):
.................

{
  "listeners": {
    "*:80": {
      "pass": "routes/str"
    },
    "*:81": {
      "pass": "routes/empty"
    },
    "*:82": {
      "pass": "routes/var"
    },
    "*:83": {
      "pass": "routes/enc-str"
    },
    "*:84": {
      "pass": "routes/enc-var"
    }
  },
  "routes": {
    "str": [
      {
        "action": {
          "return": 301,
          "location": "foo"
        }
      }
    ],
    "empty": [
      {
        "action": {
          "return": 301,
          "location": ""
        }
      }
    ],
    "var": [
      {
        "action": {
          "return": 301,
          "location": "$host"
        }
      }
    ],
    "enc-str": [
      {
        "action": {
          "return": 301,
          "location": "f%23o#o"
        }
      }
    ],
    "enc-var": [
      {
        "action": {
          "return": 301,
          "location": "f%23o${host}#o"
        }
      }
    ]
  }
}

$ curl --dump-header - localhost:80
HTTP/1.1 301 Moved Permanently
Location: foo
Server: Unit/1.27.0
Date: Thu, 07 Apr 2022 23:30:06 GMT
Content-Length: 0

$ curl --dump-header - localhost:81
HTTP/1.1 301 Moved Permanently
Server: Unit/1.27.0
Date: Thu, 07 Apr 2022 23:30:08 GMT
Content-Length: 0

$ curl --dump-header - localhost:82
HTTP/1.1 301 Moved Permanently
Location: localhost
Server: Unit/1.27.0
Date: Thu, 07 Apr 2022 23:30:15 GMT
Content-Length: 0

$ curl --dump-header - -H "Host: bar" localhost:82
HTTP/1.1 301 Moved Permanently
Location: bar
Server: Unit/1.27.0
Date: Thu, 07 Apr 2022 23:30:23 GMT
Content-Length: 0

$ curl --dump-header - -H "Host: " localhost:82
HTTP/1.1 301 Moved Permanently
Server: Unit/1.27.0
Date: Thu, 07 Apr 2022 23:30:29 GMT
Content-Length: 0

$ curl --dump-header - localhost:83
HTTP/1.1 301 Moved Permanently
Location: f%23o#o
Server: Unit/1.27.0
Date: Sat, 09 Apr 2022 11:22:23 GMT
Content-Length: 0

$ curl --dump-header - -H "Host: " localhost:84
HTTP/1.1 301 Moved Permanently
Location: f%23o#o
Server: Unit/1.27.0
Date: Sat, 09 Apr 2022 11:22:44 GMT
Content-Length: 0

$ curl --dump-header - -H "Host: alx" localhost:84
HTTP/1.1 301 Moved Permanently
Location: f%23oalx#o
Server: Unit/1.27.0
Date: Sat, 09 Apr 2022 11:22:52 GMT
Content-Length: 0

$ curl --dump-header - -H "Host: a#l%23x" localhost:84
HTTP/1.1 301 Moved Permanently
Location: f%2523oa#l%2523x%23o
Server: Unit/1.27.0
Date: Sat, 09 Apr 2022 11:23:09 GMT
Content-Length: 0

$ curl --dump-header - -H "Host: b##ar" localhost:82
HTTP/1.1 301 Moved Permanently
Location: b#%23ar
Server: Unit/1.27.0
Date: Sat, 09 Apr 2022 11:25:01 GMT
Content-Length: 0
2022-04-28 20:40:01 +02:00
Alejandro Colomar
60a584cfab Workarounded Clang bug triggered by Ruby.
Add -fdeclspec to NXT_RUBY_CFLAGS for Clang, if it's available.

Clang incorrectly reports 1 for __has_declspec_attribute(x) in
some cases, such as MacOS or Cygwin.  That causes ruby code to
break.  ruby added -fdeclspec to their CFLAGS in 2019 to
workaround this bug, since it enables __declspec() and therefore,
the compiler behavior matches what it reports.

Since we don't know what are all the architectures that trigger
the clang bug, let's add the flag for all of them (especially
since it should be harmless).

Add this workaround only at the time of configuring the ruby
module.  This way we don't clutter the global NXT_CFLAGS with an
unnecessary flag.

Link: unit bug <https://github.com/nginx/unit/issues/653>
Link: ruby bug <https://bugs.ruby-lang.org/issues/18616>
Link: LLVM bug <https://github.com/llvm/llvm-project/issues/49958>
Commit: LLVM: Add -fdeclspec <d170c4b57a91adc74ca89c6d4af616a00323b12c>
Commit: ruby: Use -fdeclspec <0958e19ffb047781fe1506760c7cbd8d7fe74e57>
2022-04-28 20:02:30 +02:00
Alejandro Colomar
0b79735b50 Added NXT_MAYBE_UNUSED for __attribute__((__unused__)).
When testing some configurations of compilers and OSes, I noticed
that clang(1) 13 on Debian caused a function to be compiled but
unused, and the compiler triggered a compile error.

To avoid that error, use __attribute__((__unused__)).  Let's call
our wrapper NXT_MAYBE_UNUSED, since it describes itself more
precisely than the GCC attribute name.  It's also the name that
C2x (likely C23) has given to the standard attribute, which is
[[maybe_unused]], so it's also likely to be more readable because
of that name being in ISO C.
2022-04-27 01:14:22 +02:00
Alejandro Colomar
a3d19f71a2 Fixed indentation.
Some lines (incorrectly) had an indentation of 3 or 5, or 7 or 9,
or 11 or 13, or 15 or 17 spaces instead of 4, 8, 12, or 16.  Fix them.

Found with:

$ find src -type f | xargs grep -n '^   [^ ]';
$ find src -type f | xargs grep -n '^     [^ *]';
$ find src -type f | xargs grep -n '^       [^ ]';
$ find src -type f | xargs grep -n '^         [^ *]';
$ find src -type f | xargs grep -n '^           [^ +]';
$ find src -type f | xargs grep -n '^             [^ *+]';
$ find src -type f | xargs grep -n '^               [^ +]';
$ find src -type f | xargs grep -n '^                 [^ *+]';
2022-04-26 12:38:48 +02:00
Alejandro Colomar
bce0f432c4 Removed special cases for non-NXT_CONF_VALUE_ARRAY.
The previous commit added more generic APIs for handling
NXT_CONF_VALUE_ARRAY and non-NXT_CONF_VALUE_ARRAY together.
Modify calling code to remove special cases for arrays and
non-arrays, taking special care that the path for non arrays is
logically equivalent to the previous special cased code.
Use the now-generic array code only.
2022-04-26 12:38:48 +02:00
Alejandro Colomar
e525605d05 Added new array APIs that also work with non-arrays.
Similar to how C pointers to variables can always be considered as
pointers to the first element of an array of size 1 (see the
following code for an example of how they are equivalent),
treating non-NXT_CONF_VALUE_ARRAY as if they were
NXT_CONF_VALUE_ARRAYs of size 1 allows for simpler and more
generic code.

	void foo(ptrdiff_t sz, int arr[sz])
	{
		for (ptrdiff_t i = 0; i < sz; i++)
			arr[i] = 0;
	}

	void bar(void)
	{
		int  x;
		int  y[1];

		foo(1, &x);
		foo(1, y);
	}

nxt_conf_array_elements_count_or_1():
	Similar to nxt_conf_array_elements_count().
	Return a size of 1 when input is non-array, instead of
	causing undefined behavior.  That value (1) makes sense
	because it will be used as the limiter of a loop that
	loops over the array and calls
	nxt_conf_get_array_element_or_itself(), which will return
	a correct element for such loops.

nxt_conf_get_array_element_or_itself():
	Similar to nxt_conf_get_array_element().
	Return the input pointer unmodified (i.e., a pointer to
	the unique element of a hypothetical array), instead of
	returning NULL, which wasn't very useful.

nxt_conf_array_qsort():
	Since it's a no-op for non-arrays, this API can be reused.
2022-04-26 12:38:48 +02:00
Alejandro Colomar
940d695f82 Added 'const' for read-only function parameter.
That parameter is not being modified in the function.  Make it
'const' to allow passing 'static const' variables.
2022-04-26 12:38:48 +02:00
Andrei Zeliankou
8138d15f76 Tests: added check for zombie processes. 2022-04-12 04:16:00 +01:00
Andrei Zeliankou
0f72534660 Tests: style. 2022-04-11 21:05:14 +01:00
Zhidao HONG
aeed86c682 Workaround for the warning in nxt_realloc() on GCC 12.
This closes #639 issue on Github.
2022-02-22 19:18:18 +08:00