summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/go/unit/nxt_cgo_lib.c4
-rw-r--r--src/go/unit/request.go7
-rw-r--r--src/java/nginx/unit/Context.java6
-rw-r--r--src/java/nginx/unit/Request.java8
-rw-r--r--src/java/nxt_jni_Context.c2
-rw-r--r--src/java/nxt_jni_Request.c23
-rw-r--r--src/nodejs/unit-http/binding.gyp9
-rw-r--r--src/nodejs/unit-http/binding_pub.gyp9
-rwxr-xr-xsrc/nodejs/unit-http/http_server.js12
-rw-r--r--src/nodejs/unit-http/nxt_napi.h656
-rw-r--r--src/nodejs/unit-http/unit.cpp865
-rw-r--r--src/nodejs/unit-http/unit.h35
-rw-r--r--src/nxt_application.c28
-rw-r--r--src/nxt_application.h56
-rw-r--r--src/nxt_buf.h2
-rw-r--r--src/nxt_conf.c225
-rw-r--r--src/nxt_conf.h13
-rw-r--r--src/nxt_conf_validation.c101
-rw-r--r--src/nxt_controller.c35
-rw-r--r--src/nxt_epoll_engine.c2
-rw-r--r--src/nxt_errno.h1
-rw-r--r--src/nxt_h1proto.c17
-rw-r--r--src/nxt_hpux_sendfile.c4
-rw-r--r--src/nxt_http.h10
-rw-r--r--src/nxt_http_parse.c6
-rw-r--r--src/nxt_http_parse.h5
-rw-r--r--src/nxt_http_request.c126
-rw-r--r--src/nxt_http_route.c1021
-rw-r--r--src/nxt_job_resolve.c16
-rw-r--r--src/nxt_kqueue_engine.c2
-rw-r--r--src/nxt_main_process.c2
-rw-r--r--src/nxt_php_sapi.c6
-rw-r--r--src/nxt_poll_engine.c2
-rw-r--r--src/nxt_port.c2
-rw-r--r--src/nxt_port_memory.c4
-rw-r--r--src/nxt_port_socket.c89
-rw-r--r--src/nxt_process.c49
-rw-r--r--src/nxt_python_wsgi.c27
-rw-r--r--src/nxt_router.c224
-rw-r--r--src/nxt_router.h5
-rw-r--r--src/nxt_runtime.c3
-rw-r--r--src/nxt_sockaddr.c16
-rw-r--r--src/nxt_socket.h4
-rw-r--r--src/nxt_socketpair.c17
-rw-r--r--src/nxt_sprintf.c12
-rw-r--r--src/nxt_timer.h2
-rw-r--r--src/nxt_unicode_lowcase.pl6
-rw-r--r--src/nxt_unit.c4
-rw-r--r--src/nxt_unit_request.h1
-rw-r--r--src/perl/nxt_perl_psgi.c5
-rw-r--r--src/ruby/nxt_ruby.c4
51 files changed, 2535 insertions, 1255 deletions
diff --git a/src/go/unit/nxt_cgo_lib.c b/src/go/unit/nxt_cgo_lib.c
index 98a23482..cc1228f5 100644
--- a/src/go/unit/nxt_cgo_lib.c
+++ b/src/go/unit/nxt_cgo_lib.c
@@ -83,6 +83,10 @@ nxt_cgo_request_handler(nxt_unit_request_info_t *req)
nxt_go_request_set_remote_addr(go_req,
nxt_cgo_str_init(&remote_addr, &r->remote, r->remote_length));
+ if (r->tls) {
+ nxt_go_request_set_tls(go_req);
+ }
+
nxt_go_request_handler(go_req, (uintptr_t) req->unit->data);
}
diff --git a/src/go/unit/request.go b/src/go/unit/request.go
index 829a2c64..ad56cabb 100644
--- a/src/go/unit/request.go
+++ b/src/go/unit/request.go
@@ -14,6 +14,7 @@ import (
"io"
"net/http"
"net/url"
+ "crypto/tls"
"unsafe"
)
@@ -125,6 +126,12 @@ func nxt_go_request_set_remote_addr(go_req uintptr, addr *C.nxt_cgo_str_t) {
get_request(go_req).req.RemoteAddr = C.GoStringN(addr.start, addr.length)
}
+//export nxt_go_request_set_tls
+func nxt_go_request_set_tls(go_req uintptr) {
+
+ get_request(go_req).req.TLS = &tls.ConnectionState{ }
+}
+
//export nxt_go_request_handler
func nxt_go_request_handler(go_req uintptr, h uintptr) {
r := get_request(go_req)
diff --git a/src/java/nginx/unit/Context.java b/src/java/nginx/unit/Context.java
index 643a336b..f6d5e339 100644
--- a/src/java/nginx/unit/Context.java
+++ b/src/java/nginx/unit/Context.java
@@ -306,7 +306,7 @@ public class Context implements ServletContext, InitParams
PrintWriter writer = response.getWriter();
for (String n : ls) {
- writer.println("<a href=\"" + n + "\">" + n + "</a><br>");
+ writer.println("<a href=\"" + n + "\">" + n + "</a><br>");
}
writer.close();
@@ -547,7 +547,7 @@ public class Context implements ServletContext, InitParams
j = j.getParent();
}
}
- system_loader = j;
+ system_loader = j;
}
private boolean isSystemPath(String path)
@@ -1733,7 +1733,7 @@ public class Context implements ServletContext, InitParams
@Override
public FileVisitResult visitFile(
- Path file, BasicFileAttributes attrs)
+ Path file, BasicFileAttributes attrs)
throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
diff --git a/src/java/nginx/unit/Request.java b/src/java/nginx/unit/Request.java
index dc73c656..3ba46f6c 100644
--- a/src/java/nginx/unit/Request.java
+++ b/src/java/nginx/unit/Request.java
@@ -920,7 +920,7 @@ public class Request implements HttpServletRequest, DynamicPathRequest
@Override
public String getScheme()
{
- log("getScheme");
+ trace("getScheme");
return getScheme(req_ptr);
}
@@ -980,11 +980,13 @@ public class Request implements HttpServletRequest, DynamicPathRequest
@Override
public boolean isSecure()
{
- log("isSecure");
+ trace("isSecure");
- return false;
+ return isSecure(req_ptr);
}
+ private static native boolean isSecure(long req_ptr);
+
@Override
public void removeAttribute(String name)
{
diff --git a/src/java/nxt_jni_Context.c b/src/java/nxt_jni_Context.c
index 8f7adddf..589e1c5b 100644
--- a/src/java/nxt_jni_Context.c
+++ b/src/java/nxt_jni_Context.c
@@ -55,7 +55,7 @@ nxt_java_initContext(JNIEnv *env, jobject cl)
}
nxt_java_Context_stop = (*env)->GetMethodID(env, cls, "stop", "()V");
- if (nxt_java_Context_service == NULL) {
+ if (nxt_java_Context_stop == NULL) {
nxt_unit_warn(NULL, "nginx.unit.Context.stop() not found");
goto failed;
}
diff --git a/src/java/nxt_jni_Request.c b/src/java/nxt_jni_Request.c
index 6fb9cb44..733290dd 100644
--- a/src/java/nxt_jni_Request.c
+++ b/src/java/nxt_jni_Request.c
@@ -56,6 +56,8 @@ static jstring JNICALL nxt_java_Request_getServerName(JNIEnv *env, jclass cls,
jlong req_ptr);
static jint JNICALL nxt_java_Request_getServerPort(JNIEnv *env, jclass cls,
jlong req_ptr);
+static jboolean JNICALL nxt_java_Request_isSecure(JNIEnv *env, jclass cls,
+ jlong req_ptr);
static void JNICALL nxt_java_Request_log(JNIEnv *env, jclass cls,
jlong req_info_ptr, jstring msg, jint msg_len);
static void JNICALL nxt_java_Request_trace(JNIEnv *env, jclass cls,
@@ -166,6 +168,10 @@ nxt_java_initRequest(JNIEnv *env, jobject cl)
(char *) "(J)I",
nxt_java_Request_getServerPort },
+ { (char *) "isSecure",
+ (char *) "(J)Z",
+ nxt_java_Request_isSecure },
+
{ (char *) "log",
(char *) "(JLjava/lang/String;I)V",
nxt_java_Request_log },
@@ -536,7 +542,11 @@ nxt_java_Request_getRemotePort(JNIEnv *env, jclass cls, jlong req_ptr)
static jstring JNICALL
nxt_java_Request_getScheme(JNIEnv *env, jclass cls, jlong req_ptr)
{
- return (*env)->NewStringUTF(env, "http");
+ nxt_unit_request_t *r;
+
+ r = nxt_jlong2ptr(req_ptr);
+
+ return (*env)->NewStringUTF(env, r->tls ? "https" : "http");
}
@@ -603,6 +613,17 @@ nxt_java_Request_getServerPort(JNIEnv *env, jclass cls, jlong req_ptr)
}
+static jboolean JNICALL
+nxt_java_Request_isSecure(JNIEnv *env, jclass cls, jlong req_ptr)
+{
+ nxt_unit_request_t *r;
+
+ r = nxt_jlong2ptr(req_ptr);
+
+ return r->tls != 0;
+}
+
+
static void JNICALL
nxt_java_Request_log(JNIEnv *env, jclass cls, jlong req_info_ptr, jstring msg,
jint msg_len)
diff --git a/src/nodejs/unit-http/binding.gyp b/src/nodejs/unit-http/binding.gyp
index ee09bfed..55d965bd 100644
--- a/src/nodejs/unit-http/binding.gyp
+++ b/src/nodejs/unit-http/binding.gyp
@@ -1,6 +1,15 @@
{
'targets': [{
'target_name': "unit-http",
+ 'cflags!': [ '-fno-exceptions' ],
+ 'cflags_cc!': [ '-fno-exceptions' ],
+ 'conditions': [
+ ['OS=="mac"', {
+ 'xcode_settings': {
+ 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES'
+ }
+ }]
+ ],
'sources': ["unit.cpp", "addon.cpp"],
'include_dirs': [
"<!(echo $UNIT_SRC_PATH)", "<!(echo $UNIT_BUILD_PATH)"
diff --git a/src/nodejs/unit-http/binding_pub.gyp b/src/nodejs/unit-http/binding_pub.gyp
index 6fe3d9bc..3c39933a 100644
--- a/src/nodejs/unit-http/binding_pub.gyp
+++ b/src/nodejs/unit-http/binding_pub.gyp
@@ -1,6 +1,15 @@
{
'targets': [{
'target_name': "unit-http",
+ 'cflags!': [ '-fno-exceptions' ],
+ 'cflags_cc!': [ '-fno-exceptions' ],
+ 'conditions': [
+ ['OS=="mac"', {
+ 'xcode_settings': {
+ 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES'
+ }
+ }]
+ ],
'sources': ["unit.cpp", "addon.cpp"],
'libraries': ["-lunit"]
}]
diff --git a/src/nodejs/unit-http/http_server.js b/src/nodejs/unit-http/http_server.js
index 057a1f26..ae8e204a 100755
--- a/src/nodejs/unit-http/http_server.js
+++ b/src/nodejs/unit-http/http_server.js
@@ -197,6 +197,14 @@ function writeHead(statusCode, reason, obj) {
}
};
+/*
+ * Some Node.js packages are known to be using this undocumented function,
+ * notably "compression" middleware.
+ */
+ServerResponse.prototype._implicitHeader = function _implicitHeader() {
+ this.writeHead(this.statusCode);
+};
+
ServerResponse.prototype._writeBody = function(chunk, encoding, callback) {
var contentLength = 0;
@@ -387,6 +395,10 @@ Server.prototype.emit_events = function (server, req, res) {
});
};
+Server.prototype.emit_close = function () {
+ this.emit('close');
+};
+
function connectionListener(socket) {
}
diff --git a/src/nodejs/unit-http/nxt_napi.h b/src/nodejs/unit-http/nxt_napi.h
new file mode 100644
index 00000000..9bcf3a21
--- /dev/null
+++ b/src/nodejs/unit-http/nxt_napi.h
@@ -0,0 +1,656 @@
+
+/*
+ * Copyright (C) NGINX, Inc.
+ */
+
+#ifndef _NXT_NODEJS_NAPI_H_INCLUDED_
+#define _NXT_NODEJS_NAPI_H_INCLUDED_
+
+#include <node_api.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "version.h"
+#include <nxt_unit.h>
+
+#if NXT_VERNUM != NXT_NODE_VERNUM
+#error "libunit version mismatch."
+#endif
+
+#include <nxt_unit_response.h>
+#include <nxt_unit_request.h>
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+
+struct nxt_napi {
+
+ struct exception {
+ exception(const char *s) : str(s) { }
+
+ const char *str;
+ };
+
+
+ nxt_napi(napi_env env) : env_(env) { }
+
+
+ inline napi_value
+ coerce_to_string(napi_value val)
+ {
+ napi_value res;
+ napi_status status;
+
+ status = napi_coerce_to_string(env_, val, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to coerce to string");
+ }
+
+ return res;
+ }
+
+
+ inline napi_value
+ create_buffer(size_t size, void **data)
+ {
+ napi_value res;
+ napi_status status;
+
+ status = napi_create_buffer(env_, size, data, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to create buffer");
+ }
+
+ return res;
+ }
+
+
+ inline napi_value
+ create_function(const char *name, size_t len, napi_callback cb, void *data)
+ {
+ napi_value res;
+ napi_status status;
+
+ status = napi_create_function(env_, name, len, cb, data, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to create function");
+ }
+
+ return res;
+ }
+
+
+ inline napi_value
+ create_function(napi_callback cb)
+ {
+ return create_function(NULL, 0, cb, NULL);
+ }
+
+
+ inline napi_value
+ create_object()
+ {
+ napi_value res;
+ napi_status status;
+
+ status = napi_create_object(env_, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to create object");
+ }
+
+ return res;
+ }
+
+
+ inline napi_ref
+ create_reference(napi_value val, int ref_count = 1)
+ {
+ napi_ref res;
+ napi_status status;
+
+ status = napi_create_reference(env_, val, ref_count, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to create reference");
+ }
+
+ return res;
+ }
+
+
+ inline napi_value
+ create_string_latin1(const char *str, size_t len)
+ {
+ napi_value res;
+ napi_status status;
+
+ status = napi_create_string_latin1(env_, str, len, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to create latin1 string");
+ }
+
+ return res;
+ }
+
+
+ inline napi_value
+ create_string_latin1(nxt_unit_sptr_t &str, size_t len)
+ {
+ const char *p;
+
+ p = (const char *) nxt_unit_sptr_get(&str);
+
+ return create_string_latin1(p, len);
+ }
+
+
+ inline napi_value
+ define_class(const char *name, napi_callback ctor, size_t prop_count,
+ const napi_property_descriptor* props)
+ {
+ napi_value res;
+ napi_status status;
+
+ status = napi_define_class(env_, name, NAPI_AUTO_LENGTH, ctor, nullptr,
+ prop_count, props, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to define class");
+ }
+
+ return res;
+ }
+
+
+ inline void
+ delete_reference(napi_ref ref)
+ {
+ napi_delete_reference(env_, ref);
+ }
+
+
+ inline uint32_t
+ get_array_length(napi_value val)
+ {
+ uint32_t res;
+ napi_status status;
+
+ status = napi_get_array_length(env_, val, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to get array length");
+ }
+
+ return res;
+ }
+
+
+ inline napi_value
+ get_cb_info(napi_callback_info info, size_t &argc, napi_value *argv)
+ {
+ napi_value res;
+ napi_status status;
+
+ status = napi_get_cb_info(env_, info, &argc, argv, &res, nullptr);
+ if (status != napi_ok) {
+ throw exception("Failed to get arguments from js");
+ }
+
+ return res;
+ }
+
+
+ inline napi_value
+ get_cb_info(napi_callback_info info)
+ {
+ napi_value res;
+ napi_status status;
+
+ status = napi_get_cb_info(env_, info, nullptr, nullptr, &res, nullptr);
+ if (status != napi_ok) {
+ throw exception("Failed to get arguments from js");
+ }
+
+ return res;
+ }
+
+
+ inline napi_value
+ get_element(napi_value obj, uint32_t i)
+ {
+ napi_value res;
+ napi_status status;
+
+ status = napi_get_element(env_, obj, i, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to get element");
+ }
+
+ return res;
+ }
+
+
+ inline napi_value
+ get_named_property(napi_value obj, const char *name)
+ {
+ napi_value res;
+ napi_status status;
+
+ status = napi_get_named_property(env_, obj, name, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to get named property");
+ }
+
+ return res;
+ }
+
+
+ inline napi_value
+ get_new_target(napi_callback_info info)
+ {
+ napi_value res;
+ napi_status status;
+
+ status = napi_get_new_target(env_, info, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to get new target");
+ }
+
+ return res;
+ }
+
+
+ inline napi_value
+ get_property(napi_value val, napi_value key)
+ {
+ napi_value res;
+ napi_status status;
+
+ status = napi_get_property(env_, val, key, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to get property");
+ }
+
+ return res;
+ }
+
+
+ inline napi_value
+ get_property_names(napi_value val)
+ {
+ napi_value res;
+ napi_status status;
+
+ status = napi_get_property_names(env_, val, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to get property names");
+ }
+
+ return res;
+ }
+
+
+ inline napi_value
+ get_reference_value(napi_ref ref)
+ {
+ napi_value res;
+ napi_status status;
+
+ status = napi_get_reference_value(env_, ref, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to get reference value");
+ }
+
+ return res;
+ }
+
+
+ inline nxt_unit_request_info_t *
+ get_request_info(napi_value obj)
+ {
+ int64_t n;
+ napi_status status;
+
+ status = napi_get_value_int64(env_, obj, &n);
+ if (status != napi_ok) {
+ throw exception("Failed to get request pointer");
+ }
+
+ return (nxt_unit_request_info_t *) (intptr_t) n;
+ }
+
+
+ inline size_t
+ get_value_string_latin1(napi_value val, char *buf, size_t bufsize)
+ {
+ size_t res;
+ napi_status status;
+
+ status = napi_get_value_string_latin1(env_, val, buf, bufsize, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to get string latin1");
+ }
+
+ return res;
+ }
+
+
+ inline uint32_t
+ get_value_uint32(napi_value obj)
+ {
+ uint32_t res;
+ napi_status status;
+
+ status = napi_get_value_uint32(env_, obj, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to get uint32_t");
+ }
+
+ return res;
+ }
+
+
+ inline bool
+ is_array(napi_value val)
+ {
+ bool res;
+ napi_status status;
+
+ status = napi_is_array(env_, val, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to confirm value is array");
+ }
+
+ return res;
+ }
+
+
+ inline napi_value
+ make_callback(napi_async_context ctx, napi_value val, napi_value func,
+ int argc, const napi_value *argv)
+ {
+ napi_value res, ex;
+ napi_status status;
+
+ status = napi_make_callback(env_, ctx, val, func, argc, argv, &res);
+ if (status != napi_ok) {
+ if (status != napi_pending_exception) {
+ throw exception("Failed to make callback");
+ }
+
+ status = napi_get_and_clear_last_exception(env_, &ex);
+ if (status != napi_ok) {
+ throw exception("Failed to get and clear last exception");
+ }
+
+ /* Logging a description of the error and call stack. */
+ status = napi_fatal_exception(env_, ex);
+ if (status != napi_ok) {
+ throw exception("Failed napi_fatal_exception()");
+ }
+ }
+
+ return res;
+ }
+
+
+ inline napi_value
+ new_instance(napi_value ctor)
+ {
+ napi_value res;
+ napi_status status;
+
+ status = napi_new_instance(env_, ctor, 0, NULL, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to create instance");
+ }
+
+ return res;
+ }
+
+
+ inline napi_value
+ new_instance(napi_value ctor, napi_value param)
+ {
+ napi_value res;
+ napi_status status;
+
+ status = napi_new_instance(env_, ctor, 1, &param, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to create instance");
+ }
+
+ return res;
+ }
+
+
+ inline void
+ set_element(napi_value obj, uint32_t i, napi_value val)
+ {
+ napi_status status;
+
+ status = napi_set_element(env_, obj, i, val);
+ if (status != napi_ok) {
+ throw exception("Failed to set element");
+ }
+ }
+
+
+ inline void
+ set_named_property(napi_value obj, const char *name, napi_value val)
+ {
+ napi_status status;
+
+ status = napi_set_named_property(env_, obj, name, val);
+ if (status != napi_ok) {
+ throw exception("Failed to set named property");
+ }
+ }
+
+
+ inline void
+ set_named_property(napi_value obj, const char *name, napi_callback cb)
+ {
+ set_named_property(obj, name, create_function(cb));
+ }
+
+
+ inline napi_value
+ set_named_property(napi_value obj, const char *name, nxt_unit_sptr_t &val,
+ size_t len)
+ {
+ napi_value str;
+
+ str = create_string_latin1(val, len);
+
+ set_named_property(obj, name, str);
+
+ return str;
+ }
+
+
+ inline void
+ set_named_property(napi_value obj, const char *name, intptr_t val)
+ {
+ napi_value ptr;
+ napi_status status;
+
+ status = napi_create_int64(env_, val, &ptr);
+ if (status != napi_ok) {
+ throw exception("Failed to create int64");
+ }
+
+ set_named_property(obj, name, ptr);
+ }
+
+
+ inline void
+ throw_error(const char *str)
+ {
+ napi_throw_error(env_, NULL, str);
+ }
+
+
+ inline void
+ throw_error(const exception &e)
+ {
+ napi_throw_error(env_, NULL, e.str);
+ }
+
+
+ inline napi_valuetype
+ type_of(napi_value val)
+ {
+ napi_status status;
+ napi_valuetype res;
+
+ status = napi_typeof(env_, val, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to get typeof");
+ }
+
+ return res;
+ }
+
+
+ inline void *
+ unwrap(napi_value val)
+ {
+ void *res;
+ napi_status status;
+
+ status = napi_unwrap(env_, val, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to unwrap");
+ }
+
+ return res;
+ }
+
+
+ inline napi_ref
+ wrap(napi_value val, void *obj, napi_finalize fin_cb, void *hint = nullptr)
+ {
+ napi_ref res;
+ napi_status status;
+
+ status = napi_wrap(env_, val, obj, fin_cb, hint, &res);
+ if (status != napi_ok) {
+ throw exception("Failed to wrap");
+ }
+
+ return res;
+ }
+
+
+ inline
+ operator napi_env()
+ {
+ return env_;
+ }
+
+
+ napi_env env()
+ {
+ return env_;
+ }
+
+private:
+ napi_env env_;
+};
+
+
+struct nxt_handle_scope : public nxt_napi {
+ nxt_handle_scope(napi_env env) : nxt_napi(env)
+ {
+ napi_status status;
+
+ status = napi_open_handle_scope(env, &scope_);
+ if (status != napi_ok) {
+ throw exception("Failed to open handle scope");
+ }
+ }
+
+ ~nxt_handle_scope()
+ {
+ napi_status status;
+
+ status = napi_close_handle_scope(env(), scope_);
+ if (status != napi_ok) {
+ throw_error("Failed to close handle scope");
+ }
+ }
+
+private:
+ napi_handle_scope scope_;
+};
+
+
+struct nxt_async_context : public nxt_napi {
+ nxt_async_context(napi_env env, const char *name) :
+ nxt_napi(env)
+ {
+ napi_value name_val;
+ napi_status status;
+
+ name_val = create_string_latin1(name, NAPI_AUTO_LENGTH);
+
+ status = napi_async_init(env, NULL, name_val, &context_);
+ if (status != napi_ok) {
+ throw exception("Failed to init async object");
+ }
+ }
+
+ operator napi_async_context() {
+ return context_;
+ }
+
+ ~nxt_async_context()
+ {
+ napi_status status;
+
+ status = napi_async_destroy(env(), context_);
+ if (status != napi_ok) {
+ throw_error("Failed to destroy async object");
+ }
+ }
+
+private:
+ napi_async_context context_;
+};
+
+
+struct nxt_callback_scope : public nxt_napi {
+ nxt_callback_scope(nxt_async_context& ctx) :
+ nxt_napi(ctx.env())
+ {
+ napi_value resource;
+ napi_status status;
+
+ resource = create_object();
+
+ status = napi_open_callback_scope(env(), resource, ctx, &scope_);
+ if (status != napi_ok) {
+ throw exception("Failed to open callback scope");
+ }
+ }
+
+ ~nxt_callback_scope()
+ {
+ napi_status status;
+
+ status = napi_close_callback_scope(env(), scope_);
+ if (status != napi_ok) {
+ throw_error("Failed to close callback scope");
+ }
+ }
+
+private:
+ napi_callback_scope scope_;
+};
+
+
+#endif /* _NXT_NODEJS_NAPI_H_INCLUDED_ */
diff --git a/src/nodejs/unit-http/unit.cpp b/src/nodejs/unit-http/unit.cpp
index 60b0412a..3f66189a 100644
--- a/src/nodejs/unit-http/unit.cpp
+++ b/src/nodejs/unit-http/unit.cpp
@@ -20,9 +20,9 @@ struct nxt_nodejs_ctx_t {
};
-Unit::Unit(napi_env env):
- env_(env),
- wrapper_(nullptr),
+Unit::Unit(napi_env env, napi_value jsthis):
+ nxt_napi(env),
+ wrapper_(wrap(jsthis, this, destroy)),
unit_ctx_(nullptr)
{
}
@@ -30,15 +30,15 @@ Unit::Unit(napi_env env):
Unit::~Unit()
{
- napi_delete_reference(env_, wrapper_);
+ delete_reference(wrapper_);
}
napi_value
Unit::init(napi_env env, napi_value exports)
{
- napi_value cons, fn;
- napi_status status;
+ nxt_napi napi(env);
+ napi_value cons;
napi_property_descriptor properties[] = {
{ "createServer", 0, create_server, 0, 0, 0, napi_default, 0 },
@@ -46,61 +46,22 @@ Unit::init(napi_env env, napi_value exports)
{ "_read", 0, _read, 0, 0, 0, napi_default, 0 }
};
- status = napi_define_class(env, "Unit", NAPI_AUTO_LENGTH, create, nullptr,
- 3, properties, &cons);
- if (status != napi_ok) {
- goto failed;
- }
-
- status = napi_create_reference(env, cons, 1, &constructor_);
- if (status != napi_ok) {
- goto failed;
- }
-
- status = napi_set_named_property(env, exports, "Unit", cons);
- if (status != napi_ok) {
- goto failed;
- }
-
- status = napi_create_function(env, NULL, 0, response_send_headers, NULL,
- &fn);
- if (status != napi_ok) {
- goto failed;
- }
-
- status = napi_set_named_property(env, exports,
- "unit_response_headers", fn);
- if (status != napi_ok) {
- goto failed;
- }
-
- status = napi_create_function(env, NULL, 0, response_write, NULL, &fn);
- if (status != napi_ok) {
- goto failed;
- }
+ try {
+ cons = napi.define_class("Unit", create, 3, properties);
+ constructor_ = napi.create_reference(cons);
- status = napi_set_named_property(env, exports, "unit_response_write", fn);
- if (status != napi_ok) {
- goto failed;
- }
+ napi.set_named_property(exports, "Unit", cons);
+ napi.set_named_property(exports, "unit_response_headers",
+ response_send_headers);
+ napi.set_named_property(exports, "unit_response_write", response_write);
+ napi.set_named_property(exports, "unit_response_end", response_end);
- status = napi_create_function(env, NULL, 0, response_end, NULL, &fn);
- if (status != napi_ok) {
- goto failed;
- }
-
- status = napi_set_named_property(env, exports, "unit_response_end", fn);
- if (status != napi_ok) {
- goto failed;
+ } catch (exception &e) {
+ napi.throw_error(e);
+ return nullptr;
}
return exports;
-
-failed:
-
- napi_throw_error(env, NULL, "Failed to define Unit class");
-
- return nullptr;
}
@@ -116,63 +77,33 @@ Unit::destroy(napi_env env, void *nativeObject, void *finalize_hint)
napi_value
Unit::create(napi_env env, napi_callback_info info)
{
- Unit *obj;
- napi_ref ref;
- napi_value target, cons, instance, jsthis;
- napi_status status;
-
- status = napi_get_new_target(env, info, &target);
- if (status != napi_ok) {
- goto failed;
- }
+ nxt_napi napi(env);
+ napi_value target, cons, instance, jsthis;
- if (target != nullptr) {
- /* Invoked as constructor: `new Unit(...)` */
- status = napi_get_cb_info(env, info, nullptr, nullptr, &jsthis,
- nullptr);
- if (status != napi_ok) {
- goto failed;
- }
+ try {
+ target = napi.get_new_target(info);
- obj = new Unit(env);
+ if (target != nullptr) {
+ /* Invoked as constructor: `new Unit(...)`. */
+ jsthis = napi.get_cb_info(info);
- status = napi_wrap(env, jsthis, reinterpret_cast<void *>(obj),
- destroy, nullptr, &obj->wrapper_);
- if (status != napi_ok) {
- goto failed;
- }
+ new Unit(env, jsthis);
+ napi.create_reference(jsthis);
- status = napi_create_reference(env, jsthis, 1, &ref);
- if (status != napi_ok) {
- goto failed;
+ return jsthis;
}
- return jsthis;
- }
-
- /* Invoked as plain function `Unit(...)`, turn into construct call. */
- status = napi_get_reference_value(env, constructor_, &cons);
- if (status != napi_ok) {
- goto failed;
- }
+ /* Invoked as plain function `Unit(...)`, turn into construct call. */
+ cons = napi.get_reference_value(constructor_);
+ instance = napi.new_instance(cons);
+ napi.create_reference(instance);
- status = napi_new_instance(env, cons, 0, nullptr, &instance);
- if (status != napi_ok) {
- goto failed;
- }
-
- status = napi_create_reference(env, instance, 1, &ref);
- if (status != napi_ok) {
- goto failed;
+ } catch (exception &e) {
+ napi.throw_error(e);
+ return nullptr;
}
return instance;
-
-failed:
-
- napi_throw_error(env, NULL, "Failed to create Unit object");
-
- return nullptr;
}
@@ -181,20 +112,19 @@ Unit::create_server(napi_env env, napi_callback_info info)
{
Unit *obj;
size_t argc;
+ nxt_napi napi(env);
napi_value jsthis, argv;
- napi_status status;
nxt_unit_init_t unit_init;
argc = 1;
- status = napi_get_cb_info(env, info, &argc, &argv, &jsthis, nullptr);
- if (status != napi_ok) {
- goto failed;
- }
+ try {
+ jsthis = napi.get_cb_info(info, argc, &argv);
+ obj = (Unit *) napi.unwrap(jsthis);
- status = napi_unwrap(env, jsthis, reinterpret_cast<void **>(&obj));
- if (status != napi_ok) {
- goto failed;
+ } catch (exception &e) {
+ napi.throw_error(e);
+ return nullptr;
}
memset(&unit_init, 0, sizeof(nxt_unit_init_t));
@@ -230,40 +160,22 @@ Unit::listen(napi_env env, napi_callback_info info)
napi_value
Unit::_read(napi_env env, napi_callback_info info)
{
- Unit *obj;
void *data;
size_t argc;
- int64_t req_pointer;
- napi_value jsthis, buffer, argv;
- napi_status status;
+ nxt_napi napi(env);
+ napi_value buffer, argv;
nxt_unit_request_info_t *req;
argc = 1;
- status = napi_get_cb_info(env, info, &argc, &argv, &jsthis, nullptr);
- if (status != napi_ok) {
- napi_throw_error(env, NULL, "Failed to get arguments from js");
- return nullptr;
- }
+ try {
+ napi.get_cb_info(info, argc, &argv);
- status = napi_unwrap(env, jsthis, reinterpret_cast<void **>(&obj));
- if (status != napi_ok) {
- napi_throw_error(env, NULL, "Failed to get Unit object form js");
- return nullptr;
- }
+ req = napi.get_request_info(argv);
+ buffer = napi.create_buffer((size_t) req->content_length, &data);
- status = napi_get_value_int64(env, argv, &req_pointer);
- if (status != napi_ok) {
- napi_throw_error(env, NULL, "Failed to get request pointer");
- return nullptr;
- }
-
- req = (nxt_unit_request_info_t *) (uintptr_t) req_pointer;
-
- status = napi_create_buffer(env, (size_t) req->content_length,
- &data, &buffer);
- if (status != napi_ok) {
- napi_throw_error(env, NULL, "Failed to create request buffer");
+ } catch (exception &e) {
+ napi.throw_error(e);
return nullptr;
}
@@ -276,138 +188,38 @@ Unit::_read(napi_env env, napi_callback_info info)
void
Unit::request_handler(nxt_unit_request_info_t *req)
{
- Unit *obj;
- napi_value socket, request, response, global, server_obj, except;
- napi_value emit_events, events_res, async_name, resource_object;
- napi_status status;
- napi_async_context async_context;
- napi_callback_scope async_scope;
- napi_value events_args[3];
+ Unit *obj;
+ napi_value socket, request, response, server_obj;
+ napi_value emit_events;
+ napi_value events_args[3];
obj = reinterpret_cast<Unit *>(req->unit->data);
- napi_handle_scope scope;
- status = napi_open_handle_scope(obj->env_, &scope);
- if (status != napi_ok) {
- napi_throw_error(obj->env_, NULL, "Failed to create handle scope");
- return;
- }
-
- server_obj = obj->get_server_object();
- if (server_obj == nullptr) {
- napi_throw_error(obj->env_, NULL, "Failed to get server object");
- return;
- }
-
- status = napi_get_global(obj->env_, &global);
- if (status != napi_ok) {
- napi_throw_error(obj->env_, NULL, "Failed to get global variable");
- return;
- }
-
- socket = obj->create_socket(server_obj, req);
- if (socket == nullptr) {
- napi_throw_error(obj->env_, NULL, "Failed to create socket object");
- return;
- }
-
- request = obj->create_request(server_obj, socket);
- if (request == nullptr) {
- napi_throw_error(obj->env_, NULL, "Failed to create request object");
- return;
- }
-
- response = obj->create_response(server_obj, socket, request, req, obj);
- if (response == nullptr) {
- napi_throw_error(obj->env_, NULL, "Failed to create response object");
- return;
- }
-
- status = obj->create_headers(req, request);
- if (status != napi_ok) {
- napi_throw_error(obj->env_, NULL, "Failed to create headers");
- return;
- }
-
- status = napi_get_named_property(obj->env_, server_obj, "emit_events",
- &emit_events);
- if (status != napi_ok) {
- napi_throw_error(obj->env_, NULL, "Failed to get "
- "'emit_events' function");
- return;
- }
-
- events_args[0] = server_obj;
- events_args[1] = request;
- events_args[2] = response;
+ try {
+ nxt_handle_scope scope(obj->env());
- status = napi_create_string_utf8(obj->env_, "unit_request_handler",
- sizeof("unit_request_handler") - 1,
- &async_name);
- if (status != napi_ok) {
- napi_throw_error(obj->env_, NULL, "Failed to create utf-8 string");
- return;
- }
+ server_obj = obj->get_server_object();
- status = napi_async_init(obj->env_, NULL, async_name, &async_context);
- if (status != napi_ok) {
- napi_throw_error(obj->env_, NULL, "Failed to init async object");
- return;
- }
+ socket = obj->create_socket(server_obj, req);
+ request = obj->create_request(server_obj, socket);
+ response = obj->create_response(server_obj, socket, request, req);
- status = napi_create_object(obj->env_, &resource_object);
- if (status != napi_ok) {
- napi_throw_error(obj->env_, NULL, "Failed to create object for "
- "callback scope");
- return;
- }
+ obj->create_headers(req, request);
- status = napi_open_callback_scope(obj->env_, resource_object, async_context,
- &async_scope);
- if (status != napi_ok) {
- napi_throw_error(obj->env_, NULL, "Failed to open callback scope");
- return;
- }
+ emit_events = obj->get_named_property(server_obj, "emit_events");
- status = napi_make_callback(obj->env_, async_context, server_obj,
- emit_events, 3, events_args, &events_res);
- if (status != napi_ok) {
- if (status != napi_pending_exception) {
- napi_throw_error(obj->env_, NULL, "Failed to make callback");
- return;
- }
+ events_args[0] = server_obj;
+ events_args[1] = request;
+ events_args[2] = response;
- status = napi_get_and_clear_last_exception(obj->env_, &except);
- if (status != napi_ok) {
- napi_throw_error(obj->env_, NULL,
- "Failed to get and clear last exception");
- return;
- }
-
- /* Logging a description of the error and call stack. */
- status = napi_fatal_exception(obj->env_, except);
- if (status != napi_ok) {
- napi_throw_error(obj->env_, NULL, "Failed to call "
- "napi_fatal_exception() function");
- return;
- }
- }
+ nxt_async_context async_context(obj->env(), "unit_request_handler");
+ nxt_callback_scope async_scope(async_context);
- status = napi_close_callback_scope(obj->env_, async_scope);
- if (status != napi_ok) {
- napi_throw_error(obj->env_, NULL, "Failed to close callback scope");
- return;
- }
+ obj->make_callback(async_context, server_obj, emit_events,
+ 3, events_args);
- status = napi_async_destroy(obj->env_, async_context);
- if (status != napi_ok) {
- napi_throw_error(obj->env_, NULL, "Failed to destroy async object");
- return;
- }
-
- status = napi_close_handle_scope(obj->env_, scope);
- if (status != napi_ok) {
- napi_throw_error(obj->env_, NULL, "Failed to close handle scope");
+ } catch (exception &e) {
+ obj->throw_error(e);
}
}
@@ -432,14 +244,14 @@ Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port)
obj = reinterpret_cast<Unit *>(ctx->unit->data);
if (fcntl(port->in_fd, F_SETFL, O_NONBLOCK) == -1) {
- napi_throw_error(obj->env_, NULL, "Failed to upgrade read"
+ obj->throw_error("Failed to upgrade read"
" file descriptor to O_NONBLOCK");
return -1;
}
- status = napi_get_uv_event_loop(obj->env_, &loop);
+ status = napi_get_uv_event_loop(obj->env(), &loop);
if (status != napi_ok) {
- napi_throw_error(obj->env_, NULL, "Failed to get uv.loop");
+ obj->throw_error("Failed to get uv.loop");
return NXT_UNIT_ERROR;
}
@@ -447,13 +259,13 @@ Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port)
err = uv_poll_init(loop, &node_ctx->poll, port->in_fd);
if (err < 0) {
- napi_throw_error(obj->env_, NULL, "Failed to init uv.poll");
+ obj->throw_error("Failed to init uv.poll");
return NXT_UNIT_ERROR;
}
err = uv_poll_start(&node_ctx->poll, UV_READABLE, nxt_uv_read_callback);
if (err < 0) {
- napi_throw_error(obj->env_, NULL, "Failed to start uv.poll");
+ obj->throw_error("Failed to start uv.poll");
return NXT_UNIT_ERROR;
}
@@ -467,7 +279,7 @@ Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port)
}
-inline bool
+inline bool
operator == (const nxt_unit_port_id_t &p1, const nxt_unit_port_id_t &p2)
{
return p1.pid == p2.pid && p1.id == p2.id;
@@ -498,6 +310,27 @@ Unit::remove_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id)
void
Unit::quit(nxt_unit_ctx_t *ctx)
{
+ Unit *obj;
+ napi_value server_obj, emit_close;
+
+ obj = reinterpret_cast<Unit *>(ctx->unit->data);
+
+ try {
+ nxt_handle_scope scope(obj->env());
+
+ server_obj = obj->get_server_object();
+
+ emit_close = obj->get_named_property(server_obj, "emit_close");
+
+ nxt_async_context async_context(obj->env(), "unit_quit");
+ nxt_callback_scope async_scope(async_context);
+
+ obj->make_callback(async_context, server_obj, emit_close, 0, NULL);
+
+ } catch (exception &e) {
+ obj->throw_error(e);
+ }
+
nxt_unit_done(ctx);
}
@@ -505,200 +338,105 @@ Unit::quit(nxt_unit_ctx_t *ctx)
napi_value
Unit::get_server_object()
{
- napi_value unit_obj, server_obj;
- napi_status status;
+ napi_value unit_obj;
- status = napi_get_reference_value(env_, wrapper_, &unit_obj);
- if (status != napi_ok) {
- return nullptr;
- }
-
- status = napi_get_named_property(env_, unit_obj, "server", &server_obj);
- if (status != napi_ok) {
- return nullptr;
- }
+ unit_obj = get_reference_value(wrapper_);
- return server_obj;
+ return get_named_property(unit_obj, "server");
}
-napi_status
+void
Unit::create_headers(nxt_unit_request_info_t *req, napi_value request)
{
uint32_t i;
- const char *p;
- napi_value headers, raw_headers, str;
+ napi_value headers, raw_headers;
napi_status status;
- nxt_unit_field_t *f;
nxt_unit_request_t *r;
r = req->request;
- status = napi_create_object(env_, &headers);
- if (status != napi_ok) {
- return status;
- }
+ headers = create_object();
- status = napi_create_array_with_length(env_, r->fields_count * 2,
+ status = napi_create_array_with_length(env(), r->fields_count * 2,
&raw_headers);
if (status != napi_ok) {
- return status;
+ throw exception("Failed to create array");
}
for (i = 0; i < r->fields_count; i++) {
- f = r->fields + i;
-
- status = this->append_header(f, headers, raw_headers, i);
- if (status != napi_ok) {
- return status;
- }
- }
-
- status = napi_set_named_property(env_, request, "headers", headers);
- if (status != napi_ok) {
- return status;
- }
-
- status = napi_set_named_property(env_, request, "rawHeaders", raw_headers);
- if (status != napi_ok) {
- return status;
- }
-
- p = (const char *) nxt_unit_sptr_get(&r->version);
-
- status = napi_create_string_latin1(env_, p, r->version_length, &str);
- if (status != napi_ok) {
- return status;
- }
-
- status = napi_set_named_property(env_, request, "httpVersion", str);
- if (status != napi_ok) {
- return status;
- }
-
- p = (const char *) nxt_unit_sptr_get(&r->method);
-
- status = napi_create_string_latin1(env_, p, r->method_length, &str);
- if (status != napi_ok) {
- return status;
+ append_header(r->fields + i, headers, raw_headers, i);
}
- status = napi_set_named_property(env_, request, "method", str);
- if (status != napi_ok) {
- return status;
- }
-
- p = (const char *) nxt_unit_sptr_get(&r->target);
-
- status = napi_create_string_latin1(env_, p, r->target_length, &str);
- if (status != napi_ok) {
- return status;
- }
+ set_named_property(request, "headers", headers);
+ set_named_property(request, "rawHeaders", raw_headers);
+ set_named_property(request, "httpVersion", r->version, r->version_length);
+ set_named_property(request, "method", r->method, r->method_length);
+ set_named_property(request, "url", r->target, r->target_length);
+}
- status = napi_set_named_property(env_, request, "url", str);
- if (status != napi_ok) {
- return status;
- }
- return napi_ok;
+inline char
+lowcase(char c)
+{
+ return (c >= 'A' && c <= 'Z') ? (c | 0x20) : c;
}
-inline napi_status
+inline void
Unit::append_header(nxt_unit_field_t *f, napi_value headers,
- napi_value raw_headers, uint32_t idx)
+ napi_value raw_headers, uint32_t idx)
{
- const char *name, *value;
- napi_value str, vstr;
- napi_status status;
+ char *name;
+ uint8_t i;
+ napi_value str, vstr;
- value = (const char *) nxt_unit_sptr_get(&f->value);
+ name = (char *) nxt_unit_sptr_get(&f->name);
- status = napi_create_string_latin1(env_, value, f->value_length, &vstr);
- if (status != napi_ok) {
- return status;
- }
-
- name = (const char *) nxt_unit_sptr_get(&f->name);
-
- status = napi_set_named_property(env_, headers, name, vstr);
- if (status != napi_ok) {
- return status;
- }
+ str = create_string_latin1(name, f->name_length);
- status = napi_create_string_latin1(env_, name, f->name_length, &str);
- if (status != napi_ok) {
- return status;
+ for (i = 0; i < f->name_length; i++) {
+ name[i] = lowcase(name[i]);
}
- status = napi_set_element(env_, raw_headers, idx * 2, str);
- if (status != napi_ok) {
- return status;
- }
-
- status = napi_set_element(env_, raw_headers, idx * 2 + 1, vstr);
- if (status != napi_ok) {
- return status;
- }
+ vstr = set_named_property(headers, name, f->value, f->value_length);
- return napi_ok;
+ set_element(raw_headers, idx * 2, str);
+ set_element(raw_headers, idx * 2 + 1, vstr);
}
napi_value
Unit::create_socket(napi_value server_obj, nxt_unit_request_info_t *req)
{
- napi_value constructor, return_val, req_pointer;
- napi_status status;
+ napi_value constructor, res;
+ nxt_unit_request_t *r;
- status = napi_get_named_property(env_, server_obj, "socket",
- &constructor);
- if (status != napi_ok) {
- return nullptr;
- }
+ r = req->request;
- status = napi_new_instance(env_, constructor, 0, NULL, &return_val);
- if (status != napi_ok) {
- return nullptr;
- }
+ constructor = get_named_property(server_obj, "socket");
- status = napi_create_int64(env_, (uintptr_t) req, &req_pointer);
- if (status != napi_ok) {
- return nullptr;
- }
+ res = new_instance(constructor);
- status = napi_set_named_property(env_, return_val, "req_pointer",
- req_pointer);
- if (status != napi_ok) {
- return nullptr;
- }
+ set_named_property(res, "req_pointer", (intptr_t) req);
+ set_named_property(res, "remoteAddress", r->remote, r->remote_length);
+ set_named_property(res, "localAddress", r->local, r->local_length);
- return return_val;
+ return res;
}
napi_value
Unit::create_request(napi_value server_obj, napi_value socket)
{
- napi_value constructor, return_val;
- napi_status status;
+ napi_value constructor, return_val;
- status = napi_get_named_property(env_, server_obj, "request",
- &constructor);
- if (status != napi_ok) {
- return nullptr;
- }
+ constructor = get_named_property(server_obj, "request");
- status = napi_new_instance(env_, constructor, 1, &server_obj,
- &return_val);
- if (status != napi_ok) {
- return nullptr;
- }
+ return_val = new_instance(constructor, server_obj);
- status = napi_set_named_property(env_, return_val, "socket", socket);
- if (status != napi_ok) {
- return nullptr;
- }
+ set_named_property(return_val, "socket", socket);
+ set_named_property(return_val, "connection", socket);
return return_val;
}
@@ -706,37 +444,17 @@ Unit::create_request(napi_value server_obj, napi_value socket)
napi_value
Unit::create_response(napi_value server_obj, napi_value socket,
- napi_value request, nxt_unit_request_info_t *req,
- Unit *obj)
+ napi_value request, nxt_unit_request_info_t *req)
{
- napi_value constructor, return_val, req_num;
- napi_status status;
+ napi_value constructor, return_val;
- status = napi_get_named_property(env_, server_obj, "response",
- &constructor);
- if (status != napi_ok) {
- return nullptr;
- }
+ constructor = get_named_property(server_obj, "response");
- status = napi_new_instance(env_, constructor, 1, &request, &return_val);
- if (status != napi_ok) {
- return nullptr;
- }
+ return_val = new_instance(constructor, request);
- status = napi_set_named_property(env_, return_val, "socket", socket);
- if (status != napi_ok) {
- return nullptr;
- }
-
- status = napi_create_int64(env_, (int64_t) (uintptr_t) req, &req_num);
- if (status != napi_ok) {
- return nullptr;
- }
-
- status = napi_set_named_property(env_, return_val, "_req_point", req_num);
- if (status != napi_ok) {
- return nullptr;
- }
+ set_named_property(return_val, "socket", socket);
+ set_named_property(return_val, "connection", socket);
+ set_named_property(return_val, "_req_point", (intptr_t) req);
return return_val;
}
@@ -749,13 +467,12 @@ Unit::response_send_headers(napi_env env, napi_callback_info info)
char *ptr, *name_ptr;
bool is_array;
size_t argc, name_len, value_len;
- int64_t req_p;
uint32_t status_code, header_len, keys_len, array_len;
uint32_t keys_count, i, j;
uint16_t hash;
+ nxt_napi napi(env);
napi_value this_arg, headers, keys, name, value, array_val;
napi_value req_num, array_entry;
- napi_status status;
napi_valuetype val_type;
nxt_unit_field_t *f;
nxt_unit_request_info_t *req;
@@ -763,137 +480,97 @@ Unit::response_send_headers(napi_env env, napi_callback_info info)
argc = 5;
- status = napi_get_cb_info(env, info, &argc, argv, &this_arg, NULL);
- if (status != napi_ok) {
- return nullptr;
- }
+ try {
+ this_arg = napi.get_cb_info(info, argc, argv);
+ if (argc != 5) {
+ napi.throw_error("Wrong args count. Expected: "
+ "statusCode, headers, headers count, "
+ "headers length");
+ return nullptr;
+ }
- if (argc != 5) {
- napi_throw_error(env, NULL, "Wrong args count. Need three: "
- "statusCode, headers, headers count, headers length");
- return nullptr;
- }
+ req_num = napi.get_named_property(argv[0], "_req_point");
- status = napi_get_named_property(env, argv[0], "_req_point", &req_num);
- if (status != napi_ok) {
- napi_throw_error(env, NULL, "Failed to get request pointer");
- return nullptr;
- }
+ req = napi.get_request_info(req_num);
- status = napi_get_value_int64(env, req_num, &req_p);
- if (status != napi_ok) {
- napi_throw_error(env, NULL, "Failed to get request pointer");
- return nullptr;
- }
+ status_code = napi.get_value_uint32(argv[1]);
+ keys_count = napi.get_value_uint32(argv[3]);
+ header_len = napi.get_value_uint32(argv[4]);
- req = (nxt_unit_request_info_t *) (uintptr_t) req_p;
+ /* Need to reserve extra byte for C-string 0-termination. */
+ header_len++;
- status = napi_get_value_uint32(env, argv[1], &status_code);
- if (status != napi_ok) {
- goto failed;
- }
+ headers = argv[2];
- status = napi_get_value_uint32(env, argv[3], &keys_count);
- if (status != napi_ok) {
- goto failed;
- }
+ ret = nxt_unit_response_init(req, status_code, keys_count, header_len);
+ if (ret != NXT_UNIT_OK) {
+ napi.throw_error("Failed to create response");
+ return nullptr;
+ }
- status = napi_get_value_uint32(env, argv[4], &header_len);
- if (status != napi_ok) {
- goto failed;
- }
+ keys = napi.get_property_names(headers);
+ keys_len = napi.get_array_length(keys);
- /* Need to reserve extra byte for C-string 0-termination. */
- header_len++;
+ ptr = req->response_buf->free;
- headers = argv[2];
+ for (i = 0; i < keys_len; i++) {
+ name = napi.get_element(keys, i);
- ret = nxt_unit_response_init(req, status_code, keys_count, header_len);
- if (ret != NXT_UNIT_OK) {
- goto failed;
- }
+ array_entry = napi.get_property(headers, name);
- status = napi_get_property_names(env, headers, &keys);
- if (status != napi_ok) {
- goto failed;
- }
+ name = napi.get_element(array_entry, 0);
+ value = napi.get_element(array_entry, 1);
- status = napi_get_array_length(env, keys, &keys_len);
- if (status != napi_ok) {
- goto failed;
- }
+ name_len = napi.get_value_string_latin1(name, ptr, header_len);
+ name_ptr = ptr;
- ptr = req->response_buf->free;
+ ptr += name_len;
+ header_len -= name_len;
- for (i = 0; i < keys_len; i++) {
- status = napi_get_element(env, keys, i, &name);
- if (status != napi_ok) {
- goto failed;
- }
+ hash = nxt_unit_field_hash(name_ptr, name_len);
- status = napi_get_property(env, headers, name, &array_entry);
- if (status != napi_ok) {
- goto failed;
- }
+ is_array = napi.is_array(value);
- status = napi_get_element(env, array_entry, 0, &name);
- if (status != napi_ok) {
- goto failed;
- }
+ if (is_array) {
+ array_len = napi.get_array_length(value);
- status = napi_get_element(env, array_entry, 1, &value);
- if (status != napi_ok) {
- goto failed;
- }
+ for (j = 0; j < array_len; j++) {
+ array_val = napi.get_element(value, j);
- status = napi_get_value_string_latin1(env, name, ptr, header_len,
- &name_len);
- if (status != napi_ok) {
- goto failed;
- }
+ val_type = napi.type_of(array_val);
- name_ptr = ptr;
+ if (val_type != napi_string) {
+ array_val = napi.coerce_to_string(array_val);
+ }
- ptr += name_len;
- header_len -= name_len;
+ value_len = napi.get_value_string_latin1(array_val, ptr,
+ header_len);
- hash = nxt_unit_field_hash(name_ptr, name_len);
+ f = req->response->fields + req->response->fields_count;
+ f->skip = 0;
- status = napi_is_array(env, value, &is_array);
- if (status != napi_ok) {
- goto failed;
- }
+ nxt_unit_sptr_set(&f->name, name_ptr);
- if (is_array) {
- status = napi_get_array_length(env, value, &array_len);
- if (status != napi_ok) {
- goto failed;
- }
+ f->name_length = name_len;
+ f->hash = hash;
- for (j = 0; j < array_len; j++) {
- status = napi_get_element(env, value, j, &array_val);
- if (status != napi_ok) {
- goto failed;
- }
+ nxt_unit_sptr_set(&f->value, ptr);
+ f->value_length = (uint32_t) value_len;
- napi_typeof(env, array_val, &val_type);
- if (status != napi_ok) {
- goto failed;
+ ptr += value_len;
+ header_len -= value_len;
+
+ req->response->fields_count++;
}
+ } else {
+ val_type = napi.type_of(value);
+
if (val_type != napi_string) {
- status = napi_coerce_to_string(env, array_val, &array_val);
- if (status != napi_ok) {
- goto failed;
- }
+ value = napi.coerce_to_string(value);
}
- status = napi_get_value_string_latin1(env, array_val, ptr,
- header_len,
- &value_len);
- if (status != napi_ok) {
- goto failed;
- }
+ value_len = napi.get_value_string_latin1(value, ptr, header_len);
f = req->response->fields + req->response->fields_count;
f->skip = 0;
@@ -911,60 +588,22 @@ Unit::response_send_headers(napi_env env, napi_callback_info info)
req->response->fields_count++;
}
-
- } else {
- napi_typeof(env, value, &val_type);
- if (status != napi_ok) {
- goto failed;
- }
-
- if (val_type != napi_string) {
- status = napi_coerce_to_string(env, value, &value);
- if (status != napi_ok) {
- goto failed;
- }
- }
-
- status = napi_get_value_string_latin1(env, value, ptr, header_len,
- &value_len);
- if (status != napi_ok) {
- goto failed;
- }
-
- f = req->response->fields + req->response->fields_count;
- f->skip = 0;
-
- nxt_unit_sptr_set(&f->name, name_ptr);
-
- f->name_length = name_len;
- f->hash = hash;
-
- nxt_unit_sptr_set(&f->value, ptr);
- f->value_length = (uint32_t) value_len;
-
- ptr += value_len;
- header_len -= value_len;
-
- req->response->fields_count++;
}
+
+ } catch (exception &e) {
+ napi.throw_error(e);
+ return nullptr;
}
req->response_buf->free = ptr;
ret = nxt_unit_response_send(req);
if (ret != NXT_UNIT_OK) {
- goto failed;
+ napi.throw_error("Failed to send response");
+ return nullptr;
}
return this_arg;
-
-failed:
-
- req->response->fields_count = 0;
-
- napi_throw_error(env, NULL, "Failed to write headers");
-
- return nullptr;
}
@@ -974,8 +613,8 @@ Unit::response_write(napi_env env, napi_callback_info info)
int ret;
char *ptr;
size_t argc, have_buf_len;
- int64_t req_p;
uint32_t buf_len;
+ nxt_napi napi(env);
napi_value this_arg, req_num;
napi_status status;
nxt_unit_buf_t *buf;
@@ -985,39 +624,23 @@ Unit::response_write(napi_env env, napi_callback_info info)
argc = 3;
- status = napi_get_cb_info(env, info, &argc, argv, &this_arg, NULL);
- if (status != napi_ok) {
- goto failed;
- }
-
- if (argc != 3) {
- napi_throw_error(env, NULL, "Wrong args count. Need two: "
- "chunk, chunk length");
- return nullptr;
- }
-
- status = napi_get_named_property(env, argv[0], "_req_point", &req_num);
- if (status != napi_ok) {
- napi_throw_error(env, NULL, "Failed to get request pointer");
- return nullptr;
- }
+ try {
+ this_arg = napi.get_cb_info(info, argc, argv);
+ if (argc != 3) {
+ throw exception("Wrong args count. Expected: "
+ "chunk, chunk length");
+ }
- status = napi_get_value_int64(env, req_num, &req_p);
- if (status != napi_ok) {
- napi_throw_error(env, NULL, "Failed to get request pointer");
- return nullptr;
- }
+ req_num = napi.get_named_property(argv[0], "_req_point");
+ req = napi.get_request_info(req_num);
- req = (nxt_unit_request_info_t *) (uintptr_t) req_p;
+ buf_len = napi.get_value_uint32(argv[2]);
- status = napi_get_value_uint32(env, argv[2], &buf_len);
- if (status != napi_ok) {
- goto failed;
- }
+ buf_type = napi.type_of(argv[1]);
- status = napi_typeof(env, argv[1], &buf_type);
- if (status != napi_ok) {
- goto failed;
+ } catch (exception &e) {
+ napi.throw_error(e);
+ return nullptr;
}
buf_len++;
@@ -1055,7 +678,7 @@ Unit::response_write(napi_env env, napi_callback_info info)
failed:
- napi_throw_error(env, NULL, "Failed to write body");
+ napi.throw_error("Failed to write body");
return nullptr;
}
@@ -1065,33 +688,23 @@ napi_value
Unit::response_end(napi_env env, napi_callback_info info)
{
size_t argc;
- int64_t req_p;
+ nxt_napi napi(env);
napi_value resp, this_arg, req_num;
- napi_status status;
nxt_unit_request_info_t *req;
argc = 1;
- status = napi_get_cb_info(env, info, &argc, &resp, &this_arg, NULL);
- if (status != napi_ok) {
- napi_throw_error(env, NULL, "Failed to finalize sending body");
- return nullptr;
- }
+ try {
+ this_arg = napi.get_cb_info(info, argc, &resp);
- status = napi_get_named_property(env, resp, "_req_point", &req_num);
- if (status != napi_ok) {
- napi_throw_error(env, NULL, "Failed to get request pointer");
- return nullptr;
- }
+ req_num = napi.get_named_property(resp, "_req_point");
+ req = napi.get_request_info(req_num);
- status = napi_get_value_int64(env, req_num, &req_p);
- if (status != napi_ok) {
- napi_throw_error(env, NULL, "Failed to get request pointer");
+ } catch (exception &e) {
+ napi.throw_error(e);
return nullptr;
}
- req = (nxt_unit_request_info_t *) (uintptr_t) req_p;
-
nxt_unit_request_done(req, NXT_UNIT_OK);
return this_arg;
diff --git a/src/nodejs/unit-http/unit.h b/src/nodejs/unit-http/unit.h
index db85e85c..e76d805a 100644
--- a/src/nodejs/unit-http/unit.h
+++ b/src/nodejs/unit-http/unit.h
@@ -6,34 +6,15 @@
#ifndef _NXT_NODEJS_UNIT_H_INCLUDED_
#define _NXT_NODEJS_UNIT_H_INCLUDED_
-#include <node_api.h>
+#include "nxt_napi.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-#include "version.h"
-#include <nxt_unit.h>
-
-#if NXT_VERNUM != NXT_NODE_VERNUM
-#error "libunit version mismatch."
-#endif
-
-#include <nxt_unit_response.h>
-#include <nxt_unit_request.h>
-
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-
-class Unit {
+class Unit : public nxt_napi {
public:
static napi_value init(napi_env env, napi_value exports);
private:
- Unit(napi_env env);
+ Unit(napi_env env, napi_value jsthis);
~Unit();
static napi_value create(napi_env env, napi_callback_info info);
@@ -56,7 +37,7 @@ private:
napi_value create_response(napi_value server_obj, napi_value socket,
napi_value request,
- nxt_unit_request_info_t *req, Unit *obj);
+ nxt_unit_request_info_t *req);
static napi_value response_send_headers(napi_env env,
napi_callback_info info);
@@ -64,18 +45,16 @@ private:
static napi_value response_write(napi_env env, napi_callback_info info);
static napi_value response_end(napi_env env, napi_callback_info info);
- napi_status create_headers(nxt_unit_request_info_t *req,
- napi_value request);
+ void create_headers(nxt_unit_request_info_t *req, napi_value request);
- inline napi_status append_header(nxt_unit_field_t *f, napi_value headers,
+ void append_header(nxt_unit_field_t *f, napi_value headers,
napi_value raw_headers, uint32_t idx);
static napi_ref constructor_;
- napi_env env_;
napi_ref wrapper_;
nxt_unit_ctx_t *unit_ctx_;
};
-#endif /* _NXT_NODEJS_H_INCLUDED_ */
+#endif /* _NXT_NODEJS_UNIT_H_INCLUDED_ */
diff --git a/src/nxt_application.c b/src/nxt_application.c
index a2827b75..f63b90fb 100644
--- a/src/nxt_application.c
+++ b/src/nxt_application.c
@@ -36,8 +36,6 @@ static nxt_app_module_t *nxt_app_module_load(nxt_task_t *task,
const char *name);
static nxt_int_t nxt_app_set_environment(nxt_conf_value_t *environment);
-static void nxt_app_http_release(nxt_task_t *task, void *obj, void *data);
-
static uint32_t compat[] = {
NXT_VERNUM, NXT_DEBUG,
@@ -431,32 +429,6 @@ nxt_app_set_environment(nxt_conf_value_t *environment)
}
-nxt_int_t
-nxt_app_http_req_done(nxt_task_t *task, nxt_app_parse_ctx_t *ar)
-{
- ar->timer.handler = nxt_app_http_release;
- nxt_timer_add(task->thread->engine, &ar->timer, 0);
-
- return NXT_OK;
-}
-
-
-static void
-nxt_app_http_release(nxt_task_t *task, void *obj, void *data)
-{
- nxt_timer_t *timer;
- nxt_app_parse_ctx_t *ar;
-
- timer = obj;
-
- nxt_debug(task, "http app release");
-
- ar = nxt_timer_data(timer, nxt_app_parse_ctx_t, timer);
-
- nxt_mp_release(ar->request->mem_pool);
-}
-
-
nxt_app_lang_module_t *
nxt_app_lang_module(nxt_runtime_t *rt, nxt_str_t *name)
{
diff --git a/src/nxt_application.h b/src/nxt_application.h
index 781f05e0..7ff4bb11 100644
--- a/src/nxt_application.h
+++ b/src/nxt_application.h
@@ -99,62 +99,6 @@ struct nxt_common_app_conf_s {
};
-typedef struct {
- nxt_str_t method;
- nxt_str_t target;
- nxt_str_t version;
- nxt_str_t path;
- nxt_str_t query;
- nxt_str_t server_name;
-
- nxt_list_t *fields;
-
- nxt_str_t cookie;
- nxt_str_t content_length;
- nxt_str_t content_type;
-
- off_t parsed_content_length;
- nxt_bool_t done;
-
- size_t bufs;
- nxt_buf_t *buf;
-} nxt_app_request_header_t;
-
-
-typedef struct {
- size_t preread_size;
- nxt_bool_t done;
-
- nxt_buf_t *buf;
-} nxt_app_request_body_t;
-
-
-typedef struct {
- nxt_app_request_header_t header;
- nxt_app_request_body_t body;
-
- nxt_str_t remote;
- nxt_str_t local;
-} nxt_app_request_t;
-
-
-typedef struct nxt_app_parse_ctx_s nxt_app_parse_ctx_t;
-
-
-struct nxt_app_parse_ctx_s {
- nxt_app_request_t r;
- nxt_http_request_t *request;
- nxt_timer_t timer;
- void *timer_data;
- nxt_http_request_parse_t parser;
- nxt_http_request_parse_t resp_parser;
- nxt_mp_t *mem_pool;
-};
-
-
-nxt_int_t nxt_app_http_req_done(nxt_task_t *task, nxt_app_parse_ctx_t *ctx);
-
-
struct nxt_app_module_s {
size_t compat_length;
uint32_t *compat;
diff --git a/src/nxt_buf.h b/src/nxt_buf.h
index d9d4ee1b..9c22d650 100644
--- a/src/nxt_buf.h
+++ b/src/nxt_buf.h
@@ -206,7 +206,7 @@ nxt_buf_set_last(b) \
#define \
nxt_buf_clear_last(b) \
- (b)->is_last = 0
+ (b)->is_last = 0
#define \
diff --git a/src/nxt_conf.c b/src/nxt_conf.c
index 4c6d8839..57870838 100644
--- a/src/nxt_conf.c
+++ b/src/nxt_conf.c
@@ -87,7 +87,6 @@ struct nxt_conf_op_s {
uint32_t index;
uint32_t action; /* nxt_conf_op_action_t */
void *ctx;
- nxt_conf_op_t *next;
};
@@ -113,6 +112,8 @@ static void nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos,
static nxt_int_t nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op,
nxt_conf_value_t *dst, nxt_conf_value_t *src);
+static nxt_int_t nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op,
+ nxt_conf_value_t *dst, nxt_conf_value_t *src);
static nxt_int_t nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op,
nxt_conf_value_t *dst, nxt_conf_value_t *src);
@@ -736,12 +737,14 @@ nxt_conf_array_qsort(nxt_conf_value_t *value,
}
-nxt_int_t
+nxt_conf_op_ret_t
nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root,
- nxt_str_t *path, nxt_conf_value_t *value)
+ nxt_str_t *path, nxt_conf_value_t *value, nxt_bool_t add)
{
nxt_str_t token;
+ nxt_int_t index;
nxt_conf_op_t *op, **parent;
+ nxt_conf_value_t *node;
nxt_conf_path_parse_t parse;
nxt_conf_object_member_t *member;
@@ -754,7 +757,7 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root,
for ( ;; ) {
op = nxt_mp_zget(mp, sizeof(nxt_conf_op_t));
if (nxt_slow_path(op == NULL)) {
- return NXT_ERROR;
+ return NXT_CONF_OP_ERROR;
}
*parent = op;
@@ -762,50 +765,107 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root,
nxt_conf_path_next_token(&parse, &token);
- root = nxt_conf_get_object_member(root, &token, &op->index);
+ switch (root->type) {
+
+ case NXT_CONF_VALUE_OBJECT:
+ node = nxt_conf_get_object_member(root, &token, &op->index);
+ break;
+
+ case NXT_CONF_VALUE_ARRAY:
+ index = nxt_int_parse(token.start, token.length);
+
+ if (index < 0 || index > NXT_INT32_T_MAX) {
+ return NXT_CONF_OP_NOT_FOUND;
+ }
+
+ op->index = index;
+
+ node = nxt_conf_get_array_element(root, index);
+ break;
+
+ default:
+ node = NULL;
+ }
if (parse.last) {
break;
}
- if (root == NULL) {
- return NXT_DECLINED;
+ if (node == NULL) {
+ return NXT_CONF_OP_NOT_FOUND;
}
op->action = NXT_CONF_OP_PASS;
+ root = node;
}
if (value == NULL) {
- if (root == NULL) {
- return NXT_DECLINED;
+ if (node == NULL) {
+ return NXT_CONF_OP_NOT_FOUND;
}
op->action = NXT_CONF_OP_DELETE;
- return NXT_OK;
+ return NXT_CONF_OP_OK;
+ }
+
+ if (add) {
+ if (node == NULL) {
+ return NXT_CONF_OP_NOT_FOUND;
+ }
+
+ if (node->type != NXT_CONF_VALUE_ARRAY) {
+ return NXT_CONF_OP_NOT_ALLOWED;
+ }
+
+ op->action = NXT_CONF_OP_PASS;
+
+ op = nxt_mp_zget(mp, sizeof(nxt_conf_op_t));
+ if (nxt_slow_path(op == NULL)) {
+ return NXT_CONF_OP_ERROR;
+ }
+
+ *parent = op;
+
+ op->index = node->u.array->count;
+ op->action = NXT_CONF_OP_CREATE;
+ op->ctx = value;
+
+ return NXT_CONF_OP_OK;
+ }
+
+ if (node != NULL) {
+ op->action = NXT_CONF_OP_REPLACE;
+ op->ctx = value;
+
+ return NXT_CONF_OP_OK;
}
- if (root == NULL) {
+ op->action = NXT_CONF_OP_CREATE;
+ if (root->type == NXT_CONF_VALUE_ARRAY) {
+ if (op->index > root->u.array->count) {
+ return NXT_CONF_OP_NOT_FOUND;
+ }
+
+ op->ctx = value;
+
+ } else {
member = nxt_mp_zget(mp, sizeof(nxt_conf_object_member_t));
if (nxt_slow_path(member == NULL)) {
- return NXT_ERROR;
+ return NXT_CONF_OP_ERROR;
}
nxt_conf_set_string(&member->name, &token);
member->value = *value;
- op->action = NXT_CONF_OP_CREATE;
+ op->index = root->u.object->count;
op->ctx = member;
-
- } else {
- op->action = NXT_CONF_OP_REPLACE;
- op->ctx = value;
}
- return NXT_OK;
+ return NXT_CONF_OP_OK;
}
@@ -834,16 +894,13 @@ static nxt_int_t
nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
nxt_conf_value_t *src)
{
- size_t size;
- nxt_int_t rc;
- nxt_uint_t n;
-
- if (op != NULL && src->type != NXT_CONF_VALUE_OBJECT) {
+ if (op != NULL
+ && src->type != NXT_CONF_VALUE_ARRAY
+ && src->type != NXT_CONF_VALUE_OBJECT)
+ {
return NXT_ERROR;
}
- dst->type = src->type;
-
switch (src->type) {
case NXT_CONF_VALUE_STRING:
@@ -861,34 +918,116 @@ nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
break;
case NXT_CONF_VALUE_ARRAY:
+ return nxt_conf_copy_array(mp, op, dst, src);
- size = sizeof(nxt_conf_array_t)
- + src->u.array->count * sizeof(nxt_conf_value_t);
+ case NXT_CONF_VALUE_OBJECT:
+ return nxt_conf_copy_object(mp, op, dst, src);
- dst->u.array = nxt_mp_get(mp, size);
- if (nxt_slow_path(dst->u.array == NULL)) {
- return NXT_ERROR;
+ default:
+ dst->u = src->u;
+ }
+
+ dst->type = src->type;
+
+ return NXT_OK;
+}
+
+
+static nxt_int_t
+nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
+ nxt_conf_value_t *src)
+{
+ size_t size;
+ nxt_int_t rc;
+ nxt_uint_t s, d, count, index;
+ nxt_conf_op_t *pass_op;
+ nxt_conf_value_t *value;
+
+ count = src->u.array->count;
+
+ if (op != NULL) {
+ if (op->action == NXT_CONF_OP_CREATE) {
+ count++;
+
+ } else if (op->action == NXT_CONF_OP_DELETE) {
+ count--;
}
+ }
+
+ size = sizeof(nxt_conf_array_t) + count * sizeof(nxt_conf_value_t);
+
+ dst->u.array = nxt_mp_get(mp, size);
+ if (nxt_slow_path(dst->u.array == NULL)) {
+ return NXT_ERROR;
+ }
+
+ dst->u.array->count = count;
+
+ s = 0;
+ d = 0;
- dst->u.array->count = src->u.array->count;
+ pass_op = NULL;
- for (n = 0; n < src->u.array->count; n++) {
- rc = nxt_conf_copy_value(mp, NULL, &dst->u.array->elements[n],
- &src->u.array->elements[n]);
+ /*
+ * This initialization is needed only to
+ * suppress a warning on GCC 4.8 and older.
+ */
+ index = 0;
+
+ do {
+ if (pass_op == NULL) {
+ index = (op == NULL) ? src->u.array->count : op->index;
+ }
+ while (s != index) {
+ rc = nxt_conf_copy_value(mp, pass_op, &dst->u.array->elements[d],
+ &src->u.array->elements[s]);
if (nxt_slow_path(rc != NXT_OK)) {
return NXT_ERROR;
}
+
+ s++;
+ d++;
}
- break;
+ if (pass_op != NULL) {
+ pass_op = NULL;
+ continue;
+ }
- case NXT_CONF_VALUE_OBJECT:
- return nxt_conf_copy_object(mp, op, dst, src);
+ if (op != NULL) {
+ switch (op->action) {
+ case NXT_CONF_OP_PASS:
+ pass_op = op->ctx;
+ index++;
+ break;
- default:
- dst->u = src->u;
- }
+ case NXT_CONF_OP_CREATE:
+ value = op->ctx;
+ dst->u.array->elements[d] = *value;
+
+ d++;
+ break;
+
+ case NXT_CONF_OP_REPLACE:
+ value = op->ctx;
+ dst->u.array->elements[d] = *value;
+
+ s++;
+ d++;
+ break;
+
+ case NXT_CONF_OP_DELETE:
+ s++;
+ break;
+ }
+
+ op = NULL;
+ }
+
+ } while (d != count);
+
+ dst->type = src->type;
return NXT_OK;
}
@@ -939,9 +1078,7 @@ nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
do {
if (pass_op == NULL) {
- index = (op == NULL || op->action == NXT_CONF_OP_CREATE)
- ? src->u.object->count
- : op->index;
+ index = (op == NULL) ? src->u.object->count : op->index;
}
while (s != index) {
@@ -1015,7 +1152,7 @@ nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
break;
}
- op = op->next;
+ op = NULL;
}
} while (d != count);
diff --git a/src/nxt_conf.h b/src/nxt_conf.h
index 20ff3b1e..2435b0e2 100644
--- a/src/nxt_conf.h
+++ b/src/nxt_conf.h
@@ -20,6 +20,14 @@ typedef enum {
} nxt_conf_type_t;
+typedef enum {
+ NXT_CONF_OP_OK = 0,
+ NXT_CONF_OP_NOT_FOUND,
+ NXT_CONF_OP_NOT_ALLOWED,
+ NXT_CONF_OP_ERROR,
+} nxt_conf_op_ret_t;
+
+
typedef struct nxt_conf_value_s nxt_conf_value_t;
typedef struct nxt_conf_op_s nxt_conf_op_t;
@@ -80,8 +88,9 @@ NXT_EXPORT nxt_conf_value_t *nxt_conf_get_array_element(nxt_conf_value_t *value,
NXT_EXPORT nxt_int_t nxt_conf_map_object(nxt_mp_t *mp, nxt_conf_value_t *value,
nxt_conf_map_t *map, nxt_uint_t n, void *data);
-nxt_int_t nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops,
- nxt_conf_value_t *root, nxt_str_t *path, nxt_conf_value_t *value);
+nxt_conf_op_ret_t nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops,
+ nxt_conf_value_t *root, nxt_str_t *path, nxt_conf_value_t *value,
+ nxt_bool_t add);
nxt_conf_value_t *nxt_conf_clone(nxt_mp_t *mp, nxt_conf_op_t *op,
nxt_conf_value_t *value);
diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c
index 5653b9eb..bee82dd4 100644
--- a/src/nxt_conf_validation.c
+++ b/src/nxt_conf_validation.c
@@ -66,6 +66,12 @@ static nxt_int_t nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
+static nxt_int_t nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt,
+ nxt_conf_value_t *value, void *data);
+static nxt_int_t nxt_conf_vldt_match_patterns_set(nxt_conf_validation_t *vldt,
+ nxt_conf_value_t *value);
+static nxt_int_t nxt_conf_vldt_match_patterns_set_member(
+ nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_app(nxt_conf_validation_t *vldt,
@@ -218,6 +224,21 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_match_members[] = {
&nxt_conf_vldt_match_patterns,
NULL },
+ { nxt_string("arguments"),
+ NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY,
+ &nxt_conf_vldt_match_patterns_sets,
+ NULL },
+
+ { nxt_string("headers"),
+ NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY,
+ &nxt_conf_vldt_match_patterns_sets,
+ NULL },
+
+ { nxt_string("cookies"),
+ NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY,
+ &nxt_conf_vldt_match_patterns_sets,
+ NULL },
+
NXT_CONF_VLDT_END
};
@@ -741,9 +762,15 @@ nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt,
nxt_str_t pattern;
nxt_uint_t i, first, last;
+ enum {
+ sw_none,
+ sw_side,
+ sw_middle
+ } state;
+
if (nxt_conf_type(value) != NXT_CONF_STRING) {
- return nxt_conf_vldt_error(vldt,
- "The \"match\" patterns must be strings.");
+ return nxt_conf_vldt_error(vldt, "The \"match\" patterns for \"host\", "
+ "\"uri\", and \"method\" must be strings.");
}
nxt_conf_get_string(value, &pattern);
@@ -754,17 +781,37 @@ nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt,
first = (pattern.start[0] == '!');
last = pattern.length - 1;
+ state = sw_none;
for (i = first; i != pattern.length; i++) {
+
ch = pattern.start[i];
if (ch != '*') {
continue;
}
- if (i != first && i != last) {
- return nxt_conf_vldt_error(vldt, "The \"match\" patterns can only "
- "contain \"*\" markers at the sides.");
+ switch (state) {
+ case sw_none:
+ state = (i == first) ? sw_side : sw_middle;
+ break;
+
+ case sw_side:
+ if (i == last) {
+ if (last - first != 1) {
+ break;
+ }
+
+ return nxt_conf_vldt_error(vldt, "The \"match\" pattern must "
+ "not contain double \"*\" markers.");
+ }
+
+ /* Fall through. */
+
+ case sw_middle:
+ return nxt_conf_vldt_error(vldt, "The \"match\" patterns can "
+ "either contain \"*\" markers at "
+ "the sides or only one in the middle.");
}
}
@@ -772,6 +819,49 @@ nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt,
}
+static nxt_int_t
+nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt,
+ nxt_conf_value_t *value, void *data)
+{
+ if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
+ return nxt_conf_vldt_array_iterator(vldt, value,
+ &nxt_conf_vldt_match_patterns_set);
+ }
+
+ /* NXT_CONF_OBJECT */
+
+ return nxt_conf_vldt_match_patterns_set(vldt, value);
+}
+
+
+static nxt_int_t
+nxt_conf_vldt_match_patterns_set(nxt_conf_validation_t *vldt,
+ nxt_conf_value_t *value)
+{
+ if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
+ return nxt_conf_vldt_error(vldt, "The \"match\" patterns for "
+ "\"arguments\", \"cookies\", and "
+ "\"headers\" must be objects.");
+ }
+
+ return nxt_conf_vldt_object_iterator(vldt, value,
+ &nxt_conf_vldt_match_patterns_set_member);
+}
+
+
+static nxt_int_t
+nxt_conf_vldt_match_patterns_set_member(nxt_conf_validation_t *vldt,
+ nxt_str_t *name, nxt_conf_value_t *value)
+{
+ if (name->length == 0) {
+ return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must "
+ "not contain empty member names.");
+ }
+
+ return nxt_conf_vldt_match_patterns(vldt, value, NULL);
+}
+
+
#if (NXT_TLS)
static nxt_int_t
@@ -1268,6 +1358,7 @@ nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt, nxt_conf_value_t *valu
return NXT_OK;
}
+
static nxt_int_t
nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
{
diff --git a/src/nxt_controller.c b/src/nxt_controller.c
index 29838bd9..49afbe46 100644
--- a/src/nxt_controller.c
+++ b/src/nxt_controller.c
@@ -184,6 +184,7 @@ nxt_controller_start(nxt_task_t *task, void *data)
vldt.pool = nxt_mp_create(1024, 128, 256, 32);
if (nxt_slow_path(vldt.pool == NULL)) {
+ nxt_mp_destroy(mp);
return NXT_ERROR;
}
@@ -929,6 +930,7 @@ nxt_controller_process_config(nxt_task_t *task, nxt_controller_request_t *req,
nxt_mp_t *mp;
nxt_int_t rc;
nxt_conn_t *c;
+ nxt_bool_t post;
nxt_buf_mem_t *mbuf;
nxt_conf_op_t *ops;
nxt_conf_value_t *value;
@@ -957,7 +959,18 @@ nxt_controller_process_config(nxt_task_t *task, nxt_controller_request_t *req,
return;
}
- if (nxt_str_eq(&req->parser.method, "PUT", 3)) {
+ if (nxt_str_eq(&req->parser.method, "POST", 4)) {
+ if (path->length == 1) {
+ goto not_allowed;
+ }
+
+ post = 1;
+
+ } else {
+ post = 0;
+ }
+
+ if (post || nxt_str_eq(&req->parser.method, "PUT", 3)) {
if (!nxt_queue_is_empty(&nxt_controller_waiting_requests)) {
nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link);
@@ -999,15 +1012,20 @@ nxt_controller_process_config(nxt_task_t *task, nxt_controller_request_t *req,
if (path->length != 1) {
rc = nxt_conf_op_compile(c->mem_pool, &ops,
nxt_controller_conf.root,
- path, value);
+ path, value, post);
- if (rc != NXT_OK) {
+ if (rc != NXT_CONF_OP_OK) {
nxt_mp_destroy(mp);
- if (rc == NXT_DECLINED) {
+ switch (rc) {
+ case NXT_CONF_OP_NOT_FOUND:
goto not_found;
+
+ case NXT_CONF_OP_NOT_ALLOWED:
+ goto not_allowed;
}
+ /* rc == NXT_CONF_OP_ERROR */
goto alloc_fail;
}
@@ -1079,13 +1097,14 @@ nxt_controller_process_config(nxt_task_t *task, nxt_controller_request_t *req,
} else {
rc = nxt_conf_op_compile(c->mem_pool, &ops,
nxt_controller_conf.root,
- path, NULL);
+ path, NULL, 0);
if (rc != NXT_OK) {
- if (rc == NXT_DECLINED) {
+ if (rc == NXT_CONF_OP_NOT_FOUND) {
goto not_found;
}
+ /* rc == NXT_CONF_OP_ERROR */
goto alloc_fail;
}
@@ -1144,8 +1163,10 @@ nxt_controller_process_config(nxt_task_t *task, nxt_controller_request_t *req,
return;
}
+not_allowed:
+
resp.status = 405;
- resp.title = (u_char *) "Invalid method.";
+ resp.title = (u_char *) "Method isn't allowed.";
resp.offset = -1;
nxt_controller_response(task, req, &resp);
diff --git a/src/nxt_epoll_engine.c b/src/nxt_epoll_engine.c
index 9f9c8f62..9cdaab9b 100644
--- a/src/nxt_epoll_engine.c
+++ b/src/nxt_epoll_engine.c
@@ -1059,7 +1059,7 @@ nxt_epoll_edge_conn_io_connect(nxt_task_t *task, void *obj, void *data)
state = c->write_state;
- switch (nxt_socket_connect(task, c->socket.fd, c->remote) ){
+ switch (nxt_socket_connect(task, c->socket.fd, c->remote)) {
case NXT_OK:
c->socket.write_ready = 1;
diff --git a/src/nxt_errno.h b/src/nxt_errno.h
index b3d7105a..e3ce8349 100644
--- a/src/nxt_errno.h
+++ b/src/nxt_errno.h
@@ -45,6 +45,7 @@ typedef int nxt_err_t;
#define NXT_EILSEQ EILSEQ
#define NXT_ETIME ETIME
#define NXT_ENOMOREFILES 0
+#define NXT_ENOBUFS ENOBUFS
#if (NXT_HPUX)
/* HP-UX uses EWOULDBLOCK instead of EAGAIN. */
diff --git a/src/nxt_h1proto.c b/src/nxt_h1proto.c
index 07e3c7bc..3a822042 100644
--- a/src/nxt_h1proto.c
+++ b/src/nxt_h1proto.c
@@ -35,6 +35,7 @@ static void nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r);
static void nxt_h1p_conn_request_body_read(nxt_task_t *task, void *obj,
void *data);
static void nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r);
+static void nxt_h1p_request_tls(nxt_task_t *task, nxt_http_request_t *r);
static void nxt_h1p_request_header_send(nxt_task_t *task,
nxt_http_request_t *r);
static void nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r,
@@ -103,6 +104,13 @@ const nxt_http_proto_local_addr_t nxt_http_proto_local_addr[3] = {
};
+const nxt_http_proto_tls_t nxt_http_proto_tls[3] = {
+ nxt_h1p_request_tls,
+ NULL,
+ NULL,
+};
+
+
const nxt_http_proto_header_send_t nxt_http_proto_header_send[3] = {
nxt_h1p_request_header_send,
NULL,
@@ -813,6 +821,15 @@ nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r)
}
+static void
+nxt_h1p_request_tls(nxt_task_t *task, nxt_http_request_t *r)
+{
+#if (NXT_TLS)
+ r->tls = r->proto.h1->conn->u.tls;
+#endif
+}
+
+
#define NXT_HTTP_LAST_SUCCESS \
(NXT_HTTP_OK + nxt_nitems(nxt_http_success) - 1)
diff --git a/src/nxt_hpux_sendfile.c b/src/nxt_hpux_sendfile.c
index 3c42c559..df200b64 100644
--- a/src/nxt_hpux_sendfile.c
+++ b/src/nxt_hpux_sendfile.c
@@ -13,7 +13,7 @@ ssize_t nxt_hpux_event_conn_io_sendfile(nxt_event_conn_t *c, nxt_buf_t *b,
size_t limit);
static ssize_t nxt_sys_sendfile(int s, int fd, off_t offset, size_t nbytes,
- const struct iovec *hdtrl, int flags)
+ const struct iovec *hdtrl, int flags)
{
return -1;
}
@@ -23,7 +23,7 @@ static ssize_t nxt_sys_sendfile(int s, int fd, off_t offset, size_t nbytes,
/* sendfile() is not declared if _XOPEN_SOURCE_EXTENDED is defined. */
sbsize_t sendfile(int s, int fd, off_t offset, bsize_t nbytes,
- const struct iovec *hdtrl, int flags);
+ const struct iovec *hdtrl, int flags);
#define nxt_sys_sendfile sendfile
diff --git a/src/nxt_http.h b/src/nxt_http.h
index 23c406d3..835cf66d 100644
--- a/src/nxt_http.h
+++ b/src/nxt_http.h
@@ -114,12 +114,15 @@ struct nxt_http_request_s {
const nxt_http_request_state_t *state;
nxt_str_t host;
+ nxt_str_t server_name;
nxt_str_t target;
nxt_str_t version;
nxt_str_t *method;
nxt_str_t *path;
nxt_str_t *args;
+ nxt_array_t *arguments; /* of nxt_http_name_value_t */
+ nxt_array_t *cookies; /* of nxt_http_name_value_t */
nxt_list_t *fields;
nxt_http_field_t *content_type;
nxt_http_field_t *content_length;
@@ -130,6 +133,10 @@ struct nxt_http_request_s {
nxt_sockaddr_t *remote;
nxt_sockaddr_t *local;
+ void *tls;
+
+ nxt_timer_t timer;
+ void *timer_data;
nxt_buf_t *last;
@@ -165,6 +172,7 @@ typedef void (*nxt_http_proto_body_read_t)(nxt_task_t *task,
nxt_http_request_t *r);
typedef void (*nxt_http_proto_local_addr_t)(nxt_task_t *task,
nxt_http_request_t *r);
+typedef void (*nxt_http_proto_tls_t)(nxt_task_t *task, nxt_http_request_t *r);
typedef void (*nxt_http_proto_header_send_t)(nxt_task_t *task,
nxt_http_request_t *r);
typedef void (*nxt_http_proto_send_t)(nxt_task_t *task, nxt_http_request_t *r,
@@ -186,7 +194,6 @@ nxt_http_request_t *nxt_http_request_create(nxt_task_t *task);
void nxt_http_request_error(nxt_task_t *task, nxt_http_request_t *r,
nxt_http_status_t status);
void nxt_http_request_read_body(nxt_task_t *task, nxt_http_request_t *r);
-void nxt_http_request_local_addr(nxt_task_t *task, nxt_http_request_t *r);
void nxt_http_request_header_send(nxt_task_t *task, nxt_http_request_t *r);
void nxt_http_request_send(nxt_task_t *task, nxt_http_request_t *r,
nxt_buf_t *out);
@@ -221,6 +228,7 @@ extern nxt_lvlhsh_t nxt_response_fields_hash;
extern const nxt_http_proto_body_read_t nxt_http_proto_body_read[];
extern const nxt_http_proto_local_addr_t nxt_http_proto_local_addr[];
+extern const nxt_http_proto_tls_t nxt_http_proto_tls[];
extern const nxt_http_proto_header_send_t nxt_http_proto_header_send[];
extern const nxt_http_proto_send_t nxt_http_proto_send[];
extern const nxt_http_proto_body_bytes_sent_t nxt_http_proto_body_bytes_sent[];
diff --git a/src/nxt_http_parse.c b/src/nxt_http_parse.c
index 34eaaaf9..05df245e 100644
--- a/src/nxt_http_parse.c
+++ b/src/nxt_http_parse.c
@@ -34,10 +34,6 @@ static nxt_int_t nxt_http_field_hash_collision(nxt_lvlhsh_query_t *lhq,
#define NXT_HTTP_FIELD_LVLHSH_SHIFT 5
-#define NXT_HTTP_FIELD_HASH_INIT 159406
-#define nxt_http_field_hash_char(h, c) (((h) << 4) + (h) + (c))
-#define nxt_http_field_hash_end(h) (((h) >> 16) ^ (h))
-
typedef enum {
NXT_HTTP_TARGET_SPACE = 1, /* \s */
@@ -119,7 +115,7 @@ nxt_http_parse_request_init(nxt_http_request_parse_t *rp, nxt_mp_t *mp)
rp->mem_pool = mp;
rp->fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t));
- if (nxt_slow_path(rp->fields == NULL)){
+ if (nxt_slow_path(rp->fields == NULL)) {
return NXT_ERROR;
}
diff --git a/src/nxt_http_parse.h b/src/nxt_http_parse.h
index 0326d45c..6c629936 100644
--- a/src/nxt_http_parse.h
+++ b/src/nxt_http_parse.h
@@ -93,6 +93,11 @@ struct nxt_http_field_s {
};
+#define NXT_HTTP_FIELD_HASH_INIT 159406U
+#define nxt_http_field_hash_char(h, c) (((h) << 4) + (h) + (c))
+#define nxt_http_field_hash_end(h) (((h) >> 16) ^ (h))
+
+
nxt_int_t nxt_http_parse_request_init(nxt_http_request_parse_t *rp,
nxt_mp_t *mp);
nxt_int_t nxt_http_parse_request(nxt_http_request_parse_t *rp,
diff --git a/src/nxt_http_request.c b/src/nxt_http_request.c
index 724b0808..1265c186 100644
--- a/src/nxt_http_request.c
+++ b/src/nxt_http_request.c
@@ -11,6 +11,8 @@
static nxt_int_t nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp);
static void nxt_http_request_start(nxt_task_t *task, void *obj, void *data);
static void nxt_http_request_pass(nxt_task_t *task, void *obj, void *data);
+static void nxt_http_request_proto_info(nxt_task_t *task,
+ nxt_http_request_t *r);
static void nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj,
void *data);
static void nxt_http_request_done(nxt_task_t *task, void *obj, void *data);
@@ -293,26 +295,23 @@ nxt_http_request_pass(nxt_task_t *task, void *obj, void *data)
pass = r->conf->socket_conf->pass;
- if (nxt_slow_path(pass == NULL)) {
- goto fail;
- }
+ if (nxt_fast_path(pass != NULL)) {
- for ( ;; ) {
- nxt_debug(task, "http request route: %V", &pass->name);
+ do {
+ nxt_debug(task, "http request route: %V", &pass->name);
- pass = pass->handler(task, r, pass);
- if (pass == NULL) {
- break;
- }
+ pass = pass->handler(task, r, pass);
- if (nxt_slow_path(r->pass_count++ == 255)) {
- goto fail;
- }
- }
+ if (pass == NULL) {
+ return;
+ }
- return;
+ if (pass == NXT_HTTP_PASS_ERROR) {
+ break;
+ }
-fail:
+ } while (r->pass_count++ < 255);
+ }
nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
}
@@ -322,117 +321,52 @@ nxt_http_pass_t *
nxt_http_request_application(nxt_task_t *task, nxt_http_request_t *r,
nxt_http_pass_t *pass)
{
- nxt_int_t ret;
- nxt_event_engine_t *engine;
- nxt_app_parse_ctx_t *ar;
+ nxt_event_engine_t *engine;
nxt_debug(task, "http request application");
- ar = nxt_mp_zget(r->mem_pool, sizeof(nxt_app_parse_ctx_t));
- if (nxt_slow_path(ar == NULL)) {
- nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
- return NULL;
- }
-
- ar->request = r;
- ar->mem_pool = r->mem_pool;
nxt_mp_retain(r->mem_pool);
- // STUB
engine = task->thread->engine;
- ar->timer.task = &engine->task;
- ar->timer.work_queue = &engine->fast_work_queue;
- ar->timer.log = engine->task.log;
- ar->timer.bias = NXT_TIMER_DEFAULT_BIAS;
-
- ar->r.remote.start = nxt_sockaddr_address(r->remote);
- ar->r.remote.length = r->remote->address_length;
+ r->timer.task = &engine->task;
+ r->timer.work_queue = &engine->fast_work_queue;
+ r->timer.log = engine->task.log;
+ r->timer.bias = NXT_TIMER_DEFAULT_BIAS;
/*
* TODO: need an application flag to get local address
* required by "SERVER_ADDR" in Pyhton and PHP. Not used in Go.
*/
- nxt_http_request_local_addr(task, r);
-
- if (nxt_fast_path(r->local != NULL)) {
- ar->r.local.start = nxt_sockaddr_address(r->local);
- ar->r.local.length = r->local->address_length;
- }
-
- ar->r.header.fields = r->fields;
- ar->r.header.done = 1;
- ar->r.header.version = r->version;
-
- if (r->method != NULL) {
- ar->r.header.method = *r->method;
- }
+ nxt_http_request_proto_info(task, r);
if (r->host.length != 0) {
- ar->r.header.server_name = r->host;
+ r->server_name = r->host;
} else {
- nxt_str_set(&ar->r.header.server_name, "localhost");
+ nxt_str_set(&r->server_name, "localhost");
}
- ar->r.header.target = r->target;
-
- if (r->path != NULL) {
- ar->r.header.path = *r->path;
- }
-
- if (r->args != NULL) {
- ar->r.header.query = *r->args;
- }
-
- if (r->content_type != NULL) {
- ar->r.header.content_type.length = r->content_type->value_length;
- ar->r.header.content_type.start = r->content_type->value;
- }
-
- if (r->content_length != NULL) {
- ar->r.header.content_length.length = r->content_length->value_length;
- ar->r.header.content_length.start = r->content_length->value;
- }
-
- if (r->cookie != NULL) {
- ar->r.header.cookie.length = r->cookie->value_length;
- ar->r.header.cookie.start = r->cookie->value;
- }
-
- if (r->body != NULL) {
- ar->r.body.buf = r->body;
- ar->r.body.preread_size = r->content_length_n;
- ar->r.header.parsed_content_length = r->content_length_n;
- }
-
- ar->r.body.done = 1;
-
- ret = nxt_http_parse_request_init(&ar->resp_parser, r->mem_pool);
- if (nxt_slow_path(ret != NXT_OK)) {
- nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
- return NULL;
- }
-
- nxt_router_process_http_request(task, ar, pass->u.application);
+ nxt_router_process_http_request(task, r, pass->u.application);
return NULL;
}
-void
-nxt_http_request_read_body(nxt_task_t *task, nxt_http_request_t *r)
+static void
+nxt_http_request_proto_info(nxt_task_t *task, nxt_http_request_t *r)
{
if (r->proto.any != NULL) {
- nxt_http_proto_body_read[r->protocol](task, r);
+ nxt_http_proto_local_addr[r->protocol](task, r);
+ nxt_http_proto_tls[r->protocol](task, r);
}
}
void
-nxt_http_request_local_addr(nxt_task_t *task, nxt_http_request_t *r)
+nxt_http_request_read_body(nxt_task_t *task, nxt_http_request_t *r)
{
if (r->proto.any != NULL) {
- nxt_http_proto_local_addr[r->protocol](task, r);
+ nxt_http_proto_body_read[r->protocol](task, r);
}
}
@@ -589,6 +523,8 @@ nxt_http_request_error_handler(nxt_task_t *task, void *obj, void *data)
nxt_debug(task, "http request error handler");
+ r->error = 1;
+
if (proto.any != NULL) {
nxt_http_proto_discard[r->protocol](task, r, nxt_http_buf_last(r));
}
diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c
index 133c39ab..d6749acb 100644
--- a/src/nxt_http_route.c
+++ b/src/nxt_http_route.c
@@ -9,9 +9,9 @@
typedef enum {
- NXT_HTTP_ROUTE_STRING = 0,
+ NXT_HTTP_ROUTE_TABLE = 0,
+ NXT_HTTP_ROUTE_STRING,
NXT_HTTP_ROUTE_STRING_PTR,
- NXT_HTTP_ROUTE_FIELD,
NXT_HTTP_ROUTE_HEADER,
NXT_HTTP_ROUTE_ARGUMENT,
NXT_HTTP_ROUTE_COOKIE,
@@ -21,6 +21,7 @@ typedef enum {
typedef enum {
NXT_HTTP_ROUTE_PATTERN_EXACT = 0,
NXT_HTTP_ROUTE_PATTERN_BEGIN,
+ NXT_HTTP_ROUTE_PATTERN_MIDDLE,
NXT_HTTP_ROUTE_PATTERN_END,
NXT_HTTP_ROUTE_PATTERN_SUBSTRING,
} nxt_http_route_pattern_type_t;
@@ -37,11 +38,17 @@ typedef struct {
nxt_conf_value_t *host;
nxt_conf_value_t *uri;
nxt_conf_value_t *method;
+ nxt_conf_value_t *headers;
+ nxt_conf_value_t *arguments;
+ nxt_conf_value_t *cookies;
} nxt_http_route_match_conf_t;
typedef struct {
- nxt_str_t test;
+ u_char *start1;
+ u_char *start2;
+ uint32_t length1;
+ uint32_t length2;
uint32_t min_length;
nxt_http_route_pattern_type_t type:8;
@@ -52,17 +59,66 @@ typedef struct {
typedef struct {
- uintptr_t offset;
- uint32_t items;
+ uint16_t hash;
+ uint16_t name_length;
+ uint32_t value_length;
+ u_char *name;
+ u_char *value;
+} nxt_http_name_value_t;
+
+
+typedef struct {
+ uint16_t hash;
+ uint16_t name_length;
+ uint32_t value_length;
+ u_char *name;
+ u_char *value;
+} nxt_http_cookie_t;
+
+
+typedef struct {
+ /* The object must be the first field. */
nxt_http_route_object_t object:8;
+ uint32_t items;
+
+ union {
+ uintptr_t offset;
+
+ struct {
+ u_char *start;
+ uint16_t hash;
+ uint16_t length;
+ } name;
+ } u;
+
nxt_http_route_pattern_t pattern[0];
} nxt_http_route_rule_t;
typedef struct {
uint32_t items;
- nxt_http_pass_t pass;
nxt_http_route_rule_t *rule[0];
+} nxt_http_route_ruleset_t;
+
+
+typedef struct {
+ /* The object must be the first field. */
+ nxt_http_route_object_t object:8;
+ uint32_t items;
+ nxt_http_route_ruleset_t *ruleset[0];
+} nxt_http_route_table_t;
+
+
+typedef union {
+ nxt_http_route_rule_t *rule;
+ nxt_http_route_table_t *table;
+} nxt_http_route_test_t;
+
+
+typedef struct {
+ uint32_t items;
+ nxt_http_pass_t pass;
+ nxt_http_route_test_t test[0];
} nxt_http_route_match_t;
@@ -79,17 +135,39 @@ struct nxt_http_routes_s {
};
+#define NJS_COOKIE_HASH \
+ (nxt_http_field_hash_end( \
+ nxt_http_field_hash_char( \
+ nxt_http_field_hash_char( \
+ nxt_http_field_hash_char( \
+ nxt_http_field_hash_char( \
+ nxt_http_field_hash_char( \
+ nxt_http_field_hash_char(NXT_HTTP_FIELD_HASH_INIT, \
+ 'c'), 'o'), 'o'), 'k'), 'i'), 'e')) & 0xFFFF)
+
+
static nxt_http_route_t *nxt_http_route_create(nxt_task_t *task,
nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv);
static nxt_http_route_match_t *nxt_http_route_match_create(nxt_task_t *task,
nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv);
+static nxt_http_route_table_t *nxt_http_route_table_create(nxt_task_t *task,
+ nxt_mp_t *mp, nxt_conf_value_t *table_cv, nxt_http_route_object_t object,
+ nxt_bool_t case_sensitive);
+static nxt_http_route_ruleset_t *nxt_http_route_ruleset_create(nxt_task_t *task,
+ nxt_mp_t *mp, nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object,
+ nxt_bool_t case_sensitive);
+static nxt_http_route_rule_t *nxt_http_route_rule_name_create(nxt_task_t *task,
+ nxt_mp_t *mp, nxt_conf_value_t *rule_cv, nxt_str_t *name,
+ nxt_bool_t case_sensitive);
static nxt_http_route_rule_t *nxt_http_route_rule_create(nxt_task_t *task,
- nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv,
- nxt_bool_t case_sensitive, nxt_http_route_pattern_case_t pattern_case);
+ nxt_mp_t *mp, nxt_conf_value_t *cv, nxt_bool_t case_sensitive,
+ nxt_http_route_pattern_case_t pattern_case);
static int nxt_http_pattern_compare(const void *one, const void *two);
static nxt_int_t nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern,
nxt_http_route_pattern_case_t pattern_case);
+static u_char *nxt_http_route_pattern_copy(nxt_mp_t *mp, nxt_str_t *test,
+ nxt_http_route_pattern_case_t pattern_case);
static void nxt_http_route_resolve(nxt_task_t *task,
nxt_router_temp_conf_t *tmcf, nxt_http_route_t *route);
@@ -103,10 +181,37 @@ static nxt_http_pass_t *nxt_http_route_pass(nxt_task_t *task,
nxt_http_request_t *r, nxt_http_pass_t *start);
static nxt_http_pass_t *nxt_http_route_match(nxt_http_request_t *r,
nxt_http_route_match_t *match);
-static nxt_bool_t nxt_http_route_rule(nxt_http_request_t *r,
+static nxt_int_t nxt_http_route_table(nxt_http_request_t *r,
+ nxt_http_route_table_t *table);
+static nxt_int_t nxt_http_route_ruleset(nxt_http_request_t *r,
+ nxt_http_route_ruleset_t *ruleset);
+static nxt_int_t nxt_http_route_rule(nxt_http_request_t *r,
+ nxt_http_route_rule_t *rule);
+static nxt_int_t nxt_http_route_header(nxt_http_request_t *r,
nxt_http_route_rule_t *rule);
-static nxt_bool_t nxt_http_route_pattern(nxt_http_request_t *r,
+static nxt_int_t nxt_http_route_arguments(nxt_http_request_t *r,
+ nxt_http_route_rule_t *rule);
+static nxt_array_t *nxt_http_route_arguments_parse(nxt_http_request_t *r);
+static nxt_http_name_value_t *nxt_http_route_argument(nxt_array_t *array,
+ u_char *name, size_t name_length, uint32_t hash, u_char *start,
+ u_char *end);
+static nxt_int_t nxt_http_route_test_argument(nxt_http_request_t *r,
+ nxt_http_route_rule_t *rule, nxt_array_t *array);
+static nxt_int_t nxt_http_route_cookies(nxt_http_request_t *r,
+ nxt_http_route_rule_t *rule);
+static nxt_array_t *nxt_http_route_cookies_parse(nxt_http_request_t *r);
+static nxt_int_t nxt_http_route_cookie_parse(nxt_array_t *cookies,
+ u_char *start, u_char *end);
+static nxt_http_name_value_t *nxt_http_route_cookie(nxt_array_t *array,
+ u_char *name, size_t name_length, u_char *start, u_char *end);
+static nxt_int_t nxt_http_route_test_cookie(nxt_http_request_t *r,
+ nxt_http_route_rule_t *rule, nxt_array_t *array);
+static nxt_int_t nxt_http_route_test_rule(nxt_http_request_t *r,
+ nxt_http_route_rule_t *rule, u_char *start, size_t length);
+static nxt_int_t nxt_http_route_pattern(nxt_http_request_t *r,
nxt_http_route_pattern_t *pattern, u_char *start, size_t length);
+static nxt_int_t nxt_http_route_memcmp(u_char *start, u_char *test,
+ size_t length, nxt_bool_t case_sensitive);
nxt_http_routes_t *
@@ -188,6 +293,24 @@ static nxt_conf_map_t nxt_http_route_match_conf[] = {
NXT_CONF_MAP_PTR,
offsetof(nxt_http_route_match_conf_t, method),
},
+
+ {
+ nxt_string("headers"),
+ NXT_CONF_MAP_PTR,
+ offsetof(nxt_http_route_match_conf_t, headers),
+ },
+
+ {
+ nxt_string("arguments"),
+ NXT_CONF_MAP_PTR,
+ offsetof(nxt_http_route_match_conf_t, arguments),
+ },
+
+ {
+ nxt_string("cookies"),
+ NXT_CONF_MAP_PTR,
+ offsetof(nxt_http_route_match_conf_t, cookies),
+ },
};
@@ -233,10 +356,13 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
{
size_t size;
uint32_t n;
+ nxt_mp_t *mp;
nxt_int_t ret;
nxt_str_t pass, *string;
nxt_conf_value_t *match_conf, *pass_conf;
- nxt_http_route_rule_t *rule, **p;
+ nxt_http_route_test_t *test;
+ nxt_http_route_rule_t *rule;
+ nxt_http_route_table_t *table;
nxt_http_route_match_t *match;
nxt_http_route_match_conf_t mtcf;
@@ -255,7 +381,9 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
n = (match_conf != NULL) ? nxt_conf_object_members_count(match_conf) : 0;
size = sizeof(nxt_http_route_match_t) + n * sizeof(nxt_http_route_rule_t *);
- match = nxt_mp_alloc(tmcf->router_conf->mem_pool, size);
+ mp = tmcf->router_conf->mem_pool;
+
+ match = nxt_mp_alloc(mp, size);
if (nxt_slow_path(match == NULL)) {
return NULL;
}
@@ -264,7 +392,7 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
match->pass.handler = NULL;
match->items = n;
- string = nxt_str_dup(tmcf->router_conf->mem_pool, &match->pass.name, &pass);
+ string = nxt_str_dup(mp, &match->pass.name, &pass);
if (nxt_slow_path(string == NULL)) {
return NULL;
}
@@ -282,64 +410,232 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
return NULL;
}
- p = &match->rule[0];
+ test = &match->test[0];
if (mtcf.host != NULL) {
- rule = nxt_http_route_rule_create(task, tmcf, mtcf.host, 1,
+ rule = nxt_http_route_rule_create(task, mp, mtcf.host, 1,
NXT_HTTP_ROUTE_PATTERN_LOWCASE);
if (rule == NULL) {
return NULL;
}
- rule->offset = offsetof(nxt_http_request_t, host);
+ rule->u.offset = offsetof(nxt_http_request_t, host);
rule->object = NXT_HTTP_ROUTE_STRING;
- *p++ = rule;
+ test->rule = rule;
+ test++;
}
if (mtcf.uri != NULL) {
- rule = nxt_http_route_rule_create(task, tmcf, mtcf.uri, 1,
+ rule = nxt_http_route_rule_create(task, mp, mtcf.uri, 1,
NXT_HTTP_ROUTE_PATTERN_NOCASE);
if (rule == NULL) {
return NULL;
}
- rule->offset = offsetof(nxt_http_request_t, path);
+ rule->u.offset = offsetof(nxt_http_request_t, path);
rule->object = NXT_HTTP_ROUTE_STRING_PTR;
- *p++ = rule;
+ test->rule = rule;
+ test++;
}
if (mtcf.method != NULL) {
- rule = nxt_http_route_rule_create(task, tmcf, mtcf.method, 1,
+ rule = nxt_http_route_rule_create(task, mp, mtcf.method, 1,
NXT_HTTP_ROUTE_PATTERN_UPCASE);
if (rule == NULL) {
return NULL;
}
- rule->offset = offsetof(nxt_http_request_t, method);
+ rule->u.offset = offsetof(nxt_http_request_t, method);
rule->object = NXT_HTTP_ROUTE_STRING_PTR;
- *p++ = rule;
+ test->rule = rule;
+ test++;
+ }
+
+ if (mtcf.headers != NULL) {
+ table = nxt_http_route_table_create(task, mp, mtcf.headers,
+ NXT_HTTP_ROUTE_HEADER, 0);
+ if (table == NULL) {
+ return NULL;
+ }
+
+ test->table = table;
+ test++;
+ }
+
+ if (mtcf.arguments != NULL) {
+ table = nxt_http_route_table_create(task, mp, mtcf.arguments,
+ NXT_HTTP_ROUTE_ARGUMENT, 1);
+ if (table == NULL) {
+ return NULL;
+ }
+
+ test->table = table;
+ test++;
+ }
+
+ if (mtcf.cookies != NULL) {
+ table = nxt_http_route_table_create(task, mp, mtcf.cookies,
+ NXT_HTTP_ROUTE_COOKIE, 0);
+ if (table == NULL) {
+ return NULL;
+ }
+
+ test->table = table;
+ test++;
}
return match;
}
+static nxt_http_route_table_t *
+nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp,
+ nxt_conf_value_t *table_cv, nxt_http_route_object_t object,
+ nxt_bool_t case_sensitive)
+{
+ size_t size;
+ uint32_t i, n;
+ nxt_bool_t array;
+ nxt_conf_value_t *ruleset_cv;
+ nxt_http_route_table_t *table;
+ nxt_http_route_ruleset_t *ruleset;
+
+ array = (nxt_conf_type(table_cv) == NXT_CONF_ARRAY);
+ n = array ? nxt_conf_array_elements_count(table_cv) : 1;
+ size = sizeof(nxt_http_route_table_t)
+ + n * sizeof(nxt_http_route_ruleset_t *);
+
+ table = nxt_mp_alloc(mp, size);
+ if (nxt_slow_path(table == NULL)) {
+ return NULL;
+ }
+
+ table->items = n;
+ table->object = NXT_HTTP_ROUTE_TABLE;
+
+ if (!array) {
+ ruleset = nxt_http_route_ruleset_create(task, mp, table_cv,
+ object, case_sensitive);
+ if (nxt_slow_path(ruleset == NULL)) {
+ return NULL;
+ }
+
+ table->ruleset[0] = ruleset;
+
+ return table;
+ }
+
+ for (i = 0; i < n; i++) {
+ ruleset_cv = nxt_conf_get_array_element(table_cv, i);
+
+ ruleset = nxt_http_route_ruleset_create(task, mp, ruleset_cv,
+ object, case_sensitive);
+ if (nxt_slow_path(ruleset == NULL)) {
+ return NULL;
+ }
+
+ table->ruleset[i] = ruleset;
+ }
+
+ return table;
+}
+
+
+static nxt_http_route_ruleset_t *
+nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp,
+ nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object,
+ nxt_bool_t case_sensitive)
+{
+ size_t size;
+ uint32_t i, n, next;
+ nxt_str_t name;
+ nxt_conf_value_t *rule_cv;
+ nxt_http_route_rule_t *rule;
+ nxt_http_route_ruleset_t *ruleset;
+
+ n = nxt_conf_object_members_count(ruleset_cv);
+ size = sizeof(nxt_http_route_ruleset_t)
+ + n * sizeof(nxt_http_route_rule_t *);
+
+ ruleset = nxt_mp_alloc(mp, size);
+ if (nxt_slow_path(ruleset == NULL)) {
+ return NULL;
+ }
+
+ ruleset->items = n;
+
+ next = 0;
+
+ for (i = 0; i < n; i++) {
+ rule_cv = nxt_conf_next_object_member(ruleset_cv, &name, &next);
+
+ rule = nxt_http_route_rule_name_create(task, mp, rule_cv, &name,
+ case_sensitive);
+ if (nxt_slow_path(rule == NULL)) {
+ return NULL;
+ }
+
+ rule->object = object;
+ ruleset->rule[i] = rule;
+ }
+
+ return ruleset;
+}
+
+
static nxt_http_route_rule_t *
-nxt_http_route_rule_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
+nxt_http_route_rule_name_create(nxt_task_t *task, nxt_mp_t *mp,
+ nxt_conf_value_t *rule_cv, nxt_str_t *name, nxt_bool_t case_sensitive)
+{
+ u_char c, *p;
+ uint32_t hash;
+ nxt_uint_t i;
+ nxt_http_route_rule_t *rule;
+
+ rule = nxt_http_route_rule_create(task, mp, rule_cv, case_sensitive,
+ NXT_HTTP_ROUTE_PATTERN_NOCASE);
+ if (nxt_slow_path(rule == NULL)) {
+ return NULL;
+ }
+
+ rule->u.name.length = name->length;
+
+ p = nxt_mp_nget(mp, name->length);
+ if (nxt_slow_path(p == NULL)) {
+ return NULL;
+ }
+
+ rule->u.name.start = p;
+
+ hash = NXT_HTTP_FIELD_HASH_INIT;
+
+ for (i = 0; i < name->length; i++) {
+ c = name->start[i];
+ *p++ = c;
+
+ c = nxt_lowcase(c);
+ hash = nxt_http_field_hash_char(hash, c);
+ }
+
+ rule->u.name.hash = nxt_http_field_hash_end(hash) & 0xFFFF;
+
+ return rule;
+}
+
+
+static nxt_http_route_rule_t *
+nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp,
nxt_conf_value_t *cv, nxt_bool_t case_sensitive,
nxt_http_route_pattern_case_t pattern_case)
{
size_t size;
uint32_t i, n;
- nxt_mp_t *mp;
nxt_int_t ret;
nxt_bool_t string;
nxt_conf_value_t *value;
nxt_http_route_rule_t *rule;
nxt_http_route_pattern_t *pattern;
- mp = tmcf->router_conf->mem_pool;
-
string = (nxt_conf_type(cv) != NXT_CONF_ARRAY);
n = string ? 1 : nxt_conf_array_elements_count(cv);
size = sizeof(nxt_http_route_rule_t) + n * sizeof(nxt_http_route_pattern_t);
@@ -407,8 +703,12 @@ nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
{
u_char *start;
nxt_str_t test;
+ nxt_uint_t n, length;
nxt_http_route_pattern_type_t type;
+ /* Suppress warning about uninitialized variable. */
+ length = 0;
+
type = NXT_HTTP_ROUTE_PATTERN_EXACT;
nxt_conf_get_string(cv, &test);
@@ -448,57 +748,98 @@ nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp,
} else if (test.start[test.length - 1] == '*') {
test.length--;
type = NXT_HTTP_ROUTE_PATTERN_BEGIN;
+
+ } else {
+ length = test.length - 1;
+
+ for (n = 1; n < length; n++) {
+ if (test.start[n] == '*') {
+ test.length = n;
+ type = NXT_HTTP_ROUTE_PATTERN_MIDDLE;
+ break;
+ }
+ }
}
}
}
pattern->type = type;
pattern->min_length = test.length;
- pattern->test.length = test.length;
+ pattern->length1 = test.length;
- start = nxt_mp_nget(mp, test.length);
+ start = nxt_http_route_pattern_copy(mp, &test, pattern_case);
if (nxt_slow_path(start == NULL)) {
return NXT_ERROR;
}
- pattern->test.start = start;
+ pattern->start1 = start;
+
+ if (type == NXT_HTTP_ROUTE_PATTERN_MIDDLE) {
+ length -= test.length;
+ pattern->length2 = length;
+ pattern->min_length += length;
+
+ test.start = &test.start[test.length + 1];
+ test.length = length;
+
+ start = nxt_http_route_pattern_copy(mp, &test, pattern_case);
+ if (nxt_slow_path(start == NULL)) {
+ return NXT_ERROR;
+ }
+
+ pattern->start2 = start;
+ }
+
+ return NXT_OK;
+}
+
+
+static u_char *
+nxt_http_route_pattern_copy(nxt_mp_t *mp, nxt_str_t *test,
+ nxt_http_route_pattern_case_t pattern_case)
+{
+ u_char *start;
+
+ start = nxt_mp_nget(mp, test->length);
+ if (nxt_slow_path(start == NULL)) {
+ return start;
+ }
switch (pattern_case) {
case NXT_HTTP_ROUTE_PATTERN_UPCASE:
- nxt_memcpy_upcase(start, test.start, test.length);
+ nxt_memcpy_upcase(start, test->start, test->length);
break;
case NXT_HTTP_ROUTE_PATTERN_LOWCASE:
- nxt_memcpy_lowcase(start, test.start, test.length);
+ nxt_memcpy_lowcase(start, test->start, test->length);
break;
case NXT_HTTP_ROUTE_PATTERN_NOCASE:
- nxt_memcpy(start, test.start, test.length);
+ nxt_memcpy(start, test->start, test->length);
break;
}
- return NXT_OK;
+ return start;
}
void
nxt_http_routes_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
{
- nxt_uint_t items;
- nxt_http_route_t **route;
+ nxt_http_route_t **route, **end;
nxt_http_routes_t *routes;
routes = tmcf->router_conf->routes;
+
if (routes != NULL) {
- items = routes->items;
route = &routes->route[0];
+ end = route + routes->items;
- while (items != 0) {
+ while (route < end) {
nxt_http_route_resolve(task, tmcf, *route);
route++;
- items--;
}
}
}
@@ -508,17 +849,15 @@ static void
nxt_http_route_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
nxt_http_route_t *route)
{
- nxt_uint_t items;
- nxt_http_route_match_t **match;
+ nxt_http_route_match_t **match, **end;
- items = route->items;
match = &route->match[0];
+ end = match + route->items;
- while (items != 0) {
+ while (match < end) {
nxt_http_pass_resolve(task, tmcf, &(*match)->pass);
match++;
- items--;
}
}
@@ -561,21 +900,18 @@ nxt_http_pass_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
static nxt_http_route_t *
nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name)
{
- nxt_uint_t items;
- nxt_http_route_t **route;
+ nxt_http_route_t **route, **end;
- items = routes->items;
route = &routes->route[0];
+ end = route + routes->items;
- do {
+ while (route < end) {
if (nxt_strstr_eq(&(*route)->name, name)) {
return *route;
}
route++;
- items--;
-
- } while (items != 0);
+ }
return NULL;
}
@@ -627,20 +963,17 @@ nxt_http_pass_application(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
void
nxt_http_routes_cleanup(nxt_task_t *task, nxt_http_routes_t *routes)
{
- nxt_uint_t items;
- nxt_http_route_t **route;
+ nxt_http_route_t **route, **end;
if (routes != NULL) {
- items = routes->items;
route = &routes->route[0];
+ end = route + routes->items;
- do {
+ while (route < end) {
nxt_http_route_cleanup(task, *route);
route++;
- items--;
-
- } while (items != 0);
+ }
}
}
@@ -648,19 +981,16 @@ nxt_http_routes_cleanup(nxt_task_t *task, nxt_http_routes_t *routes)
static void
nxt_http_route_cleanup(nxt_task_t *task, nxt_http_route_t *route)
{
- nxt_uint_t items;
- nxt_http_route_match_t **match;
+ nxt_http_route_match_t **match, **end;
- items = route->items;
match = &route->match[0];
+ end = match + route->items;
- do {
+ while (match < end) {
nxt_http_pass_cleanup(task, &(*match)->pass);
match++;
- items--;
-
- } while (items != 0);
+ }
}
@@ -677,23 +1007,21 @@ static nxt_http_pass_t *
nxt_http_route_pass(nxt_task_t *task, nxt_http_request_t *r,
nxt_http_pass_t *start)
{
- nxt_uint_t items;
nxt_http_pass_t *pass;
nxt_http_route_t *route;
- nxt_http_route_match_t **match;
+ nxt_http_route_match_t **match, **end;
route = start->u.route;
- items = route->items;
match = &route->match[0];
+ end = match + route->items;
- while (items != 0) {
+ while (match < end) {
pass = nxt_http_route_match(r, *match);
if (pass != NULL) {
return pass;
}
match++;
- items--;
}
nxt_http_request_error(task, r, NXT_HTTP_NOT_FOUND);
@@ -705,87 +1033,488 @@ nxt_http_route_pass(nxt_task_t *task, nxt_http_request_t *r,
static nxt_http_pass_t *
nxt_http_route_match(nxt_http_request_t *r, nxt_http_route_match_t *match)
{
- nxt_uint_t items;
- nxt_http_route_rule_t **rule;
+ nxt_int_t ret;
+ nxt_http_route_test_t *test, *end;
- rule = &match->rule[0];
- items = match->items;
+ test = &match->test[0];
+ end = test + match->items;
- while (items != 0) {
- if (!nxt_http_route_rule(r, *rule)) {
- return NULL;
+ while (test < end) {
+ if (test->rule->object != NXT_HTTP_ROUTE_TABLE) {
+ ret = nxt_http_route_rule(r, test->rule);
+
+ } else {
+ ret = nxt_http_route_table(r, test->table);
}
- rule++;
- items--;
+ if (ret <= 0) {
+ /* 0 => NULL, -1 => NXT_HTTP_PASS_ERROR. */
+ return (nxt_http_pass_t *) (intptr_t) ret;
+ }
+
+ test++;
}
return &match->pass;
}
-static nxt_bool_t
+static nxt_int_t
+nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table)
+{
+ nxt_int_t ret;
+ nxt_http_route_ruleset_t **ruleset, **end;
+
+ ret = 1;
+ ruleset = &table->ruleset[0];
+ end = ruleset + table->items;
+
+ while (ruleset < end) {
+ ret = nxt_http_route_ruleset(r, *ruleset);
+
+ if (ret != 0) {
+ return ret;
+ }
+
+ ruleset++;
+ }
+
+ return ret;
+}
+
+
+static nxt_int_t
+nxt_http_route_ruleset(nxt_http_request_t *r, nxt_http_route_ruleset_t *ruleset)
+{
+ nxt_int_t ret;
+ nxt_http_route_rule_t **rule, **end;
+
+ rule = &ruleset->rule[0];
+ end = rule + ruleset->items;
+
+ while (rule < end) {
+ ret = nxt_http_route_rule(r, *rule);
+
+ if (ret <= 0) {
+ return ret;
+ }
+
+ rule++;
+ }
+
+ return 1;
+}
+
+
+static nxt_int_t
nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
{
- void *p, **pp;
- u_char *start;
- size_t length;
- nxt_str_t *s;
- nxt_uint_t items;
- nxt_bool_t ret;
- nxt_http_field_t *f;
- nxt_http_route_pattern_t *pattern;
+ void *p, **pp;
+ u_char *start;
+ size_t length;
+ nxt_str_t *s;
+
+ switch (rule->object) {
+
+ case NXT_HTTP_ROUTE_HEADER:
+ return nxt_http_route_header(r, rule);
- p = nxt_pointer_to(r, rule->offset);
+ case NXT_HTTP_ROUTE_ARGUMENT:
+ return nxt_http_route_arguments(r, rule);
+
+ case NXT_HTTP_ROUTE_COOKIE:
+ return nxt_http_route_cookies(r, rule);
+
+ default:
+ break;
+ }
+
+ p = nxt_pointer_to(r, rule->u.offset);
if (rule->object == NXT_HTTP_ROUTE_STRING) {
s = p;
- length = s->length;
- start = s->start;
} else {
+ /* NXT_HTTP_ROUTE_STRING_PTR */
pp = p;
- p = *pp;
+ s = *pp;
- if (p == NULL) {
+ if (s == NULL) {
return 0;
}
+ }
- switch (rule->object) {
+ length = s->length;
+ start = s->start;
- case NXT_HTTP_ROUTE_STRING_PTR:
- s = p;
- length = s->length;
- start = s->start;
- break;
+ return nxt_http_route_test_rule(r, rule, start, length);
+}
- case NXT_HTTP_ROUTE_FIELD:
- f = p;
- length = f->value_length;
- start = f->value;
- break;
- case NXT_HTTP_ROUTE_HEADER:
- return 0;
+static nxt_int_t
+nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
+{
+ nxt_int_t ret;
+ nxt_http_field_t *f;
- case NXT_HTTP_ROUTE_ARGUMENT:
- return 0;
+ ret = 0;
- case NXT_HTTP_ROUTE_COOKIE:
- return 0;
+ nxt_list_each(f, r->fields) {
- default:
- nxt_unreachable();
- return 0;
+ if (rule->u.name.hash != f->hash
+ || rule->u.name.length != f->name_length
+ || nxt_strncasecmp(rule->u.name.start, f->name, f->name_length)
+ != 0)
+ {
+ continue;
+ }
+
+ ret = nxt_http_route_test_rule(r, rule, f->value, f->value_length);
+
+ if (ret == 0) {
+ return ret;
+ }
+
+ } nxt_list_loop;
+
+ return ret;
+}
+
+
+static nxt_int_t
+nxt_http_route_arguments(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
+{
+ nxt_array_t *arguments;
+
+ if (r->args == NULL) {
+ return 0;
+ }
+
+ arguments = nxt_http_route_arguments_parse(r);
+ if (nxt_slow_path(arguments == NULL)) {
+ return -1;
+ }
+
+ return nxt_http_route_test_argument(r, rule, arguments);
+}
+
+
+static nxt_array_t *
+nxt_http_route_arguments_parse(nxt_http_request_t *r)
+{
+ size_t name_length;
+ u_char c, *p, *start, *end, *name;
+ uint32_t hash;
+ nxt_bool_t valid;
+ nxt_array_t *args;
+ nxt_http_name_value_t *nv;
+
+ if (r->arguments != NULL) {
+ return r->arguments;
+ }
+
+ args = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t));
+ if (nxt_slow_path(args == NULL)) {
+ return NULL;
+ }
+
+ hash = NXT_HTTP_FIELD_HASH_INIT;
+ valid = 1;
+ name = NULL;
+ name_length = 0;
+
+ start = r->args->start;
+ end = start + r->args->length;
+
+ for (p = start; p < end; p++) {
+ c = *p;
+
+ if (c == '=') {
+ name_length = p - start;
+ name = start;
+ start = p + 1;
+ valid = (name_length != 0);
+
+ } else if (c == '&') {
+ if (valid) {
+ nv = nxt_http_route_argument(args, name, name_length, hash,
+ start, p);
+ if (nxt_slow_path(nv == NULL)) {
+ return NULL;
+ }
+ }
+
+ hash = NXT_HTTP_FIELD_HASH_INIT;
+ valid = 1;
+ name = NULL;
+ start = p + 1;
+
+ } else if (name == NULL) {
+ hash = nxt_http_field_hash_char(hash, c);
+ }
+ }
+
+ if (valid) {
+ nv = nxt_http_route_argument(args, name, name_length, hash, start, p);
+ if (nxt_slow_path(nv == NULL)) {
+ return NULL;
+ }
+ }
+
+ r->arguments = args;
+
+ return args;
+}
+
+
+static nxt_http_name_value_t *
+nxt_http_route_argument(nxt_array_t *array, u_char *name, size_t name_length,
+ uint32_t hash, u_char *start, u_char *end)
+{
+ size_t length;
+ nxt_http_name_value_t *nv;
+
+ nv = nxt_array_add(array);
+ if (nxt_slow_path(nv == NULL)) {
+ return NULL;
+ }
+
+ nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF;
+
+ length = end - start;
+
+ if (name == NULL) {
+ name_length = length;
+ name = start;
+ length = 0;
+ }
+
+ nv->name_length = name_length;
+ nv->value_length = length;
+ nv->name = name;
+ nv->value = start;
+
+ return nv;
+}
+
+
+static nxt_int_t
+nxt_http_route_test_argument(nxt_http_request_t *r,
+ nxt_http_route_rule_t *rule, nxt_array_t *array)
+{
+ nxt_bool_t ret;
+ nxt_http_name_value_t *nv, *end;
+
+ ret = 0;
+
+ nv = array->elts;
+ end = nv + array->nelts;
+
+ while (nv < end) {
+
+ if (rule->u.name.hash == nv->hash
+ && rule->u.name.length == nv->name_length
+ && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0)
+ {
+ ret = nxt_http_route_test_rule(r, rule, nv->value,
+ nv->value_length);
+ if (ret == 0) {
+ break;
+ }
+ }
+
+ nv++;
+ }
+
+ return ret;
+}
+
+
+static nxt_int_t
+nxt_http_route_cookies(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
+{
+ nxt_array_t *cookies;
+
+ cookies = nxt_http_route_cookies_parse(r);
+ if (nxt_slow_path(cookies == NULL)) {
+ return -1;
+ }
+
+ return nxt_http_route_test_cookie(r, rule, cookies);
+}
+
+
+static nxt_array_t *
+nxt_http_route_cookies_parse(nxt_http_request_t *r)
+{
+ nxt_int_t ret;
+ nxt_array_t *cookies;
+ nxt_http_field_t *f;
+
+ if (r->cookies != NULL) {
+ return r->cookies;
+ }
+
+ cookies = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t));
+ if (nxt_slow_path(cookies == NULL)) {
+ return NULL;
+ }
+
+ nxt_list_each(f, r->fields) {
+
+ if (f->hash != NJS_COOKIE_HASH
+ || f->name_length != 6
+ || nxt_strncasecmp(f->name, (u_char *) "Cookie", 6) != 0)
+ {
+ continue;
+ }
+
+ ret = nxt_http_route_cookie_parse(cookies, f->value,
+ f->value + f->value_length);
+ if (ret != NXT_OK) {
+ return NULL;
+ }
+
+ } nxt_list_loop;
+
+ r->cookies = cookies;
+
+ return cookies;
+}
+
+
+static nxt_int_t
+nxt_http_route_cookie_parse(nxt_array_t *cookies, u_char *start, u_char *end)
+{
+ size_t name_length;
+ u_char c, *p, *name;
+ nxt_http_name_value_t *nv;
+
+ name = NULL;
+ name_length = 0;
+
+ for (p = start; p < end; p++) {
+ c = *p;
+
+ if (c == '=') {
+ while (start[0] == ' ') { start++; }
+
+ name_length = p - start;
+
+ if (name_length != 0) {
+ name = start;
+ }
+
+ start = p + 1;
+
+ } else if (c == ';') {
+ if (name != NULL) {
+ nv = nxt_http_route_cookie(cookies, name, name_length,
+ start, p);
+ if (nxt_slow_path(nv == NULL)) {
+ return NXT_ERROR;
+ }
+ }
+
+ name = NULL;
+ start = p + 1;
+ }
+ }
+
+ if (name != NULL) {
+ nv = nxt_http_route_cookie(cookies, name, name_length, start, p);
+ if (nxt_slow_path(nv == NULL)) {
+ return NXT_ERROR;
+ }
+ }
+
+ return NXT_OK;
+}
+
+
+static nxt_http_name_value_t *
+nxt_http_route_cookie(nxt_array_t *array, u_char *name, size_t name_length,
+ u_char *start, u_char *end)
+{
+ u_char c, *p;
+ uint32_t hash;
+ nxt_http_name_value_t *nv;
+
+ nv = nxt_array_add(array);
+ if (nxt_slow_path(nv == NULL)) {
+ return NULL;
+ }
+
+ nv->name_length = name_length;
+ nv->name = name;
+
+ hash = NXT_HTTP_FIELD_HASH_INIT;
+
+ for (p = name; p < name + name_length; p++) {
+ c = *p;
+ c = nxt_lowcase(c);
+ hash = nxt_http_field_hash_char(hash, c);
+ }
+
+ nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF;
+
+ while (start < end && end[-1] == ' ') { end--; }
+
+ nv->value_length = end - start;
+ nv->value = start;
+
+ return nv;
+}
+
+
+static nxt_int_t
+nxt_http_route_test_cookie(nxt_http_request_t *r,
+ nxt_http_route_rule_t *rule, nxt_array_t *array)
+{
+ nxt_bool_t ret;
+ nxt_http_name_value_t *nv, *end;
+
+ ret = 0;
+
+ nv = array->elts;
+ end = nv + array->nelts;
+
+ while (nv < end) {
+
+ if (rule->u.name.hash == nv->hash
+ && rule->u.name.length == nv->name_length
+ && nxt_strncasecmp(rule->u.name.start, nv->name, nv->name_length)
+ == 0)
+ {
+ ret = nxt_http_route_test_rule(r, rule, nv->value,
+ nv->value_length);
+ if (ret == 0) {
+ break;
+ }
}
+
+ nv++;
}
- items = rule->items;
+ return ret;
+}
+
+
+static nxt_int_t
+nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule,
+ u_char *start, size_t length)
+{
+ nxt_int_t ret;
+ nxt_http_route_pattern_t *pattern, *end;
+
+ ret = 1;
pattern = &rule->pattern[0];
+ end = pattern + rule->items;
- do {
+ while (pattern < end) {
ret = nxt_http_route_pattern(r, pattern, start, length);
+ /* nxt_http_route_pattern() returns either 1 or 0. */
ret ^= pattern->negative;
if (pattern->any == ret) {
@@ -793,30 +1522,31 @@ nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
}
pattern++;
- items--;
-
- } while (items != 0);
+ }
return ret;
}
-static nxt_bool_t
+static nxt_int_t
nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern,
u_char *start, size_t length)
{
- nxt_str_t *test;
+ u_char *p, *end, *test;
+ size_t test_length;
+ nxt_int_t ret;
if (length < pattern->min_length) {
return 0;
}
- test = &pattern->test;
+ test = pattern->start1;
+ test_length = pattern->length1;
switch (pattern->type) {
case NXT_HTTP_ROUTE_PATTERN_EXACT:
- if (length != test->length) {
+ if (length != test_length) {
return 0;
}
@@ -825,25 +1555,52 @@ nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern,
case NXT_HTTP_ROUTE_PATTERN_BEGIN:
break;
+ case NXT_HTTP_ROUTE_PATTERN_MIDDLE:
+ ret = nxt_http_route_memcmp(start, test, test_length,
+ pattern->case_sensitive);
+ if (!ret) {
+ return ret;
+ }
+
+ test = pattern->start2;
+ test_length = pattern->length2;
+
+ /* Fall through. */
+
case NXT_HTTP_ROUTE_PATTERN_END:
- start += length - test->length;
+ start += length - test_length;
break;
case NXT_HTTP_ROUTE_PATTERN_SUBSTRING:
+ end = start + length;
+
if (pattern->case_sensitive) {
- return (nxt_memstrn(start, start + length,
- (char *) test->start, test->length)
- != NULL);
+ p = nxt_memstrn(start, end, (char *) test, test_length);
+
+ } else {
+ p = nxt_memcasestrn(start, end, (char *) test, test_length);
}
- return (nxt_memcasestrn(start, start + length,
- (char *) test->start, test->length)
- != NULL);
+ return (p != NULL);
}
- if (pattern->case_sensitive) {
- return (nxt_memcmp(start, test->start, test->length) == 0);
+ return nxt_http_route_memcmp(start, test, test_length,
+ pattern->case_sensitive);
+}
+
+
+static nxt_int_t
+nxt_http_route_memcmp(u_char *start, u_char *test, size_t test_length,
+ nxt_bool_t case_sensitive)
+{
+ nxt_int_t n;
+
+ if (case_sensitive) {
+ n = nxt_memcmp(start, test, test_length);
+
+ } else {
+ n = nxt_memcasecmp(start, test, test_length);
}
- return (nxt_memcasecmp(start, test->start, test->length) == 0);
+ return (n == 0);
}
diff --git a/src/nxt_job_resolve.c b/src/nxt_job_resolve.c
index a1317756..0f1fb9aa 100644
--- a/src/nxt_job_resolve.c
+++ b/src/nxt_job_resolve.c
@@ -59,11 +59,11 @@ nxt_job_resolve(nxt_job_resolve_t *jbr)
case AF_INET6:
#endif
case AF_INET:
- n++;
- break;
+ n++;
+ break;
default:
- break;
+ break;
}
}
@@ -81,15 +81,15 @@ nxt_job_resolve(nxt_job_resolve_t *jbr)
switch (r->ai_addr->sa_family) {
#if (NXT_INET6)
case AF_INET6:
- length = NXT_INET6_ADDR_STR_LEN;
- break;
+ length = NXT_INET6_ADDR_STR_LEN;
+ break;
#endif
case AF_INET:
- length = NXT_INET_ADDR_STR_LEN;
- break;
+ length = NXT_INET_ADDR_STR_LEN;
+ break;
default:
- continue;
+ continue;
}
sa = nxt_sockaddr_create(mp, r->ai_addr, r->ai_addrlen, length);
diff --git a/src/nxt_kqueue_engine.c b/src/nxt_kqueue_engine.c
index 0e68fbdc..0212b331 100644
--- a/src/nxt_kqueue_engine.c
+++ b/src/nxt_kqueue_engine.c
@@ -856,7 +856,7 @@ nxt_kqueue_conn_io_connect(nxt_task_t *task, void *obj, void *data)
state = c->write_state;
- switch (nxt_socket_connect(task, c->socket.fd, c->remote) ){
+ switch (nxt_socket_connect(task, c->socket.fd, c->remote)) {
case NXT_OK:
c->socket.write_ready = 1;
diff --git a/src/nxt_main_process.c b/src/nxt_main_process.c
index f756bff7..40682eb9 100644
--- a/src/nxt_main_process.c
+++ b/src/nxt_main_process.c
@@ -842,7 +842,7 @@ nxt_main_process_sigusr1_handler(nxt_task_t *task, void *obj, void *data)
nxt_mp_destroy(mp);
return;
- }
+ }
fail:
diff --git a/src/nxt_php_sapi.c b/src/nxt_php_sapi.c
index 80321a85..a6ec6c60 100644
--- a/src/nxt_php_sapi.c
+++ b/src/nxt_php_sapi.c
@@ -699,7 +699,7 @@ fail:
static int
nxt_php_startup(sapi_module_struct *sapi_module)
{
- return php_module_startup(sapi_module, NULL, 0);
+ return php_module_startup(sapi_module, NULL, 0);
}
@@ -929,6 +929,10 @@ nxt_php_register_variables(zval *track_vars_array TSRMLS_DC)
track_vars_array TSRMLS_CC);
nxt_php_set_cstr(req, "SERVER_PORT", "80", 2, track_vars_array TSRMLS_CC);
+ if (r->tls) {
+ nxt_php_set_cstr(req, "HTTPS", "on", 2, track_vars_array TSRMLS_CC);
+ }
+
f_end = r->fields + r->fields_count;
for (f = r->fields; f < f_end; f++) {
name = nxt_unit_sptr_get(&f->name);
diff --git a/src/nxt_poll_engine.c b/src/nxt_poll_engine.c
index acb44a22..f514e0a9 100644
--- a/src/nxt_poll_engine.c
+++ b/src/nxt_poll_engine.c
@@ -370,7 +370,7 @@ nxt_poll_commit_changes(nxt_event_engine_t *engine)
retval = NXT_ERROR;
- next:
+ next:
change++;
diff --git a/src/nxt_port.c b/src/nxt_port.c
index 30719ad3..aff46666 100644
--- a/src/nxt_port.c
+++ b/src/nxt_port.c
@@ -510,7 +510,7 @@ nxt_port_post(nxt_task_t *task, nxt_port_t *port,
pw = nxt_zalloc(sizeof(nxt_port_work_t));
if (nxt_slow_path(pw == NULL)) {
- return NXT_ERROR;
+ return NXT_ERROR;
}
nxt_atomic_fetch_add(&port->use_count, 1);
diff --git a/src/nxt_port_memory.c b/src/nxt_port_memory.c
index 774f1f33..b908041c 100644
--- a/src/nxt_port_memory.c
+++ b/src/nxt_port_memory.c
@@ -49,10 +49,10 @@ nxt_port_mmap_at(nxt_port_mmaps_t *port_mmaps, uint32_t i)
while (i + 1 > cap) {
if (cap < 16) {
- cap = cap * 2;
+ cap = cap * 2;
} else {
- cap = cap + cap / 2;
+ cap = cap + cap / 2;
}
}
diff --git a/src/nxt_port_socket.c b/src/nxt_port_socket.c
index 01fe2dab..c9b5105b 100644
--- a/src/nxt_port_socket.c
+++ b/src/nxt_port_socket.c
@@ -195,7 +195,24 @@ nxt_port_msg_create(nxt_task_t *task, nxt_port_send_msg_t *m)
static nxt_port_send_msg_t *
-nxt_port_msg_push(nxt_task_t *task, nxt_port_t *port, nxt_port_send_msg_t *msg)
+nxt_port_msg_insert_head(nxt_task_t *task, nxt_port_t *port,
+ nxt_port_send_msg_t *msg)
+{
+ if (msg->work.data == NULL) {
+ msg = nxt_port_msg_create(task, msg);
+ }
+
+ if (msg != NULL) {
+ nxt_queue_insert_head(&port->messages, &msg->link);
+ }
+
+ return msg;
+}
+
+
+static nxt_port_send_msg_t *
+nxt_port_msg_insert_tail(nxt_task_t *task, nxt_port_t *port,
+ nxt_port_send_msg_t *msg)
{
if (msg->work.data == NULL) {
msg = nxt_port_msg_create(task, msg);
@@ -260,7 +277,7 @@ nxt_port_socket_twrite(nxt_task_t *task, nxt_port_t *port, nxt_uint_t type,
} else {
nxt_thread_mutex_lock(&port->write_mutex);
- res = nxt_port_msg_push(task, port, &msg);
+ res = nxt_port_msg_insert_tail(task, port, &msg);
nxt_thread_mutex_unlock(&port->write_mutex);
@@ -349,6 +366,8 @@ nxt_port_write_handler(nxt_task_t *task, void *obj, void *data)
iov[0].iov_len += sizeof(msg->tracking_msg);
}
+ sb.limit -= iov[0].iov_len;
+
nxt_sendbuf_mem_coalesce(task, &sb);
plain_size = sb.size;
@@ -407,7 +426,7 @@ nxt_port_write_handler(nxt_task_t *task, void *obj, void *data)
}
data = NULL;
- if (nxt_port_msg_push(task, port, msg) != NULL) {
+ if (nxt_port_msg_insert_tail(task, port, msg) != NULL) {
use_delta++;
}
}
@@ -422,16 +441,17 @@ nxt_port_write_handler(nxt_task_t *task, void *obj, void *data)
data = NULL;
}
- } else if (nxt_slow_path(n == NXT_ERROR)) {
+ } else {
if (msg->link.next == NULL) {
- if (nxt_port_msg_push(task, port, msg) != NULL) {
+ if (nxt_port_msg_insert_head(task, port, msg) != NULL) {
use_delta++;
}
}
- goto fail;
- }
- /* n == NXT_AGAIN */
+ if (nxt_slow_path(n == NXT_ERROR)) {
+ goto fail;
+ }
+ }
} while (port->socket.write_ready);
@@ -546,6 +566,7 @@ void
nxt_port_read_close(nxt_port_t *port)
{
port->socket.read_ready = 0;
+ port->socket.read = NXT_EVENT_INACTIVE;
nxt_socket_close(port->socket.task, port->pair[0]);
port->pair[0] = -1;
}
@@ -618,15 +639,24 @@ nxt_port_read_handler(nxt_task_t *task, void *obj, void *data)
}
+typedef struct {
+ uint32_t stream;
+ uint32_t pid;
+} nxt_port_frag_key_t;
+
+
static nxt_int_t
nxt_port_lvlhsh_frag_test(nxt_lvlhsh_query_t *lhq, void *data)
{
nxt_port_recv_msg_t *fmsg;
+ nxt_port_frag_key_t *frag_key;
fmsg = data;
+ frag_key = (nxt_port_frag_key_t *) lhq->key.start;
- if (lhq->key.length == sizeof(uint32_t)
- && *(uint32_t *) lhq->key.start == fmsg->port_msg.stream)
+ if (lhq->key.length == sizeof(nxt_port_frag_key_t)
+ && frag_key->stream == fmsg->port_msg.stream
+ && frag_key->pid == (uint32_t) fmsg->port_msg.pid)
{
return NXT_OK;
}
@@ -664,6 +694,7 @@ nxt_port_frag_start(nxt_task_t *task, nxt_port_t *port,
nxt_int_t res;
nxt_lvlhsh_query_t lhq;
nxt_port_recv_msg_t *fmsg;
+ nxt_port_frag_key_t frag_key;
nxt_debug(task, "start frag stream #%uD", msg->port_msg.stream);
@@ -675,9 +706,12 @@ nxt_port_frag_start(nxt_task_t *task, nxt_port_t *port,
*fmsg = *msg;
- lhq.key_hash = nxt_murmur_hash2(&fmsg->port_msg.stream, sizeof(uint32_t));
- lhq.key.length = sizeof(uint32_t);
- lhq.key.start = (u_char *) &fmsg->port_msg.stream;
+ frag_key.stream = fmsg->port_msg.stream;
+ frag_key.pid = fmsg->port_msg.pid;
+
+ lhq.key_hash = nxt_murmur_hash2(&frag_key, sizeof(nxt_port_frag_key_t));
+ lhq.key.length = sizeof(nxt_port_frag_key_t);
+ lhq.key.start = (u_char *) &frag_key;
lhq.proto = &lvlhsh_frag_proto;
lhq.replace = 0;
lhq.value = fmsg;
@@ -710,17 +744,24 @@ nxt_port_frag_start(nxt_task_t *task, nxt_port_t *port,
static nxt_port_recv_msg_t *
-nxt_port_frag_find(nxt_task_t *task, nxt_port_t *port, uint32_t stream,
- nxt_bool_t last)
+nxt_port_frag_find(nxt_task_t *task, nxt_port_t *port, nxt_port_recv_msg_t *msg)
{
- nxt_int_t res;
- nxt_lvlhsh_query_t lhq;
+ nxt_int_t res;
+ nxt_bool_t last;
+ nxt_lvlhsh_query_t lhq;
+ nxt_port_frag_key_t frag_key;
+
+ last = msg->port_msg.mf == 0;
+
+ nxt_debug(task, "%s frag stream #%uD", last ? "last" : "next",
+ msg->port_msg.stream);
- nxt_debug(task, "%s frag stream #%uD", last ? "last" : "next", stream);
+ frag_key.stream = msg->port_msg.stream;
+ frag_key.pid = msg->port_msg.pid;
- lhq.key_hash = nxt_murmur_hash2(&stream, sizeof(uint32_t));
- lhq.key.length = sizeof(uint32_t);
- lhq.key.start = (u_char *) &stream;
+ lhq.key_hash = nxt_murmur_hash2(&frag_key, sizeof(nxt_port_frag_key_t));
+ lhq.key.length = sizeof(nxt_port_frag_key_t);
+ lhq.key.start = (u_char *) &frag_key;
lhq.proto = &lvlhsh_frag_proto;
lhq.pool = port->mem_pool;
@@ -733,7 +774,8 @@ nxt_port_frag_find(nxt_task_t *task, nxt_port_t *port, uint32_t stream,
return lhq.value;
default:
- nxt_log(task, NXT_LOG_INFO, "frag stream #%uD not found", stream);
+ nxt_log(task, NXT_LOG_INFO, "frag stream #%uD not found",
+ frag_key.stream);
return NULL;
}
@@ -773,8 +815,7 @@ nxt_port_read_msg_process(nxt_task_t *task, nxt_port_t *port,
if (nxt_slow_path(msg->port_msg.nf != 0)) {
- fmsg = nxt_port_frag_find(task, port, msg->port_msg.stream,
- msg->port_msg.mf == 0);
+ fmsg = nxt_port_frag_find(task, port, msg);
if (nxt_slow_path(fmsg == NULL)) {
goto fmsg_failed;
diff --git a/src/nxt_process.c b/src/nxt_process.c
index 59520297..c4aef21c 100644
--- a/src/nxt_process.c
+++ b/src/nxt_process.c
@@ -136,9 +136,11 @@ nxt_process_start(nxt_task_t *task, nxt_process_t *process)
nxt_random_init(&thread->random);
- if (init->user_cred != NULL && getuid() == 0) {
- /* Super-user. */
-
+ if (init->user_cred != NULL) {
+ /*
+ * Changing user credentials requires either root privileges
+ * or CAP_SETUID and CAP_SETGID capabilities on Linux.
+ */
ret = nxt_user_cred_set(task, init->user_cred);
if (ret != NXT_OK) {
goto fail;
@@ -434,11 +436,7 @@ nxt_user_cred_get(nxt_task_t *task, nxt_user_cred_t *uc, const char *group)
uc->base_gid = grp->gr_gid;
}
- if (getuid() == 0) {
- return nxt_user_groups_get(task, uc);
- }
-
- return NXT_OK;
+ return nxt_user_groups_get(task, uc);
}
@@ -505,14 +503,26 @@ nxt_user_groups_get(nxt_task_t *task, nxt_user_cred_t *uc)
if (nsaved == -1) {
nxt_alert(task, "getgroups(%d) failed %E", nsaved, nxt_errno);
- goto fail;
+ goto free;
}
nxt_debug(task, "getgroups(): %d", nsaved);
if (initgroups(uc->user, uc->base_gid) != 0) {
- nxt_alert(task, "initgroups(%s, %d) failed", uc->user, uc->base_gid);
- goto restore;
+ if (nxt_errno == NXT_EPERM) {
+ nxt_log(task, NXT_LOG_NOTICE,
+ "initgroups(%s, %d) failed %E, ignored",
+ uc->user, uc->base_gid, nxt_errno);
+
+ ret = NXT_OK;
+
+ goto free;
+
+ } else {
+ nxt_alert(task, "initgroups(%s, %d) failed %E",
+ uc->user, uc->base_gid, nxt_errno);
+ goto restore;
+ }
}
ngroups = getgroups(0, NULL);
@@ -567,7 +577,7 @@ restore:
ret = NXT_ERROR;
}
-fail:
+free:
nxt_free(saved);
@@ -582,8 +592,15 @@ nxt_user_cred_set(nxt_task_t *task, nxt_user_cred_t *uc)
uc->user, (uint64_t) uc->uid, (uint64_t) uc->base_gid);
if (setgid(uc->base_gid) != 0) {
- nxt_alert(task, "setgid(%d) failed %E", uc->base_gid, nxt_errno);
- return NXT_ERROR;
+ if (nxt_errno == NXT_EPERM) {
+ nxt_log(task, NXT_LOG_NOTICE, "setgid(%d) failed %E, ignored",
+ uc->base_gid, nxt_errno);
+ return NXT_OK;
+
+ } else {
+ nxt_alert(task, "setgid(%d) failed %E", uc->base_gid, nxt_errno);
+ return NXT_ERROR;
+ }
}
if (uc->gids != NULL) {
@@ -595,8 +612,8 @@ nxt_user_cred_set(nxt_task_t *task, nxt_user_cred_t *uc)
} else {
/* MacOSX fallback. */
if (initgroups(uc->user, uc->base_gid) != 0) {
- nxt_alert(task, "initgroups(%s, %d) failed",
- uc->user, uc->base_gid);
+ nxt_alert(task, "initgroups(%s, %d) failed %E",
+ uc->user, uc->base_gid, nxt_errno);
return NXT_ERROR;
}
}
diff --git a/src/nxt_python_wsgi.c b/src/nxt_python_wsgi.c
index 6478f38c..a6d5f217 100644
--- a/src/nxt_python_wsgi.c
+++ b/src/nxt_python_wsgi.c
@@ -619,26 +619,6 @@ nxt_python_create_environ(nxt_task_t *task)
}
- obj = PyString_FromStringAndSize("http", nxt_length("http"));
-
- if (nxt_slow_path(obj == NULL)) {
- nxt_alert(task,
- "Python failed to create the \"wsgi.url_scheme\" environ value");
- goto fail;
- }
-
- if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.url_scheme", obj)
- != 0))
- {
- nxt_alert(task,
- "Python failed to set the \"wsgi.url_scheme\" environ value");
- goto fail;
- }
-
- Py_DECREF(obj);
- obj = NULL;
-
-
if (nxt_slow_path(PyType_Ready(&nxt_py_input_type) != 0)) {
nxt_alert(task,
"Python failed to initialize the \"wsgi.input\" type object");
@@ -726,6 +706,13 @@ nxt_python_get_environ(nxt_python_run_ctx_t *ctx)
RC(nxt_python_add_sptr(ctx, "REMOTE_ADDR", &r->remote, r->remote_length));
RC(nxt_python_add_sptr(ctx, "SERVER_ADDR", &r->local, r->local_length));
+ if (r->tls) {
+ RC(nxt_python_add_str(ctx, "wsgi.url_scheme", "https", 5));
+
+ } else {
+ RC(nxt_python_add_str(ctx, "wsgi.url_scheme", "http", 4));
+ }
+
RC(nxt_python_add_sptr(ctx, "SERVER_PROTOCOL", &r->version,
r->version_length));
diff --git a/src/nxt_router.c b/src/nxt_router.c
index e46e8f82..149a0ff3 100644
--- a/src/nxt_router.c
+++ b/src/nxt_router.c
@@ -62,7 +62,7 @@ typedef struct {
uint32_t stream;
nxt_app_t *app;
nxt_port_t *app_port;
- nxt_app_parse_ctx_t *ap;
+ nxt_http_request_t *request;
nxt_msg_info_t msg_info;
nxt_req_app_link_t *ra;
@@ -75,7 +75,7 @@ struct nxt_req_app_link_s {
nxt_atomic_t use_count;
nxt_port_t *app_port;
nxt_port_t *reply_port;
- nxt_app_parse_ctx_t *ap;
+ nxt_http_request_t *request;
nxt_msg_info_t msg_info;
nxt_req_conn_link_t *rc;
@@ -264,8 +264,8 @@ static nxt_int_t nxt_router_app_port(nxt_task_t *task, nxt_app_t *app,
static void nxt_router_app_prepare_request(nxt_task_t *task,
nxt_req_app_link_t *ra);
-static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
- nxt_port_t *port, const nxt_str_t *prefix);
+static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task,
+ nxt_http_request_t *r, nxt_port_t *port, const nxt_str_t *prefix);
static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data);
static void nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj,
@@ -282,6 +282,11 @@ static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data);
static void nxt_router_app_joint_use(nxt_task_t *task,
nxt_app_joint_t *app_joint, int i);
+static nxt_int_t nxt_router_http_request_done(nxt_task_t *task,
+ nxt_http_request_t *r);
+static void nxt_router_http_request_release(nxt_task_t *task, void *obj,
+ void *data);
+
static nxt_router_t *nxt_router;
static const nxt_str_t http_prefix = nxt_string("HTTP_");
@@ -502,7 +507,7 @@ nxt_router_ra_init(nxt_task_t *task, nxt_req_app_link_t *ra,
ra->rc = rc;
rc->ra = ra;
ra->reply_port = engine->port;
- ra->ap = rc->ap;
+ ra->request = rc->request;
ra->work.handler = NULL;
ra->work.task = &engine->task;
@@ -521,7 +526,7 @@ nxt_router_ra_create(nxt_task_t *task, nxt_req_app_link_t *ra_src)
return ra_src;
}
- mp = ra_src->ap->mem_pool;
+ mp = ra_src->request->mem_pool;
ra = nxt_mp_alloc(mp, sizeof(nxt_req_app_link_t));
@@ -645,16 +650,16 @@ nxt_router_ra_release(nxt_task_t *task, nxt_req_app_link_t *ra)
if (rc != NULL) {
if (nxt_slow_path(ra->err_code != 0)) {
- nxt_http_request_error(task, rc->ap->request, ra->err_code);
+ nxt_http_request_error(task, rc->request, ra->err_code);
} else {
rc->app_port = ra->app_port;
rc->msg_info = ra->msg_info;
if (rc->app->timeout != 0) {
- rc->ap->timer.handler = nxt_router_app_timeout;
- rc->ap->timer_data = rc;
- nxt_timer_add(task->thread->engine, &rc->ap->timer,
+ rc->request->timer.handler = nxt_router_app_timeout;
+ rc->request->timer_data = rc;
+ nxt_timer_add(task->thread->engine, &rc->request->timer,
rc->app->timeout);
}
@@ -817,12 +822,12 @@ nxt_router_rc_unlink(nxt_task_t *task, nxt_req_conn_link_t *rc)
rc->app = NULL;
}
- if (rc->ap != NULL) {
- rc->ap->timer_data = NULL;
+ if (rc->request != NULL) {
+ rc->request->timer_data = NULL;
- nxt_app_http_req_done(task, rc->ap);
+ nxt_router_http_request_done(task, rc->request);
- rc->ap = NULL;
+ rc->request = NULL;
}
}
@@ -3377,33 +3382,27 @@ static void
nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
void *data)
{
- size_t dump_size;
nxt_int_t ret;
nxt_buf_t *b;
+ nxt_unit_field_t *f;
+ nxt_http_field_t *field;
nxt_http_request_t *r;
nxt_req_conn_link_t *rc;
- nxt_app_parse_ctx_t *ar;
nxt_unit_response_t *resp;
b = msg->buf;
rc = data;
- dump_size = nxt_buf_used_size(b);
-
- if (dump_size > 300) {
- dump_size = 300;
- }
-
if (msg->size == 0) {
b = NULL;
}
- ar = rc->ap;
- if (nxt_slow_path(ar == NULL)) {
+ r = rc->request;
+ if (nxt_slow_path(r == NULL)) {
return;
}
- if (ar->request->error) {
+ if (r->error) {
nxt_router_rc_unlink(task, rc);
return;
}
@@ -3411,15 +3410,15 @@ nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
if (msg->port_msg.last != 0) {
nxt_debug(task, "router data create last buf");
- nxt_buf_chain_add(&b, nxt_http_buf_last(ar->request));
+ nxt_buf_chain_add(&b, nxt_http_buf_last(r));
nxt_router_rc_unlink(task, rc);
} else {
if (rc->app != NULL && rc->app->timeout != 0) {
- ar->timer.handler = nxt_router_app_timeout;
- ar->timer_data = rc;
- nxt_timer_add(task->thread->engine, &ar->timer, rc->app->timeout);
+ r->timer.handler = nxt_router_app_timeout;
+ r->timer_data = rc;
+ nxt_timer_add(task->thread->engine, &r->timer, rc->app->timeout);
}
}
@@ -3432,8 +3431,6 @@ nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
msg->buf = NULL;
}
- r = ar->request;
-
if (r->header_sent) {
nxt_buf_chain_add(&r->out, b);
nxt_http_request_send_body(task, r, NULL);
@@ -3451,11 +3448,8 @@ nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
goto fail;
}
- nxt_unit_field_t *f;
- nxt_http_field_t *field;
-
for (f = resp->fields; f < resp->fields + resp->fields_count; f++) {
- field = nxt_list_add(ar->resp_parser.fields);
+ field = nxt_list_add(r->resp.fields);
if (nxt_slow_path(field == NULL)) {
goto fail;
@@ -3473,15 +3467,8 @@ nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
(size_t) field->name_length, field->name,
(size_t) field->value_length, field->value);
}
- r->status = resp->status;
-/*
- ret = nxt_http_parse_fields(&ar->resp_parser, &b->mem);
- if (nxt_slow_path(ret != NXT_DONE)) {
- goto fail;
- }
-*/
- r->resp.fields = ar->resp_parser.fields;
+ r->status = resp->status;
ret = nxt_http_fields_process(r->resp.fields,
&nxt_response_fields_hash, r);
@@ -3590,8 +3577,8 @@ nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
}
}
- if (rc->ap != NULL) {
- nxt_http_request_error(task, rc->ap->request,
+ if (rc->request != NULL) {
+ nxt_http_request_error(task, rc->request,
NXT_HTTP_SERVICE_UNAVAILABLE);
}
@@ -4452,17 +4439,15 @@ nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra)
void
-nxt_router_process_http_request(nxt_task_t *task, nxt_app_parse_ctx_t *ar,
+nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r,
nxt_app_t *app)
{
nxt_int_t res;
nxt_port_t *port;
nxt_event_engine_t *engine;
- nxt_http_request_t *r;
nxt_req_app_link_t ra_local, *ra;
nxt_req_conn_link_t *rc;
- r = ar->request;
engine = task->thread->engine;
rc = nxt_port_rpc_register_handler_ex(task, engine->port,
@@ -4480,7 +4465,7 @@ nxt_router_process_http_request(nxt_task_t *task, nxt_app_parse_ctx_t *ar,
nxt_router_app_use(task, app, 1);
- rc->ap = ar;
+ rc->request = r;
ra = &ra_local;
nxt_router_ra_init(task, ra, rc);
@@ -4511,17 +4496,15 @@ nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data)
static void
nxt_router_app_prepare_request(nxt_task_t *task, nxt_req_app_link_t *ra)
{
- uint32_t request_failed;
- nxt_buf_t *buf;
- nxt_int_t res;
- nxt_port_t *port, *c_port, *reply_port;
- nxt_app_parse_ctx_t *ap;
+ uint32_t request_failed;
+ nxt_buf_t *buf;
+ nxt_int_t res;
+ nxt_port_t *port, *c_port, *reply_port;
nxt_assert(ra->app_port != NULL);
port = ra->app_port;
reply_port = ra->reply_port;
- ap = ra->ap;
request_failed = 1;
@@ -4539,7 +4522,7 @@ nxt_router_app_prepare_request(nxt_task_t *task, nxt_req_app_link_t *ra)
nxt_process_connected_port_add(port->process, reply_port);
}
- buf = nxt_router_prepare_msg(task, &ap->r, port,
+ buf = nxt_router_prepare_msg(task, ra->request, port,
nxt_app_msg_prefix[port->app->type]);
if (nxt_slow_path(buf == NULL)) {
@@ -4642,34 +4625,33 @@ nxt_fields_next(nxt_fields_iter_t *i)
static nxt_buf_t *
-nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
+nxt_router_prepare_msg(nxt_task_t *task, nxt_http_request_t *r,
nxt_port_t *port, const nxt_str_t *prefix)
{
- void *target_pos, *query_pos;
- u_char *pos, *end, *p, c;
- size_t fields_count, req_size, size, free_size;
- size_t copy_size;
- nxt_buf_t *b, *buf, *out, **tail;
- nxt_http_field_t *field, *dup;
- nxt_unit_field_t *dst_field;
- nxt_fields_iter_t iter, dup_iter;
- nxt_unit_request_t *req;
- nxt_app_request_header_t *h;
-
- h = &r->header;
+ void *target_pos, *query_pos;
+ u_char *pos, *end, *p, c;
+ size_t fields_count, req_size, size, free_size;
+ size_t copy_size;
+ nxt_off_t content_length;
+ nxt_buf_t *b, *buf, *out, **tail;
+ nxt_http_field_t *field, *dup;
+ nxt_unit_field_t *dst_field;
+ nxt_fields_iter_t iter, dup_iter;
+ nxt_unit_request_t *req;
req_size = sizeof(nxt_unit_request_t)
- + h->method.length + 1
- + h->version.length + 1
- + r->remote.length + 1
- + r->local.length + 1
- + h->server_name.length + 1
- + h->target.length + 1
- + (h->path.start != h->target.start ? h->path.length + 1 : 0);
-
+ + r->method->length + 1
+ + r->version.length + 1
+ + r->remote->length + 1
+ + r->local->length + 1
+ + r->server_name.length + 1
+ + r->target.length + 1
+ + (r->path->start != r->target.start ? r->path->length + 1 : 0);
+
+ content_length = r->content_length_n < 0 ? 0 : r->content_length_n;
fields_count = 0;
- nxt_list_each(field, h->fields) {
+ nxt_list_each(field, r->fields) {
fields_count++;
req_size += field->name_length + prefix->length + 1
@@ -4686,7 +4668,7 @@ nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
}
out = nxt_port_mmap_get_buf(task, port,
- nxt_min(req_size + r->body.preread_size, PORT_MMAP_DATA_SIZE));
+ nxt_min(req_size + content_length, PORT_MMAP_DATA_SIZE));
if (nxt_slow_path(out == NULL)) {
return NULL;
}
@@ -4694,57 +4676,60 @@ nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
req = (nxt_unit_request_t *) out->mem.free;
out->mem.free += req_size;
- req->content_length = h->parsed_content_length;
+ req->content_length = content_length;
p = (u_char *) (req->fields + fields_count);
nxt_debug(task, "fields_count=%d", (int) fields_count);
- req->method_length = h->method.length;
+ req->method_length = r->method->length;
nxt_unit_sptr_set(&req->method, p);
- p = nxt_cpymem(p, h->method.start, h->method.length);
+ p = nxt_cpymem(p, r->method->start, r->method->length);
*p++ = '\0';
- req->version_length = h->version.length;
+ req->version_length = r->version.length;
nxt_unit_sptr_set(&req->version, p);
- p = nxt_cpymem(p, h->version.start, h->version.length);
+ p = nxt_cpymem(p, r->version.start, r->version.length);
*p++ = '\0';
- req->remote_length = r->remote.length;
+ req->remote_length = r->remote->address_length;
nxt_unit_sptr_set(&req->remote, p);
- p = nxt_cpymem(p, r->remote.start, r->remote.length);
+ p = nxt_cpymem(p, nxt_sockaddr_address(r->remote),
+ r->remote->address_length);
*p++ = '\0';
- req->local_length = r->local.length;
+ req->local_length = r->local->address_length;
nxt_unit_sptr_set(&req->local, p);
- p = nxt_cpymem(p, r->local.start, r->local.length);
+ p = nxt_cpymem(p, nxt_sockaddr_address(r->local), r->local->address_length);
*p++ = '\0';
- req->server_name_length = h->server_name.length;
+ req->tls = (r->tls != NULL);
+
+ req->server_name_length = r->server_name.length;
nxt_unit_sptr_set(&req->server_name, p);
- p = nxt_cpymem(p, h->server_name.start, h->server_name.length);
+ p = nxt_cpymem(p, r->server_name.start, r->server_name.length);
*p++ = '\0';
target_pos = p;
- req->target_length = h->target.length;
+ req->target_length = (uint32_t) r->target.length;
nxt_unit_sptr_set(&req->target, p);
- p = nxt_cpymem(p, h->target.start, h->target.length);
+ p = nxt_cpymem(p, r->target.start, r->target.length);
*p++ = '\0';
- req->path_length = h->path.length;
- if (h->path.start == h->target.start) {
+ req->path_length = (uint32_t) r->path->length;
+ if (r->path->start == r->target.start) {
nxt_unit_sptr_set(&req->path, target_pos);
} else {
nxt_unit_sptr_set(&req->path, p);
- p = nxt_cpymem(p, h->path.start, h->path.length);
+ p = nxt_cpymem(p, r->path->start, r->path->length);
*p++ = '\0';
}
- req->query_length = h->query.length;
- if (h->query.start != NULL) {
+ req->query_length = r->args != NULL ? (uint32_t) r->args->length : 0;
+ if (r->args != NULL && r->args->start != NULL) {
query_pos = nxt_pointer_to(target_pos,
- h->query.start - h->target.start);
+ r->args->start - r->target.start);
nxt_unit_sptr_set(&req->query, query_pos);
@@ -4758,7 +4743,7 @@ nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
dst_field = req->fields;
- for (field = nxt_fields_first(h->fields, &iter);
+ for (field = nxt_fields_first(r->fields, &iter);
field != NULL;
field = nxt_fields_next(&iter))
{
@@ -4771,13 +4756,13 @@ nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
dst_field->name_length = field->name_length + prefix->length;
dst_field->value_length = field->value_length;
- if (field->value == h->content_length.start) {
+ if (field == r->content_length) {
req->content_length_field = dst_field - req->fields;
- } else if (field->value == h->content_type.start) {
+ } else if (field == r->content_type) {
req->content_type_field = dst_field - req->fields;
- } else if (field->value == h->cookie.start) {
+ } else if (field == r->cookie) {
req->cookie_field = dst_field - req->fields;
}
@@ -4846,14 +4831,14 @@ nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
dst_field++;
}
- req->fields_count = dst_field - req->fields;
+ req->fields_count = (uint32_t) (dst_field - req->fields);
nxt_unit_sptr_set(&req->preread_content, out->mem.free);
buf = out;
tail = &buf->next;
- for (b = r->body.buf; b != NULL; b = b->next) {
+ for (b = r->body; b != NULL; b = b->next) {
size = nxt_buf_mem_used_size(&b->mem);
pos = b->mem.pos;
@@ -4913,8 +4898,8 @@ nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data)
nxt_port_t *port;
nxt_timer_t *timer;
nxt_queue_link_t *lnk;
+ nxt_http_request_t *r;
nxt_req_app_link_t *pending_ra;
- nxt_app_parse_ctx_t *ar;
nxt_req_conn_link_t *rc;
nxt_port_select_state_t state;
@@ -4922,8 +4907,8 @@ nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data)
nxt_debug(task, "router app timeout");
- ar = nxt_timer_data(timer, nxt_app_parse_ctx_t, timer);
- rc = ar->timer_data;
+ r = nxt_timer_data(timer, nxt_http_request_t, timer);
+ rc = r->timer_data;
app = rc->app;
if (app == NULL) {
@@ -4994,7 +4979,30 @@ nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data)
generate_error:
- nxt_http_request_error(task, ar->request, NXT_HTTP_SERVICE_UNAVAILABLE);
+ nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE);
nxt_router_rc_unlink(task, rc);
}
+
+
+static nxt_int_t
+nxt_router_http_request_done(nxt_task_t *task, nxt_http_request_t *r)
+{
+ r->timer.handler = nxt_router_http_request_release;
+ nxt_timer_add(task->thread->engine, &r->timer, 0);
+
+ return NXT_OK;
+}
+
+
+static void
+nxt_router_http_request_release(nxt_task_t *task, void *obj, void *data)
+{
+ nxt_http_request_t *r;
+
+ nxt_debug(task, "http app release");
+
+ r = nxt_timer_data(obj, nxt_http_request_t, timer);
+
+ nxt_mp_release(r->mem_pool);
+}
diff --git a/src/nxt_router.h b/src/nxt_router.h
index dec56bd5..d9fbfe05 100644
--- a/src/nxt_router.h
+++ b/src/nxt_router.h
@@ -21,6 +21,9 @@ typedef struct nxt_http_routes_s nxt_http_routes_t;
typedef struct nxt_router_access_log_s nxt_router_access_log_t;
+#define NXT_HTTP_PASS_ERROR ((nxt_http_pass_t *) -1)
+
+
typedef struct {
nxt_thread_spinlock_t lock;
nxt_queue_t engines;
@@ -192,7 +195,7 @@ void nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg);
void nxt_router_access_log_reopen_handler(nxt_task_t *task,
nxt_port_recv_msg_t *msg);
-void nxt_router_process_http_request(nxt_task_t *task, nxt_app_parse_ctx_t *ar,
+void nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r,
nxt_app_t *app);
void nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port);
nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf,
diff --git a/src/nxt_runtime.c b/src/nxt_runtime.c
index 547c7494..06478f72 100644
--- a/src/nxt_runtime.c
+++ b/src/nxt_runtime.c
@@ -53,14 +53,13 @@ nxt_runtime_create(nxt_task_t *task)
nxt_app_lang_module_t *lang;
mp = nxt_mp_create(1024, 128, 256, 32);
-
if (nxt_slow_path(mp == NULL)) {
return NXT_ERROR;
}
rt = nxt_mp_zget(mp, sizeof(nxt_runtime_t));
if (nxt_slow_path(rt == NULL)) {
- return NXT_ERROR;
+ goto fail;
}
task->thread->runtime = rt;
diff --git a/src/nxt_sockaddr.c b/src/nxt_sockaddr.c
index a001c730..99cf54b4 100644
--- a/src/nxt_sockaddr.c
+++ b/src/nxt_sockaddr.c
@@ -197,23 +197,23 @@ nxt_getsockname(nxt_task_t *task, nxt_mp_t *mp, nxt_socket_t s)
switch (sockaddr.buf.sa_family) {
#if (NXT_INET6)
case AF_INET6:
- length = NXT_INET6_ADDR_STR_LEN;
- break;
+ length = NXT_INET6_ADDR_STR_LEN;
+ break;
#endif
#if (NXT_HAVE_UNIX_DOMAIN)
case AF_UNIX:
- length = nxt_length("unix:") + socklen;
+ length = nxt_length("unix:") + socklen;
#endif
- break;
+ break;
case AF_INET:
- length = NXT_INET_ADDR_STR_LEN;
- break;
+ length = NXT_INET_ADDR_STR_LEN;
+ break;
default:
- length = 0;
- break;
+ length = 0;
+ break;
}
return nxt_sockaddr_create(mp, &sockaddr.buf, socklen, length);
diff --git a/src/nxt_socket.h b/src/nxt_socket.h
index 42ef6c53..3f00648d 100644
--- a/src/nxt_socket.h
+++ b/src/nxt_socket.h
@@ -112,9 +112,9 @@ NXT_EXPORT nxt_int_t nxt_socketpair_create(nxt_task_t *task,
nxt_socket_t *pair);
NXT_EXPORT void nxt_socketpair_close(nxt_task_t *task, nxt_socket_t *pair);
NXT_EXPORT ssize_t nxt_socketpair_send(nxt_fd_event_t *ev, nxt_fd_t fd,
- nxt_iobuf_t *iob, nxt_uint_t niob);
+ nxt_iobuf_t *iob, nxt_uint_t niob);
NXT_EXPORT ssize_t nxt_socketpair_recv(nxt_fd_event_t *ev, nxt_fd_t *fd,
- nxt_iobuf_t *iob, nxt_uint_t niob);
+ nxt_iobuf_t *iob, nxt_uint_t niob);
#define \
diff --git a/src/nxt_socketpair.c b/src/nxt_socketpair.c
index a7396b31..10ea562e 100644
--- a/src/nxt_socketpair.c
+++ b/src/nxt_socketpair.c
@@ -21,9 +21,9 @@
static ssize_t nxt_sendmsg(nxt_socket_t s, nxt_fd_t fd, nxt_iobuf_t *iob,
- nxt_uint_t niob);
+ nxt_uint_t niob);
static ssize_t nxt_recvmsg(nxt_socket_t s, nxt_fd_t *fd, nxt_iobuf_t *iob,
- nxt_uint_t niob);
+ nxt_uint_t niob);
nxt_int_t
@@ -94,9 +94,14 @@ nxt_socketpair_send(nxt_fd_event_t *ev, nxt_fd_t fd, nxt_iobuf_t *iob,
case NXT_EAGAIN:
nxt_debug(ev->task, "sendmsg(%d) not ready", ev->fd);
- ev->write_ready = 0;
+ break;
- return NXT_AGAIN;
+ /*
+ * Returned (at least on OSX) when trying to send many small messages.
+ */
+ case NXT_ENOBUFS:
+ nxt_debug(ev->task, "sendmsg(%d) no buffers", ev->fd);
+ break;
case NXT_EINTR:
nxt_debug(ev->task, "sendmsg(%d) interrupted", ev->fd);
@@ -108,6 +113,10 @@ nxt_socketpair_send(nxt_fd_event_t *ev, nxt_fd_t fd, nxt_iobuf_t *iob,
return NXT_ERROR;
}
+
+ ev->write_ready = 0;
+
+ return NXT_AGAIN;
}
}
diff --git a/src/nxt_sprintf.c b/src/nxt_sprintf.c
index 0b387883..240f47ef 100644
--- a/src/nxt_sprintf.c
+++ b/src/nxt_sprintf.c
@@ -76,12 +76,12 @@ nxt_sprintf(u_char *buf, u_char *end, const char *fmt, ...)
*/
typedef struct {
- u_char *end;
- const u_char *hex;
- uint32_t width;
- int32_t frac_width;
- uint8_t max_width;
- u_char padding;
+ u_char *end;
+ const u_char *hex;
+ uint32_t width;
+ int32_t frac_width;
+ uint8_t max_width;
+ u_char padding;
} nxt_sprintf_t;
diff --git a/src/nxt_timer.h b/src/nxt_timer.h
index 4199f0dd..3ccff848 100644
--- a/src/nxt_timer.h
+++ b/src/nxt_timer.h
@@ -69,7 +69,7 @@ typedef struct {
nxt_uint_t mchanges;
nxt_uint_t nchanges;
- nxt_timer_change_t *changes;
+ nxt_timer_change_t *changes;
} nxt_timers_t;
diff --git a/src/nxt_unicode_lowcase.pl b/src/nxt_unicode_lowcase.pl
index 974ae23a..abf64965 100644
--- a/src/nxt_unicode_lowcase.pl
+++ b/src/nxt_unicode_lowcase.pl
@@ -29,9 +29,9 @@ my $last_block_size = $max_lowcase % BLOCK_SIZE + 1;
for my $block (sort { $a <=> $b } keys %blocks) {
- if ($max_block < $block) {
- $max_block = $block;
- }
+ if ($max_block < $block) {
+ $max_block = $block;
+ }
}
diff --git a/src/nxt_unit.c b/src/nxt_unit.c
index 6339aec5..88c7fa6a 100644
--- a/src/nxt_unit.c
+++ b/src/nxt_unit.c
@@ -1946,10 +1946,10 @@ nxt_unit_mmap_at(nxt_unit_mmaps_t *mmaps, uint32_t i)
while (i + 1 > cap) {
if (cap < 16) {
- cap = cap * 2;
+ cap = cap * 2;
} else {
- cap = cap + cap / 2;
+ cap = cap + cap / 2;
}
}
diff --git a/src/nxt_unit_request.h b/src/nxt_unit_request.h
index 88d569a6..2207cefa 100644
--- a/src/nxt_unit_request.h
+++ b/src/nxt_unit_request.h
@@ -19,6 +19,7 @@ struct nxt_unit_request_s {
uint8_t version_length;
uint8_t remote_length;
uint8_t local_length;
+ uint8_t tls;
uint32_t server_name_length;
uint32_t target_length;
uint32_t path_length;
diff --git a/src/perl/nxt_perl_psgi.c b/src/perl/nxt_perl_psgi.c
index 0b4b31d7..b99d3269 100644
--- a/src/perl/nxt_perl_psgi.c
+++ b/src/perl/nxt_perl_psgi.c
@@ -656,8 +656,11 @@ nxt_perl_psgi_env_create(PerlInterpreter *my_perl,
RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.version"),
newRV_noinc((SV *) array_version)));
+
RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.url_scheme"),
- newSVpv("http", 4)));
+ r->tls ? newSVpv("https", 5)
+ : newSVpv("http", 4)));
+
RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.input"),
SvREFCNT_inc(nxt_perl_psgi_arg_input.io)));
RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.errors"),
diff --git a/src/ruby/nxt_ruby.c b/src/ruby/nxt_ruby.c
index b2398abe..ab9f7020 100644
--- a/src/ruby/nxt_ruby.c
+++ b/src/ruby/nxt_ruby.c
@@ -327,7 +327,6 @@ nxt_ruby_rack_env_create(VALUE arg)
rb_ary_push(version, UINT2NUM(NXT_RUBY_RACK_API_VERSION_MINOR));
rb_hash_aset(hash_env, rb_str_new2("rack.version"), version);
- rb_hash_aset(hash_env, rb_str_new2("rack.url_scheme"), rb_str_new2("http"));
rb_hash_aset(hash_env, rb_str_new2("rack.input"), nxt_ruby_io_input);
rb_hash_aset(hash_env, rb_str_new2("rack.errors"), nxt_ruby_io_error);
rb_hash_aset(hash_env, rb_str_new2("rack.multithread"), Qfalse);
@@ -454,6 +453,9 @@ nxt_ruby_read_request(VALUE hash_env)
r->server_name_length);
nxt_ruby_add_str(hash_env, NL("SERVER_PORT"), "80", 2);
+ rb_hash_aset(hash_env, rb_str_new2("rack.url_scheme"),
+ r->tls ? rb_str_new2("https") : rb_str_new2("http"));
+
for (i = 0; i < r->fields_count; i++) {
f = r->fields + i;