Unit application library.

Library now used in all language modules.
Old 'nxt_app_*' code removed.

See src/test/nxt_unit_app_test.c for usage sample.
This commit is contained in:
Max Romanov
2018-08-06 17:27:33 +03:00
parent b6ce2da65c
commit 1bb22d1e92
54 changed files with 6685 additions and 4469 deletions

View File

@@ -8,6 +8,9 @@
#include <nxt_router.h>
#include <nxt_conf.h>
#include <nxt_http.h>
#include <nxt_port_memory_int.h>
#include <nxt_unit_request.h>
#include <nxt_unit_response.h>
typedef struct {
@@ -241,16 +244,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_int_t nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
nxt_app_wmsg_t *wmsg);
static nxt_int_t nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
nxt_app_wmsg_t *wmsg);
static nxt_int_t nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
nxt_app_wmsg_t *wmsg);
static nxt_int_t nxt_perl_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
nxt_app_wmsg_t *wmsg);
static nxt_int_t nxt_ruby_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
nxt_app_wmsg_t *wmsg);
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 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,
@@ -265,13 +260,15 @@ static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data);
static nxt_router_t *nxt_router;
static const nxt_str_t http_prefix = nxt_string("HTTP_");
static const nxt_str_t empty_prefix = nxt_string("");
static nxt_app_prepare_msg_t nxt_app_prepare_msg[] = {
nxt_python_prepare_msg,
nxt_php_prepare_msg,
nxt_go_prepare_msg,
nxt_perl_prepare_msg,
nxt_ruby_prepare_msg,
static const nxt_str_t *nxt_app_msg_prefix[] = {
&http_prefix,
&http_prefix,
&empty_prefix,
&http_prefix,
&http_prefix,
};
@@ -1459,7 +1456,6 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
app->live = 1;
app->max_pending_responses = 2;
app->max_requests = apcf.requests;
app->prepare_msg = nxt_app_prepare_msg[lang->type];
engine = task->thread->engine;
@@ -3145,6 +3141,7 @@ nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
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;
@@ -3204,11 +3201,48 @@ nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
nxt_http_request_send_body(task, r, NULL);
} else {
size_t b_size = nxt_buf_mem_used_size(&b->mem);
if (nxt_slow_path(b_size < sizeof(*resp))) {
goto fail;
}
resp = (void *) b->mem.pos;
if (nxt_slow_path(b_size < sizeof(*resp)
+ resp->fields_count * sizeof(nxt_unit_field_t))) {
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);
if (nxt_slow_path(field == NULL)) {
goto fail;
}
field->hash = f->hash;
field->skip = f->skip;
field->name_length = f->name_length;
field->value_length = f->value_length;
field->name = nxt_unit_sptr_get(&f->name);
field->value = nxt_unit_sptr_get(&f->value);
nxt_debug(task, "header: %*s: %*s",
(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;
ret = nxt_http_fields_process(r->resp.fields,
@@ -3217,6 +3251,14 @@ nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
goto fail;
}
if (resp->piggyback_content_length != 0) {
b->mem.pos = nxt_unit_sptr_get(&resp->piggyback_content);
b->mem.free = b->mem.pos + resp->piggyback_content_length;
} else {
b->mem.pos = b->mem.free;
}
if (nxt_buf_mem_used_size(&b->mem) == 0) {
nxt_work_queue_add(&task->thread->engine->fast_work_queue,
b->completion_handler, task, b, b->parent);
@@ -4208,10 +4250,9 @@ static void
nxt_router_app_prepare_request(nxt_task_t *task, nxt_req_app_link_t *ra)
{
uint32_t request_failed;
nxt_buf_t *b;
nxt_buf_t *buf;
nxt_int_t res;
nxt_port_t *port, *c_port, *reply_port;
nxt_app_wmsg_t wmsg;
nxt_app_parse_ctx_t *ap;
nxt_assert(ra->app_port != NULL);
@@ -4236,32 +4277,30 @@ nxt_router_app_prepare_request(nxt_task_t *task, nxt_req_app_link_t *ra)
nxt_process_connected_port_add(port->process, reply_port);
}
wmsg.port = port;
wmsg.write = NULL;
wmsg.buf = &wmsg.write;
wmsg.stream = ra->stream;
buf = nxt_router_prepare_msg(task, &ap->r, port,
nxt_app_msg_prefix[port->app->type]);
res = port->app->prepare_msg(task, &ap->r, &wmsg);
if (nxt_slow_path(res != NXT_OK)) {
if (nxt_slow_path(buf == NULL)) {
nxt_router_ra_error(ra, 500,
"Failed to prepare message for application");
goto release_port;
}
nxt_debug(task, "about to send %O bytes buffer to app process port %d",
nxt_buf_used_size(wmsg.write),
wmsg.port->socket.fd);
nxt_buf_used_size(buf),
port->socket.fd);
request_failed = 0;
ra->msg_info.buf = wmsg.write;
ra->msg_info.completion_handler = wmsg.write->completion_handler;
ra->msg_info.buf = buf;
ra->msg_info.completion_handler = buf->completion_handler;
for (b = wmsg.write; b != NULL; b = b->next) {
b->completion_handler = nxt_router_dummy_buf_completion;
for (; buf; buf = buf->next) {
buf->completion_handler = nxt_router_dummy_buf_completion;
}
buf = ra->msg_info.buf;
res = nxt_port_mmap_get_tracking(task, port, &ra->msg_info.tracking,
ra->stream);
if (nxt_slow_path(res != NXT_OK)) {
@@ -4270,8 +4309,8 @@ nxt_router_app_prepare_request(nxt_task_t *task, nxt_req_app_link_t *ra)
goto release_port;
}
res = nxt_port_socket_twrite(task, wmsg.port, NXT_PORT_MSG_DATA,
-1, ra->stream, reply_port->id, wmsg.write,
res = nxt_port_socket_twrite(task, port, NXT_PORT_MSG_DATA,
-1, ra->stream, reply_port->id, buf,
&ra->msg_info.tracking);
if (nxt_slow_path(res != NXT_OK)) {
@@ -4288,421 +4327,317 @@ release_port:
}
static nxt_int_t
nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
nxt_app_wmsg_t *wmsg)
{
nxt_int_t rc;
nxt_buf_t *b;
nxt_http_field_t *field;
nxt_app_request_header_t *h;
struct nxt_fields_iter_s {
nxt_list_part_t *part;
nxt_http_field_t *field;
};
static const nxt_str_t prefix = nxt_string("HTTP_");
static const nxt_str_t eof = nxt_null_string;
typedef struct nxt_fields_iter_s nxt_fields_iter_t;
static nxt_http_field_t *
nxt_fields_part_first(nxt_list_part_t *part, nxt_fields_iter_t *i)
{
if (part == NULL) {
return NULL;
}
while (part->nelts == 0) {
part = part->next;
if (part == NULL) {
return NULL;
}
}
i->part = part;
i->field = nxt_list_data(i->part);
return i->field;
}
static nxt_http_field_t *
nxt_fields_first(nxt_list_t *fields, nxt_fields_iter_t *i)
{
return nxt_fields_part_first(nxt_list_part(fields), i);
}
static nxt_http_field_t *
nxt_fields_next(nxt_fields_iter_t *i)
{
nxt_http_field_t *end = nxt_list_data(i->part);
end += i->part->nelts;
i->field++;
if (i->field < end) {
return i->field;
}
return nxt_fields_part_first(i->part->next, i);
}
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)
{
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;
#define RC(S) \
do { \
rc = (S); \
if (nxt_slow_path(rc != NXT_OK)) { \
goto fail; \
} \
} while(0)
req_size = sizeof(nxt_unit_request_t)
+ h->method.length + 1
+ h->version.length + 1
+ r->remote.length + 1
+ r->local.length + 1
+ h->target.length + 1
+ (h->path.start != h->target.start ? h->path.length + 1 : 0);
#define NXT_WRITE(N) \
RC(nxt_app_msg_write_str(task, wmsg, N))
fields_count = 0;
/* TODO error handle, async mmap buffer assignment */
nxt_list_each(field, h->fields) {
fields_count++;
NXT_WRITE(&h->method);
NXT_WRITE(&h->target);
req_size += field->name_length + prefix->length + 1
+ field->value_length + 1;
} nxt_list_loop;
req_size += fields_count * sizeof(nxt_unit_field_t);
if (nxt_slow_path(req_size > PORT_MMAP_DATA_SIZE)) {
nxt_alert(task, "headers to big to fit in shared memory (%d)",
(int) req_size);
return NULL;
}
out = nxt_port_mmap_get_buf(task, port,
nxt_min(req_size + r->body.preread_size, PORT_MMAP_DATA_SIZE));
if (nxt_slow_path(out == NULL)) {
return NULL;
}
req = (nxt_unit_request_t *) out->mem.free;
out->mem.free += req_size;
req->content_length = h->parsed_content_length;
p = (u_char *) (req->fields + fields_count);
nxt_debug(task, "fields_count=%d", (int) fields_count);
req->method_length = h->method.length;
nxt_unit_sptr_set(&req->method, p);
p = nxt_cpymem(p, h->method.start, h->method.length);
*p++ = '\0';
req->version_length = h->version.length;
nxt_unit_sptr_set(&req->version, p);
p = nxt_cpymem(p, h->version.start, h->version.length);
*p++ = '\0';
req->remote_length = r->remote.length;
nxt_unit_sptr_set(&req->remote, p);
p = nxt_cpymem(p, r->remote.start, r->remote.length);
*p++ = '\0';
req->local_length = r->local.length;
nxt_unit_sptr_set(&req->local, p);
p = nxt_cpymem(p, r->local.start, r->local.length);
*p++ = '\0';
target_pos = p;
req->target_length = h->target.length;
nxt_unit_sptr_set(&req->target, p);
p = nxt_cpymem(p, h->target.start, h->target.length);
*p++ = '\0';
req->path_length = h->path.length;
if (h->path.start == h->target.start) {
NXT_WRITE(&eof);
nxt_unit_sptr_set(&req->path, target_pos);
} else {
NXT_WRITE(&h->path);
nxt_unit_sptr_set(&req->path, p);
p = nxt_cpymem(p, h->path.start, h->path.length);
*p++ = '\0';
}
req->query_length = h->query.length;
if (h->query.start != NULL) {
RC(nxt_app_msg_write_size(task, wmsg,
h->query.start - h->target.start + 1));
query_pos = nxt_pointer_to(target_pos,
h->query.start - h->target.start);
nxt_unit_sptr_set(&req->query, query_pos);
} else {
RC(nxt_app_msg_write_size(task, wmsg, 0));
req->query.offset = 0;
}
NXT_WRITE(&h->version);
req->host_field = NXT_UNIT_NONE_FIELD;
req->content_length_field = NXT_UNIT_NONE_FIELD;
req->content_type_field = NXT_UNIT_NONE_FIELD;
req->cookie_field = NXT_UNIT_NONE_FIELD;
NXT_WRITE(&r->remote);
NXT_WRITE(&r->local);
dst_field = req->fields;
NXT_WRITE(&h->host);
NXT_WRITE(&h->content_type);
NXT_WRITE(&h->content_length);
for (field = nxt_fields_first(h->fields, &iter);
field != NULL;
field = nxt_fields_next(&iter))
{
if (field->skip) {
continue;
}
nxt_list_each(field, h->fields) {
RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, &prefix, field->name,
field->name_length));
RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length));
dst_field->hash = field->hash;
dst_field->skip = 0;
dst_field->name_length = field->name_length + prefix->length;
dst_field->value_length = field->value_length;
} nxt_list_loop;
if (field->value == h->host.start) {
req->host_field = dst_field - req->fields;
/* end-of-headers mark */
NXT_WRITE(&eof);
} else if (field->value == h->content_length.start) {
req->content_length_field = dst_field - req->fields;
RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
} else if (field->value == h->content_type.start) {
req->content_type_field = dst_field - req->fields;
} else if (field->value == h->cookie.start) {
req->cookie_field = dst_field - req->fields;
}
nxt_debug(task, "add field 0x%04Xd, %d, %d, %p : %d %p",
(int) field->hash, (int) field->skip,
(int) field->name_length, field->name,
(int) field->value_length, field->value);
if (prefix->length != 0) {
nxt_unit_sptr_set(&dst_field->name, p);
p = nxt_cpymem(p, prefix->start, prefix->length);
end = field->name + field->name_length;
for (pos = field->name; pos < end; pos++) {
c = *pos;
if (c >= 'a' && c <= 'z') {
*p++ = (c & ~0x20);
continue;
}
if (c == '-') {
*p++ = '_';
continue;
}
*p++ = c;
}
} else {
nxt_unit_sptr_set(&dst_field->name, p);
p = nxt_cpymem(p, field->name, field->name_length);
}
*p++ = '\0';
nxt_unit_sptr_set(&dst_field->value, p);
p = nxt_cpymem(p, field->value, field->value_length);
if (prefix->length != 0) {
dup_iter = iter;
for (dup = nxt_fields_next(&dup_iter);
dup != NULL;
dup = nxt_fields_next(&dup_iter))
{
if (dup->name_length != field->name_length
|| dup->skip
|| dup->hash != field->hash
|| nxt_memcasecmp(dup->name, field->name, dup->name_length))
{
continue;
}
p = nxt_cpymem(p, ", ", 2);
p = nxt_cpymem(p, dup->value, dup->value_length);
dst_field->value_length += 2 + dup->value_length;
dup->skip = 1;
}
}
*p++ = '\0';
dst_field++;
}
req->fields_count = 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) {
RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
nxt_buf_mem_used_size(&b->mem)));
size = nxt_buf_mem_used_size(&b->mem);
pos = b->mem.pos;
while (size > 0) {
if (buf == NULL) {
free_size = nxt_min(size, PORT_MMAP_DATA_SIZE);
buf = nxt_port_mmap_get_buf(task, port, free_size);
if (nxt_slow_path(buf == NULL)) {
while (out != NULL) {
buf = out->next;
out->completion_handler(task, out, out->parent);
out = buf;
}
return NULL;
}
*tail = buf;
tail = &buf->next;
} else {
free_size = nxt_buf_mem_free_size(&buf->mem);
if (free_size < size
&& nxt_port_mmap_increase_buf(task, buf, size, 1)
== NXT_OK)
{
free_size = nxt_buf_mem_free_size(&buf->mem);
}
}
if (free_size > 0) {
copy_size = nxt_min(free_size, size);
buf->mem.free = nxt_cpymem(buf->mem.free, pos, copy_size);
size -= copy_size;
pos += copy_size;
if (size == 0) {
break;
}
}
buf = NULL;
}
}
#undef NXT_WRITE
#undef RC
return NXT_OK;
fail:
return NXT_ERROR;
}
static nxt_int_t
nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
nxt_app_wmsg_t *wmsg)
{
nxt_int_t rc;
nxt_buf_t *b;
nxt_http_field_t *field;
nxt_app_request_header_t *h;
static const nxt_str_t prefix = nxt_string("HTTP_");
static const nxt_str_t eof = nxt_null_string;
h = &r->header;
#define RC(S) \
do { \
rc = (S); \
if (nxt_slow_path(rc != NXT_OK)) { \
goto fail; \
} \
} while(0)
#define NXT_WRITE(N) \
RC(nxt_app_msg_write_str(task, wmsg, N))
/* TODO error handle, async mmap buffer assignment */
NXT_WRITE(&h->method);
NXT_WRITE(&h->target);
if (h->path.start == h->target.start) {
NXT_WRITE(&eof);
} else {
NXT_WRITE(&h->path);
}
if (h->query.start != NULL) {
RC(nxt_app_msg_write_size(task, wmsg,
h->query.start - h->target.start + 1));
} else {
RC(nxt_app_msg_write_size(task, wmsg, 0));
}
NXT_WRITE(&h->version);
// PHP_SELF
// SCRIPT_NAME
// SCRIPT_FILENAME
// DOCUMENT_ROOT
NXT_WRITE(&r->remote);
NXT_WRITE(&r->local);
NXT_WRITE(&h->host);
NXT_WRITE(&h->cookie);
NXT_WRITE(&h->content_type);
NXT_WRITE(&h->content_length);
RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length));
RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
for (b = r->body.buf; b != NULL; b = b->next) {
RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
nxt_buf_mem_used_size(&b->mem)));
}
nxt_list_each(field, h->fields) {
RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, &prefix, field->name,
field->name_length));
RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length));
} nxt_list_loop;
/* end-of-headers mark */
NXT_WRITE(&eof);
#undef NXT_WRITE
#undef RC
return NXT_OK;
fail:
return NXT_ERROR;
}
static nxt_int_t
nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, nxt_app_wmsg_t *wmsg)
{
nxt_int_t rc;
nxt_buf_t *b;
nxt_http_field_t *field;
nxt_app_request_header_t *h;
static const nxt_str_t eof = nxt_null_string;
h = &r->header;
#define RC(S) \
do { \
rc = (S); \
if (nxt_slow_path(rc != NXT_OK)) { \
goto fail; \
} \
} while(0)
#define NXT_WRITE(N) \
RC(nxt_app_msg_write_str(task, wmsg, N))
/* TODO error handle, async mmap buffer assignment */
NXT_WRITE(&h->method);
NXT_WRITE(&h->target);
if (h->path.start == h->target.start) {
NXT_WRITE(&eof);
} else {
NXT_WRITE(&h->path);
}
if (h->query.start != NULL) {
RC(nxt_app_msg_write_size(task, wmsg,
h->query.start - h->target.start + 1));
} else {
RC(nxt_app_msg_write_size(task, wmsg, 0));
}
NXT_WRITE(&h->version);
NXT_WRITE(&r->remote);
NXT_WRITE(&h->host);
NXT_WRITE(&h->cookie);
NXT_WRITE(&h->content_type);
NXT_WRITE(&h->content_length);
RC(nxt_app_msg_write_size(task, wmsg, h->parsed_content_length));
nxt_list_each(field, h->fields) {
RC(nxt_app_msg_write(task, wmsg, field->name, field->name_length));
RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length));
} nxt_list_loop;
/* end-of-headers mark */
NXT_WRITE(&eof);
RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
for (b = r->body.buf; b != NULL; b = b->next) {
RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
nxt_buf_mem_used_size(&b->mem)));
}
#undef NXT_WRITE
#undef RC
return NXT_OK;
fail:
return NXT_ERROR;
}
static nxt_int_t
nxt_perl_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
nxt_app_wmsg_t *wmsg)
{
nxt_int_t rc;
nxt_str_t str;
nxt_buf_t *b;
nxt_http_field_t *field;
nxt_app_request_header_t *h;
static const nxt_str_t prefix = nxt_string("HTTP_");
static const nxt_str_t eof = nxt_null_string;
h = &r->header;
#define RC(S) \
do { \
rc = (S); \
if (nxt_slow_path(rc != NXT_OK)) { \
goto fail; \
} \
} while(0)
#define NXT_WRITE(N) \
RC(nxt_app_msg_write_str(task, wmsg, N))
/* TODO error handle, async mmap buffer assignment */
NXT_WRITE(&h->method);
NXT_WRITE(&h->target);
if (h->query.length) {
str.start = h->target.start;
str.length = (h->target.length - h->query.length) - 1;
RC(nxt_app_msg_write_str(task, wmsg, &str));
} else {
NXT_WRITE(&eof);
}
if (h->query.start != NULL) {
RC(nxt_app_msg_write_size(task, wmsg,
h->query.start - h->target.start + 1));
} else {
RC(nxt_app_msg_write_size(task, wmsg, 0));
}
NXT_WRITE(&h->version);
NXT_WRITE(&r->remote);
NXT_WRITE(&r->local);
NXT_WRITE(&h->host);
NXT_WRITE(&h->content_type);
NXT_WRITE(&h->content_length);
nxt_list_each(field, h->fields) {
RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, &prefix,
field->name, field->name_length));
RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length));
} nxt_list_loop;
/* end-of-headers mark */
NXT_WRITE(&eof);
RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
for (b = r->body.buf; b != NULL; b = b->next) {
RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
nxt_buf_mem_used_size(&b->mem)));
}
#undef NXT_WRITE
#undef RC
return NXT_OK;
fail:
return NXT_ERROR;
}
static nxt_int_t
nxt_ruby_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
nxt_app_wmsg_t *wmsg)
{
nxt_int_t rc;
nxt_str_t str;
nxt_buf_t *b;
nxt_http_field_t *field;
nxt_app_request_header_t *h;
static const nxt_str_t prefix = nxt_string("HTTP_");
static const nxt_str_t eof = nxt_null_string;
h = &r->header;
#define RC(S) \
do { \
rc = (S); \
if (nxt_slow_path(rc != NXT_OK)) { \
goto fail; \
} \
} while(0)
#define NXT_WRITE(N) \
RC(nxt_app_msg_write_str(task, wmsg, N))
/* TODO error handle, async mmap buffer assignment */
NXT_WRITE(&h->method);
NXT_WRITE(&h->target);
if (h->query.length) {
str.start = h->target.start;
str.length = (h->target.length - h->query.length) - 1;
RC(nxt_app_msg_write_str(task, wmsg, &str));
} else {
NXT_WRITE(&eof);
}
if (h->query.start != NULL) {
RC(nxt_app_msg_write_size(task, wmsg,
h->query.start - h->target.start + 1));
} else {
RC(nxt_app_msg_write_size(task, wmsg, 0));
}
NXT_WRITE(&h->version);
NXT_WRITE(&r->remote);
NXT_WRITE(&r->local);
NXT_WRITE(&h->host);
NXT_WRITE(&h->content_type);
NXT_WRITE(&h->content_length);
nxt_list_each(field, h->fields) {
RC(nxt_app_msg_write_prefixed_upcase(task, wmsg, &prefix,
field->name, field->name_length));
RC(nxt_app_msg_write(task, wmsg, field->value, field->value_length));
} nxt_list_loop;
/* end-of-headers mark */
NXT_WRITE(&eof);
RC(nxt_app_msg_write_size(task, wmsg, r->body.preread_size));
for (b = r->body.buf; b != NULL; b = b->next) {
RC(nxt_app_msg_write_raw(task, wmsg, b->mem.pos,
nxt_buf_mem_used_size(&b->mem)));
}
#undef NXT_WRITE
#undef RC
return NXT_OK;
fail:
return NXT_ERROR;
return out;
}