The nxt_murmur_hash2() generated 4-byte hash that was stored in uintptr_t,
which was 8 bytes long on 64-bit systems. At each iteration, it took the
previous key and hashed it again.
The problem was that it took only the first 4 bytes of the key, and these
4 bytes were always zero on 64-bit big-endian system. That resulted in
equal keys at each iteration.
Dmitry Volyntsev [Mon, 29 Oct 2018 14:36:43 +0000 (17:36 +0300)]
Stream: marking incoming chain as processed.
Previously, the buffers of proxy module were not reclaimed.
This resulted in stopping the processing of new data chunks from
a client after proxy_buffer_size bytes were received.
Dmitry Volyntsev [Fri, 19 Oct 2018 17:52:57 +0000 (20:52 +0300)]
Object property quering is refactored.
njs_property_query() is rectified and unified
1) returns only property descriptors. Special return codes
NJS_PRIMITIVE_VALUE, NJS_STRING_VALUE, NJS_ARRAY_VALUE and
NJS_EXTERNAL_VALUE are replaced with a temporary property
descriptor of type NJS_PROPERTY_REF or NJS_PROPERTY_HANDLER.
If NJS_PROPERTY_REF is set reference to a value is contained
in prop->value.data.u.value.
2) NJS_PROPERTY_HANDLER properties returned as is.
3) njs_property_query_t.own can be used to query for an object's
OwnProperty.
4) NJS_PROPERTY_QUERY_IN is removed.
The aim is to implement with it [[GetOwnProperty]] and
[[GetProperty]] methods from specification. Which are used
extensively in many places of the ECMAScript spec.
njs_value_property() is introduced which corresponds to [[Get]]
method from specification.
Fixed macro for aligned size of njs_frame_t struct.
NJS_FRAME_SIZE did not take into account the variable length of
closures array. This can result in overlapping addresses for
native_frame->arguments and frame->closures[n],
The module handlers are refactored to make them similar to the HTTP
ones. This change is not backward compatible with the existing njs code.
To allow asynchronous operations the model of evaluation of njs handlers
is changed. A handler function (which is set for a corresponding nginx
directive) is invoked only once. It can register a callback if more data
is necessary, by calling s.on(<event_name>, <callback>). Available
events:
upload - new data from a client.
download - new data from an upstream.
Callback prototype:
callback(data, flags).
data - string.
flags - object.
Available properties:
last - boolean, data is a last buffer.
A callback can be deregistered by s.off(<event_name>).
Return codes are replaced with special methods: s.allow(), s.deny(),
s.done().
s.done([code]) (s.OK), can be used to return arbitrary code.
s.allow() (s.OK)
s.deny() (s.ABORT)
In addition, s.decline() method is added to allow handlers to stop
processing of the current handler and pass control to the next
handler of the current phase.
A handler is expected to invoke one of these methods when the
processing is done.
For example js_preread can wait for additional data by registering
a callback which will be called whenever new incoming data appears.
function js_preread(s) {
s.on('upload', function(data, flags) {
// process data
// to proceed to the next phase
s.done()
// to proceed to next handler
// of the current phase
s.decline()
})
}
js_filter handler is refactored.
1) The current data chunk is moved from s.buffer to
the callback argument.
2) s.fromUpstream is removed.
3) The properties related to the current data chunk
(s.eof) are put into the second callback argument.
s.eof is renamed to flags.last.
3) s.send(data[, opts]) is added to replace s.buffer = data;
opts - object, can be used to override nginx buffer flags
derived from an incoming data chunk buffer.
It can contain boolean flags: last, flush.
4) data toward corresponding direction is not forwarded
if a callback is active, a callback is expected to
call s.send(data, flags) if it wants to pass data
as is.
5) s.send() can be called multiple times per callback invocation.
function stream_filter(s) {
s.on('upload', function (data, flags) {
// process a data chunk from a client
// stop filtering data
s.off('upload')
})
s.on('download', function (data, flags) {
// process data from upstream
// send my_data as the last buffer.
s.send(my_data, {last:1});
})
}
Added the pretty string representation for values.
Interactive shell: dumping the pretty string representation of
the last expression.
>> [1, new Number(2), {a: new String('αβZγ')}, true, console.log,
/^undef$/m, new Date(0)]
[
1,
[Number: 2],
{
a: [String: 'αβZγ']
},
true,
[Function: native],
/^undef$/m,
1970-01-01T00:00:00.000Z
]
njs.dump(value[, indent]):
Returns the pretty string representation of a value.
value - a value of any type.
indent - a number.
A number of space characters per indentation level.
The original code was correct, the (int) casting does not change
anything because the type of the '0' literal is int. The solution to the
original problem is to mark CID 1438046 as false-positive.