Coverage Report

Created: 2026-05-04 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/unit/src/nxt_controller.c
Line
Count
Source
1
2
/*
3
 * Copyright (C) Igor Sysoev
4
 * Copyright (C) Valentin V. Bartenev
5
 * Copyright (C) NGINX, Inc.
6
 */
7
8
#include <nxt_main.h>
9
#include <nxt_runtime.h>
10
#include <nxt_main_process.h>
11
#include <nxt_conf.h>
12
#include <nxt_status.h>
13
#include <nxt_cert.h>
14
#include <nxt_script.h>
15
16
17
typedef struct {
18
    nxt_conf_value_t  *root;
19
    nxt_mp_t          *pool;
20
} nxt_controller_conf_t;
21
22
23
typedef struct {
24
    nxt_http_request_parse_t  parser;
25
    size_t                    length;
26
    nxt_controller_conf_t     conf;
27
    nxt_conn_t                *conn;
28
    nxt_queue_link_t          link;
29
} nxt_controller_request_t;
30
31
32
typedef struct {
33
    nxt_uint_t        status;
34
    nxt_conf_value_t  *conf;
35
36
    u_char            *title;
37
    nxt_str_t         detail;
38
    ssize_t           offset;
39
    nxt_uint_t        line;
40
    nxt_uint_t        column;
41
} nxt_controller_response_t;
42
43
44
static nxt_int_t nxt_controller_prefork(nxt_task_t *task,
45
    nxt_process_t *process, nxt_mp_t *mp);
46
static nxt_int_t nxt_controller_file_read(nxt_task_t *task, const char *name,
47
    nxt_str_t *str, nxt_mp_t *mp);
48
static nxt_int_t nxt_controller_start(nxt_task_t *task,
49
    nxt_process_data_t *data);
50
static void nxt_controller_process_new_port_handler(nxt_task_t *task,
51
    nxt_port_recv_msg_t *msg);
52
static void nxt_controller_send_current_conf(nxt_task_t *task);
53
static void nxt_controller_router_ready_handler(nxt_task_t *task,
54
    nxt_port_recv_msg_t *msg);
55
static void nxt_controller_remove_pid_handler(nxt_task_t *task,
56
    nxt_port_recv_msg_t *msg);
57
static nxt_int_t nxt_controller_conf_default(void);
58
static void nxt_controller_conf_init_handler(nxt_task_t *task,
59
    nxt_port_recv_msg_t *msg, void *data);
60
static void nxt_controller_flush_requests(nxt_task_t *task);
61
static nxt_int_t nxt_controller_conf_send(nxt_task_t *task, nxt_mp_t *mp,
62
    nxt_conf_value_t *conf, nxt_port_rpc_handler_t handler, void *data);
63
64
static void nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data);
65
static void nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data);
66
static nxt_msec_t nxt_controller_conn_timeout_value(nxt_conn_t *c,
67
    uintptr_t data);
68
static void nxt_controller_conn_read_error(nxt_task_t *task, void *obj,
69
    void *data);
70
static void nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj,
71
    void *data);
72
static void nxt_controller_conn_body_read(nxt_task_t *task, void *obj,
73
    void *data);
74
static void nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data);
75
static void nxt_controller_conn_write_error(nxt_task_t *task, void *obj,
76
    void *data);
77
static void nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj,
78
    void *data);
79
static void nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data);
80
static void nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data);
81
82
static nxt_int_t nxt_controller_request_content_length(void *ctx,
83
    nxt_http_field_t *field, uintptr_t data);
84
85
static void nxt_controller_process_request(nxt_task_t *task,
86
    nxt_controller_request_t *req);
87
static void nxt_controller_process_config(nxt_task_t *task,
88
    nxt_controller_request_t *req, nxt_str_t *path);
89
static nxt_bool_t nxt_controller_check_postpone_request(nxt_task_t *task);
90
static void nxt_controller_process_status(nxt_task_t *task,
91
    nxt_controller_request_t *req);
92
static void nxt_controller_status_handler(nxt_task_t *task,
93
    nxt_port_recv_msg_t *msg, void *data);
94
static void nxt_controller_status_response(nxt_task_t *task,
95
    nxt_controller_request_t *req, nxt_str_t *path);
96
#if (NXT_TLS)
97
static void nxt_controller_process_cert(nxt_task_t *task,
98
    nxt_controller_request_t *req, nxt_str_t *path);
99
static void nxt_controller_process_cert_save(nxt_task_t *task,
100
    nxt_port_recv_msg_t *msg, void *data);
101
static nxt_bool_t nxt_controller_cert_in_use(nxt_str_t *name);
102
static void nxt_controller_cert_cleanup(nxt_task_t *task, void *obj,
103
    void *data);
104
#endif
105
#if (NXT_HAVE_NJS)
106
static void nxt_controller_process_script(nxt_task_t *task,
107
    nxt_controller_request_t *req, nxt_str_t *path);
108
static void nxt_controller_process_script_save(nxt_task_t *task,
109
    nxt_port_recv_msg_t *msg, void *data);
110
static nxt_bool_t nxt_controller_script_in_use(nxt_str_t *name);
111
static void nxt_controller_script_cleanup(nxt_task_t *task, void *obj,
112
    void *data);
113
#endif
114
static void nxt_controller_process_control(nxt_task_t *task,
115
    nxt_controller_request_t *req, nxt_str_t *path);
116
static void nxt_controller_app_restart_handler(nxt_task_t *task,
117
    nxt_port_recv_msg_t *msg, void *data);
118
static void nxt_controller_conf_handler(nxt_task_t *task,
119
    nxt_port_recv_msg_t *msg, void *data);
120
static void nxt_controller_conf_store(nxt_task_t *task,
121
    nxt_conf_value_t *conf);
122
static void nxt_controller_response(nxt_task_t *task,
123
    nxt_controller_request_t *req, nxt_controller_response_t *resp);
124
static u_char *nxt_controller_date(u_char *buf, nxt_realtime_t *now,
125
    struct tm *tm, size_t size, const char *format);
126
127
128
static nxt_http_field_proc_t  nxt_controller_request_fields[] = {
129
    { nxt_string("Content-Length"),
130
      &nxt_controller_request_content_length, 0 },
131
};
132
133
static nxt_lvlhsh_t            nxt_controller_fields_hash;
134
135
static nxt_uint_t              nxt_controller_listening;
136
static nxt_uint_t              nxt_controller_router_ready;
137
static nxt_controller_conf_t   nxt_controller_conf;
138
static nxt_queue_t             nxt_controller_waiting_requests;
139
static nxt_bool_t              nxt_controller_waiting_init_conf;
140
static nxt_conf_value_t        *nxt_controller_status;
141
142
143
static const nxt_event_conn_state_t  nxt_controller_conn_read_state;
144
static const nxt_event_conn_state_t  nxt_controller_conn_body_read_state;
145
static const nxt_event_conn_state_t  nxt_controller_conn_write_state;
146
static const nxt_event_conn_state_t  nxt_controller_conn_close_state;
147
148
149
static const nxt_port_handlers_t  nxt_controller_process_port_handlers = {
150
    .quit           = nxt_signal_quit_handler,
151
    .new_port       = nxt_controller_process_new_port_handler,
152
    .change_file    = nxt_port_change_log_file_handler,
153
    .mmap           = nxt_port_mmap_handler,
154
    .process_ready  = nxt_controller_router_ready_handler,
155
    .data           = nxt_port_data_handler,
156
    .remove_pid     = nxt_controller_remove_pid_handler,
157
    .rpc_ready      = nxt_port_rpc_handler,
158
    .rpc_error      = nxt_port_rpc_handler,
159
};
160
161
162
const nxt_process_init_t  nxt_controller_process = {
163
    .name           = "controller",
164
    .type           = NXT_PROCESS_CONTROLLER,
165
    .prefork        = nxt_controller_prefork,
166
    .restart        = 1,
167
    .setup          = nxt_process_core_setup,
168
    .start          = nxt_controller_start,
169
    .port_handlers  = &nxt_controller_process_port_handlers,
170
    .signals        = nxt_process_signals,
171
};
172
173
174
static nxt_int_t
175
nxt_controller_prefork(nxt_task_t *task, nxt_process_t *process, nxt_mp_t *mp)
176
0
{
177
0
    nxt_str_t              ver;
178
0
    nxt_int_t              ret, num;
179
0
    nxt_runtime_t          *rt;
180
0
    nxt_controller_init_t  ctrl_init;
181
182
0
    nxt_log(task, NXT_LOG_INFO, "controller started");
183
184
0
    rt = task->thread->runtime;
185
186
0
    nxt_memzero(&ctrl_init, sizeof(nxt_controller_init_t));
187
188
    /*
189
     * Since configuration version has only been introduced in 1.26,
190
     * set the default version to 1.25.
191
    */
192
0
    nxt_conf_ver = 12500;
193
194
0
    ret = nxt_controller_file_read(task, rt->conf, &ctrl_init.conf, mp);
195
0
    if (nxt_slow_path(ret == NXT_ERROR)) {
196
0
        return NXT_ERROR;
197
0
    }
198
199
0
    if (ret == NXT_OK) {
200
0
        ret = nxt_controller_file_read(task, rt->ver, &ver, mp);
201
0
        if (nxt_slow_path(ret == NXT_ERROR)) {
202
0
            return NXT_ERROR;
203
0
        }
204
205
0
        if (ret == NXT_OK) {
206
0
            num = nxt_int_parse(ver.start, ver.length);
207
208
0
            if (nxt_slow_path(num < 0)) {
209
0
                nxt_alert(task, "failed to restore previous configuration: "
210
0
                          "invalid version string \"%V\"", &ver);
211
212
0
                nxt_str_null(&ctrl_init.conf);
213
214
0
            } else {
215
0
                nxt_conf_ver = num;
216
0
            }
217
0
        }
218
0
    }
219
220
#if (NXT_TLS)
221
    ctrl_init.certs = nxt_cert_store_load(task, mp);
222
223
    nxt_mp_cleanup(mp, nxt_controller_cert_cleanup, task, ctrl_init.certs, rt);
224
#endif
225
226
#if (NXT_HAVE_NJS)
227
    ctrl_init.scripts = nxt_script_store_load(task, mp);
228
229
    nxt_mp_cleanup(mp, nxt_controller_script_cleanup, task, ctrl_init.scripts,
230
                   rt);
231
#endif
232
233
0
    process->data.controller = ctrl_init;
234
235
0
    return NXT_OK;
236
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_prefork
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_prefork
237
238
239
static nxt_int_t
240
nxt_controller_file_read(nxt_task_t *task, const char *name, nxt_str_t *str,
241
    nxt_mp_t *mp)
242
0
{
243
0
    ssize_t          n;
244
0
    nxt_int_t        ret;
245
0
    nxt_file_t       file;
246
0
    nxt_file_info_t  fi;
247
248
0
    nxt_memzero(&file, sizeof(nxt_file_t));
249
250
0
    file.name = (nxt_file_name_t *) name;
251
252
0
    ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
253
254
0
    if (ret == NXT_OK) {
255
0
        ret = nxt_file_info(&file, &fi);
256
0
        if (nxt_slow_path(ret != NXT_OK)) {
257
0
            goto fail;
258
0
        }
259
260
0
        if (nxt_fast_path(nxt_is_file(&fi))) {
261
0
            str->length = nxt_file_size(&fi);
262
0
            str->start = nxt_mp_nget(mp, str->length);
263
0
            if (nxt_slow_path(str->start == NULL)) {
264
0
                goto fail;
265
0
            }
266
267
0
            n = nxt_file_read(&file, str->start, str->length, 0);
268
0
            if (nxt_slow_path(n != (ssize_t) str->length)) {
269
0
                goto fail;
270
0
            }
271
272
0
            nxt_file_close(task, &file);
273
274
0
            return NXT_OK;
275
0
        }
276
277
0
        nxt_file_close(task, &file);
278
0
    }
279
280
0
    return NXT_DECLINED;
281
282
0
fail:
283
284
0
    nxt_file_close(task, &file);
285
286
0
    return NXT_ERROR;
287
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_file_read
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_file_read
288
289
290
#if (NXT_TLS)
291
292
static void
293
nxt_controller_cert_cleanup(nxt_task_t *task, void *obj, void *data)
294
{
295
    pid_t          main_pid;
296
    nxt_array_t    *certs;
297
    nxt_runtime_t  *rt;
298
299
    certs = obj;
300
    rt = data;
301
302
    main_pid = rt->port_by_type[NXT_PROCESS_MAIN]->pid;
303
304
    if (nxt_pid == main_pid && certs != NULL) {
305
        nxt_cert_store_release(certs);
306
    }
307
}
308
309
#endif
310
311
312
static nxt_int_t
313
nxt_controller_start(nxt_task_t *task, nxt_process_data_t *data)
314
0
{
315
0
    nxt_mp_t               *mp;
316
0
    nxt_int_t              ret;
317
0
    nxt_str_t              *json;
318
0
    nxt_conf_value_t       *conf;
319
0
    nxt_conf_validation_t  vldt;
320
0
    nxt_controller_init_t  *init;
321
322
0
    ret = nxt_http_fields_hash(&nxt_controller_fields_hash,
323
0
                               nxt_controller_request_fields,
324
0
                               nxt_nitems(nxt_controller_request_fields));
325
326
0
    if (nxt_slow_path(ret != NXT_OK)) {
327
0
        return NXT_ERROR;
328
0
    }
329
330
0
    nxt_queue_init(&nxt_controller_waiting_requests);
331
332
0
    init = &data->controller;
333
334
#if (NXT_TLS)
335
    if (init->certs != NULL) {
336
        nxt_cert_info_init(task, init->certs);
337
        nxt_cert_store_release(init->certs);
338
    }
339
#endif
340
341
#if (NXT_HAVE_NJS)
342
    if (init->scripts != NULL) {
343
        nxt_script_info_init(task, init->scripts);
344
        nxt_script_store_release(init->scripts);
345
    }
346
#endif
347
348
0
    json = &init->conf;
349
350
0
    if (json->start == NULL) {
351
0
        return NXT_OK;
352
0
    }
353
354
0
    mp = nxt_mp_create(1024, 128, 256, 32);
355
0
    if (nxt_slow_path(mp == NULL)) {
356
0
        return NXT_ERROR;
357
0
    }
358
359
0
    conf = nxt_conf_json_parse_str(mp, json);
360
0
    if (nxt_slow_path(conf == NULL)) {
361
0
        nxt_alert(task, "failed to restore previous configuration: "
362
0
                  "file is corrupted or not enough memory");
363
364
0
        nxt_mp_destroy(mp);
365
0
        return NXT_OK;
366
0
    }
367
368
0
    nxt_memzero(&vldt, sizeof(nxt_conf_validation_t));
369
370
0
    vldt.pool = nxt_mp_create(1024, 128, 256, 32);
371
0
    if (nxt_slow_path(vldt.pool == NULL)) {
372
0
        nxt_mp_destroy(mp);
373
0
        return NXT_ERROR;
374
0
    }
375
376
0
    vldt.conf = conf;
377
0
    vldt.conf_pool = mp;
378
0
    vldt.ver = nxt_conf_ver;
379
380
0
    ret = nxt_conf_validate(&vldt);
381
382
0
    if (nxt_slow_path(ret != NXT_OK)) {
383
384
0
        if (ret == NXT_DECLINED) {
385
0
            nxt_alert(task, "the previous configuration is invalid: %V",
386
0
                      &vldt.error);
387
388
0
            nxt_mp_destroy(vldt.pool);
389
0
            nxt_mp_destroy(mp);
390
391
0
            return NXT_OK;
392
0
        }
393
394
        /* ret == NXT_ERROR */
395
396
0
        return NXT_ERROR;
397
0
    }
398
399
0
    nxt_mp_destroy(vldt.pool);
400
401
0
    nxt_controller_conf.root = conf;
402
0
    nxt_controller_conf.pool = mp;
403
404
0
    return NXT_OK;
405
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_start
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_start
406
407
408
static void
409
nxt_controller_process_new_port_handler(nxt_task_t *task,
410
    nxt_port_recv_msg_t *msg)
411
0
{
412
0
    nxt_port_new_port_handler(task, msg);
413
414
0
    if (msg->u.new_port->type != NXT_PROCESS_ROUTER
415
0
        || !nxt_controller_router_ready)
416
0
    {
417
0
        return;
418
0
    }
419
420
0
    nxt_controller_send_current_conf(task);
421
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_process_new_port_handler
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_process_new_port_handler
422
423
424
static void
425
nxt_controller_send_current_conf(nxt_task_t *task)
426
0
{
427
0
    nxt_int_t         rc;
428
0
    nxt_runtime_t     *rt;
429
0
    nxt_conf_value_t  *conf;
430
431
0
    conf = nxt_controller_conf.root;
432
433
0
    if (conf != NULL) {
434
0
        rc = nxt_controller_conf_send(task, nxt_controller_conf.pool, conf,
435
0
                                      nxt_controller_conf_init_handler, NULL);
436
437
0
        if (nxt_fast_path(rc == NXT_OK)) {
438
0
            nxt_controller_waiting_init_conf = 1;
439
440
0
            return;
441
0
        }
442
443
0
        nxt_mp_destroy(nxt_controller_conf.pool);
444
445
0
        if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) {
446
0
            nxt_abort();
447
0
        }
448
0
    }
449
450
0
    if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) {
451
0
        nxt_abort();
452
0
    }
453
454
0
    rt = task->thread->runtime;
455
456
0
    if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket) == NULL)) {
457
0
        nxt_abort();
458
0
    }
459
460
0
    nxt_controller_listening = 1;
461
462
0
    nxt_controller_flush_requests(task);
463
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_send_current_conf
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_send_current_conf
464
465
466
static void
467
nxt_controller_router_ready_handler(nxt_task_t *task,
468
    nxt_port_recv_msg_t *msg)
469
0
{
470
0
    nxt_port_t     *router_port;
471
0
    nxt_runtime_t  *rt;
472
473
0
    rt = task->thread->runtime;
474
475
0
    router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
476
477
0
    nxt_controller_router_ready = 1;
478
479
0
    if (router_port != NULL) {
480
0
        nxt_controller_send_current_conf(task);
481
0
    }
482
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_router_ready_handler
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_router_ready_handler
483
484
485
static void
486
nxt_controller_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
487
0
{
488
0
    nxt_pid_t      pid;
489
0
    nxt_process_t  *process;
490
0
    nxt_runtime_t  *rt;
491
492
0
    rt = task->thread->runtime;
493
494
0
    nxt_assert(nxt_buf_used_size(msg->buf) == sizeof(pid));
495
496
0
    nxt_memcpy(&pid, msg->buf->mem.pos, sizeof(pid));
497
498
0
    process = nxt_runtime_process_find(rt, pid);
499
0
    if (process != NULL && nxt_process_type(process) == NXT_PROCESS_ROUTER) {
500
0
        nxt_controller_router_ready = 0;
501
0
    }
502
503
0
    nxt_port_remove_pid_handler(task, msg);
504
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_remove_pid_handler
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_remove_pid_handler
505
506
507
static nxt_int_t
508
nxt_controller_conf_default(void)
509
0
{
510
0
    nxt_mp_t          *mp;
511
0
    nxt_conf_value_t  *conf;
512
513
0
    static const nxt_str_t json = nxt_string(
514
0
        "{ \"listeners\": {}, \"routes\": [], \"applications\": {} }"
515
0
    );
516
517
0
    mp = nxt_mp_create(1024, 128, 256, 32);
518
519
0
    if (nxt_slow_path(mp == NULL)) {
520
0
        return NXT_ERROR;
521
0
    }
522
523
0
    conf = nxt_conf_json_parse_str(mp, &json);
524
525
0
    if (nxt_slow_path(conf == NULL)) {
526
0
        return NXT_ERROR;
527
0
    }
528
529
0
    nxt_controller_conf.root = conf;
530
0
    nxt_controller_conf.pool = mp;
531
532
0
    return NXT_OK;
533
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_conf_default
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_conf_default
534
535
536
static void
537
nxt_controller_conf_init_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
538
    void *data)
539
0
{
540
0
    nxt_runtime_t  *rt;
541
542
0
    nxt_controller_waiting_init_conf = 0;
543
544
0
    if (msg->port_msg.type != NXT_PORT_MSG_RPC_READY) {
545
0
        nxt_alert(task, "failed to apply previous configuration");
546
547
0
        nxt_mp_destroy(nxt_controller_conf.pool);
548
549
0
        if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) {
550
0
            nxt_abort();
551
0
        }
552
0
    }
553
554
0
    if (nxt_controller_listening == 0) {
555
0
        rt = task->thread->runtime;
556
557
0
        if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket)
558
0
                          == NULL))
559
0
        {
560
0
            nxt_abort();
561
0
        }
562
563
0
        nxt_controller_listening = 1;
564
0
    }
565
566
0
    nxt_controller_flush_requests(task);
567
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_conf_init_handler
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_conf_init_handler
568
569
570
static void
571
nxt_controller_flush_requests(nxt_task_t *task)
572
0
{
573
0
    nxt_queue_t               queue;
574
0
    nxt_controller_request_t  *req;
575
576
0
    nxt_queue_init(&queue);
577
0
    nxt_queue_add(&queue, &nxt_controller_waiting_requests);
578
579
0
    nxt_queue_init(&nxt_controller_waiting_requests);
580
581
0
    nxt_queue_each(req, &queue, nxt_controller_request_t, link) {
582
0
        nxt_controller_process_request(task, req);
583
0
    } nxt_queue_loop;
584
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_flush_requests
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_flush_requests
585
586
587
static nxt_int_t
588
nxt_controller_conf_send(nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *conf,
589
    nxt_port_rpc_handler_t handler, void *data)
590
0
{
591
0
    void           *mem;
592
0
    u_char         *end;
593
0
    size_t         size;
594
0
    uint32_t       stream;
595
0
    nxt_fd_t       fd;
596
0
    nxt_int_t      rc;
597
0
    nxt_buf_t      *b;
598
0
    nxt_port_t     *router_port, *controller_port;
599
0
    nxt_runtime_t  *rt;
600
601
0
    rt = task->thread->runtime;
602
603
0
    router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
604
605
0
    nxt_assert(router_port != NULL);
606
0
    nxt_assert(nxt_controller_router_ready);
607
608
0
    controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
609
610
0
    size = nxt_conf_json_length(conf, NULL);
611
612
0
    b = nxt_buf_mem_alloc(mp, sizeof(size_t), 0);
613
0
    if (nxt_slow_path(b == NULL)) {
614
0
        return NXT_ERROR;
615
0
    }
616
617
0
    fd = nxt_shm_open(task, size);
618
0
    if (nxt_slow_path(fd == -1)) {
619
0
        return NXT_ERROR;
620
0
    }
621
622
0
    mem = nxt_mem_mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
623
0
    if (nxt_slow_path(mem == MAP_FAILED)) {
624
0
        goto fail;
625
0
    }
626
627
0
    end = nxt_conf_json_print(mem, conf, NULL);
628
629
0
    nxt_mem_munmap(mem, size);
630
631
0
    size = end - (u_char *) mem;
632
633
0
    b->mem.free = nxt_cpymem(b->mem.pos, &size, sizeof(size_t));
634
635
0
    stream = nxt_port_rpc_register_handler(task, controller_port,
636
0
                                           handler, handler,
637
0
                                           router_port->pid, data);
638
0
    if (nxt_slow_path(stream == 0)) {
639
0
        goto fail;
640
0
    }
641
642
0
    rc = nxt_port_socket_write(task, router_port,
643
0
                               NXT_PORT_MSG_DATA_LAST | NXT_PORT_MSG_CLOSE_FD,
644
0
                               fd, stream, controller_port->id, b);
645
646
0
    if (nxt_slow_path(rc != NXT_OK)) {
647
0
        nxt_port_rpc_cancel(task, controller_port, stream);
648
649
0
        goto fail;
650
0
    }
651
652
0
    return NXT_OK;
653
654
0
fail:
655
656
0
    nxt_fd_close(fd);
657
658
0
    return NXT_ERROR;
659
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_conf_send
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_conf_send
660
661
662
nxt_int_t
663
nxt_runtime_controller_socket(nxt_task_t *task, nxt_runtime_t *rt)
664
0
{
665
0
    nxt_listen_socket_t  *ls;
666
667
0
    ls = nxt_mp_alloc(rt->mem_pool, sizeof(nxt_listen_socket_t));
668
0
    if (ls == NULL) {
669
0
        return NXT_ERROR;
670
0
    }
671
672
0
    ls->sockaddr = rt->controller_listen;
673
674
0
    nxt_listen_socket_remote_size(ls);
675
676
0
    ls->socket = -1;
677
0
    ls->backlog = NXT_LISTEN_BACKLOG;
678
0
    ls->read_after_accept = 1;
679
0
    ls->flags = NXT_NONBLOCK;
680
681
#if 0
682
    /* STUB */
683
    wq = nxt_mp_zget(cf->mem_pool, sizeof(nxt_work_queue_t));
684
    if (wq == NULL) {
685
        return NXT_ERROR;
686
    }
687
    nxt_work_queue_name(wq, "listen");
688
    /**/
689
690
    ls->work_queue = wq;
691
#endif
692
0
    ls->handler = nxt_controller_conn_init;
693
694
0
#if (NXT_HAVE_UNIX_DOMAIN)
695
0
    if (ls->sockaddr->u.sockaddr.sa_family == AF_UNIX) {
696
0
        const char *path = ls->sockaddr->u.sockaddr_un.sun_path;
697
698
0
        nxt_fs_mkdir_p_dirname((const u_char *) path, 0755);
699
0
    }
700
0
#endif
701
702
0
    if (nxt_listen_socket_create(task, rt->mem_pool, ls) != NXT_OK) {
703
0
        return NXT_ERROR;
704
0
    }
705
706
0
    rt->controller_socket = ls;
707
708
0
    return NXT_OK;
709
0
}
710
711
712
static void
713
nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data)
714
0
{
715
0
    nxt_buf_t                 *b;
716
0
    nxt_conn_t                *c;
717
0
    nxt_event_engine_t        *engine;
718
0
    nxt_controller_request_t  *r;
719
720
0
    c = obj;
721
722
0
    nxt_debug(task, "controller conn init fd:%d", c->socket.fd);
723
724
0
    r = nxt_mp_zget(c->mem_pool, sizeof(nxt_controller_request_t));
725
0
    if (nxt_slow_path(r == NULL)) {
726
0
        nxt_controller_conn_free(task, c, NULL);
727
0
        return;
728
0
    }
729
730
0
    r->conn = c;
731
732
0
    if (nxt_slow_path(nxt_http_parse_request_init(&r->parser, c->mem_pool)
733
0
                      != NXT_OK))
734
0
    {
735
0
        nxt_controller_conn_free(task, c, NULL);
736
0
        return;
737
0
    }
738
739
0
    r->parser.encoded_slashes = 1;
740
741
0
    b = nxt_buf_mem_alloc(c->mem_pool, 1024, 0);
742
0
    if (nxt_slow_path(b == NULL)) {
743
0
        nxt_controller_conn_free(task, c, NULL);
744
0
        return;
745
0
    }
746
747
0
    c->read = b;
748
0
    c->socket.data = r;
749
0
    c->socket.read_ready = 1;
750
0
    c->read_state = &nxt_controller_conn_read_state;
751
752
0
    engine = task->thread->engine;
753
0
    c->read_work_queue = &engine->read_work_queue;
754
0
    c->write_work_queue = &engine->write_work_queue;
755
756
0
    nxt_conn_read(engine, c);
757
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_conn_init
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_conn_init
758
759
760
static const nxt_event_conn_state_t  nxt_controller_conn_read_state
761
    nxt_aligned(64) =
762
{
763
    .ready_handler = nxt_controller_conn_read,
764
    .close_handler = nxt_controller_conn_close,
765
    .error_handler = nxt_controller_conn_read_error,
766
767
    .timer_handler = nxt_controller_conn_read_timeout,
768
    .timer_value = nxt_controller_conn_timeout_value,
769
    .timer_data = 300 * 1000,
770
};
771
772
773
static void
774
nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data)
775
0
{
776
0
    size_t                    preread;
777
0
    nxt_buf_t                 *b;
778
0
    nxt_int_t                 rc;
779
0
    nxt_conn_t                *c;
780
0
    nxt_controller_request_t  *r;
781
782
0
    c = obj;
783
0
    r = data;
784
785
0
    nxt_debug(task, "controller conn read");
786
787
0
    nxt_queue_remove(&c->link);
788
0
    nxt_queue_self(&c->link);
789
790
0
    b = c->read;
791
792
0
    rc = nxt_http_parse_request(&r->parser, &b->mem);
793
794
0
    if (nxt_slow_path(rc != NXT_DONE)) {
795
796
0
        if (rc == NXT_AGAIN) {
797
0
            if (nxt_buf_mem_free_size(&b->mem) == 0) {
798
0
                nxt_log(task, NXT_LOG_ERR, "too long request headers");
799
0
                nxt_controller_conn_close(task, c, r);
800
0
                return;
801
0
            }
802
803
0
            nxt_conn_read(task->thread->engine, c);
804
0
            return;
805
0
        }
806
807
        /* rc == NXT_ERROR */
808
809
0
        nxt_log(task, NXT_LOG_ERR, "parsing error");
810
811
0
        nxt_controller_conn_close(task, c, r);
812
0
        return;
813
0
    }
814
815
0
    rc = nxt_http_fields_process(r->parser.fields, &nxt_controller_fields_hash,
816
0
                                 r);
817
818
0
    if (nxt_slow_path(rc != NXT_OK)) {
819
0
        nxt_controller_conn_close(task, c, r);
820
0
        return;
821
0
    }
822
823
0
    preread = nxt_buf_mem_used_size(&b->mem);
824
825
0
    nxt_debug(task, "controller request header parsing complete, "
826
0
                    "body length: %uz, preread: %uz",
827
0
                    r->length, preread);
828
829
0
    if (preread >= r->length) {
830
0
        nxt_controller_process_request(task, r);
831
0
        return;
832
0
    }
833
834
0
    if (r->length - preread > (size_t) nxt_buf_mem_free_size(&b->mem)) {
835
0
        b = nxt_buf_mem_alloc(c->mem_pool, r->length, 0);
836
0
        if (nxt_slow_path(b == NULL)) {
837
0
            nxt_controller_conn_free(task, c, NULL);
838
0
            return;
839
0
        }
840
841
0
        b->mem.free = nxt_cpymem(b->mem.free, c->read->mem.pos, preread);
842
843
0
        c->read = b;
844
0
    }
845
846
0
    c->read_state = &nxt_controller_conn_body_read_state;
847
848
0
    nxt_conn_read(task->thread->engine, c);
849
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_conn_read
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_conn_read
850
851
852
static nxt_msec_t
853
nxt_controller_conn_timeout_value(nxt_conn_t *c, uintptr_t data)
854
0
{
855
0
    return (nxt_msec_t) data;
856
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_conn_timeout_value
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_conn_timeout_value
857
858
859
static void
860
nxt_controller_conn_read_error(nxt_task_t *task, void *obj, void *data)
861
0
{
862
0
    nxt_conn_t  *c;
863
864
0
    c = obj;
865
866
0
    nxt_debug(task, "controller conn read error");
867
868
0
    nxt_controller_conn_close(task, c, data);
869
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_conn_read_error
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_conn_read_error
870
871
872
static void
873
nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj, void *data)
874
0
{
875
0
    nxt_timer_t  *timer;
876
0
    nxt_conn_t   *c;
877
878
0
    timer = obj;
879
880
0
    c = nxt_read_timer_conn(timer);
881
0
    c->socket.timedout = 1;
882
0
    c->socket.closed = 1;
883
884
0
    nxt_debug(task, "controller conn read timeout");
885
886
0
    nxt_controller_conn_close(task, c, data);
887
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_conn_read_timeout
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_conn_read_timeout
888
889
890
static const nxt_event_conn_state_t  nxt_controller_conn_body_read_state
891
    nxt_aligned(64) =
892
{
893
    .ready_handler = nxt_controller_conn_body_read,
894
    .close_handler = nxt_controller_conn_close,
895
    .error_handler = nxt_controller_conn_read_error,
896
897
    .timer_handler = nxt_controller_conn_read_timeout,
898
    .timer_value = nxt_controller_conn_timeout_value,
899
    .timer_data = 60 * 1000,
900
    .timer_autoreset = 1,
901
};
902
903
904
static void
905
nxt_controller_conn_body_read(nxt_task_t *task, void *obj, void *data)
906
0
{
907
0
    size_t                    read;
908
0
    nxt_buf_t                 *b;
909
0
    nxt_conn_t                *c;
910
0
    nxt_controller_request_t  *r;
911
912
0
    c = obj;
913
0
    r = data;
914
0
    b = c->read;
915
916
0
    read = nxt_buf_mem_used_size(&b->mem);
917
918
0
    nxt_debug(task, "controller conn body read: %uz of %uz",
919
0
              read, r->length);
920
921
0
    if (read >= r->length) {
922
0
        nxt_controller_process_request(task, r);
923
0
        return;
924
0
    }
925
926
0
    nxt_conn_read(task->thread->engine, c);
927
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_conn_body_read
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_conn_body_read
928
929
930
static const nxt_event_conn_state_t  nxt_controller_conn_write_state
931
    nxt_aligned(64) =
932
{
933
    .ready_handler = nxt_controller_conn_write,
934
    .error_handler = nxt_controller_conn_write_error,
935
936
    .timer_handler = nxt_controller_conn_write_timeout,
937
    .timer_value = nxt_controller_conn_timeout_value,
938
    .timer_data = 60 * 1000,
939
    .timer_autoreset = 1,
940
};
941
942
943
static void
944
nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data)
945
0
{
946
0
    nxt_buf_t   *b;
947
0
    nxt_conn_t  *c;
948
949
0
    c = obj;
950
951
0
    nxt_debug(task, "controller conn write");
952
953
0
    b = c->write;
954
955
0
    if (b->mem.pos != b->mem.free) {
956
0
        nxt_conn_write(task->thread->engine, c);
957
0
        return;
958
0
    }
959
960
0
    nxt_debug(task, "controller conn write complete");
961
962
0
    nxt_controller_conn_close(task, c, data);
963
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_conn_write
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_conn_write
964
965
966
static void
967
nxt_controller_conn_write_error(nxt_task_t *task, void *obj, void *data)
968
0
{
969
0
    nxt_conn_t  *c;
970
971
0
    c = obj;
972
973
0
    nxt_debug(task, "controller conn write error");
974
975
0
    nxt_controller_conn_close(task, c, data);
976
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_conn_write_error
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_conn_write_error
977
978
979
static void
980
nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj, void *data)
981
0
{
982
0
    nxt_conn_t   *c;
983
0
    nxt_timer_t  *timer;
984
985
0
    timer = obj;
986
987
0
    c = nxt_write_timer_conn(timer);
988
0
    c->socket.timedout = 1;
989
0
    c->socket.closed = 1;
990
991
0
    nxt_debug(task, "controller conn write timeout");
992
993
0
    nxt_controller_conn_close(task, c, data);
994
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_conn_write_timeout
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_conn_write_timeout
995
996
997
static const nxt_event_conn_state_t  nxt_controller_conn_close_state
998
    nxt_aligned(64) =
999
{
1000
    .ready_handler = nxt_controller_conn_free,
1001
};
1002
1003
1004
static void
1005
nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data)
1006
0
{
1007
0
    nxt_conn_t  *c;
1008
1009
0
    c = obj;
1010
1011
0
    nxt_debug(task, "controller conn close");
1012
1013
0
    nxt_queue_remove(&c->link);
1014
1015
0
    c->write_state = &nxt_controller_conn_close_state;
1016
1017
0
    nxt_conn_close(task->thread->engine, c);
1018
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_conn_close
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_conn_close
1019
1020
1021
static void
1022
nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data)
1023
0
{
1024
0
    nxt_conn_t  *c;
1025
1026
0
    c = obj;
1027
1028
0
    nxt_debug(task, "controller conn free");
1029
1030
0
    nxt_sockaddr_cache_free(task->thread->engine, c);
1031
1032
0
    nxt_conn_free(task, c);
1033
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_conn_free
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_conn_free
1034
1035
1036
static nxt_int_t
1037
nxt_controller_request_content_length(void *ctx, nxt_http_field_t *field,
1038
    uintptr_t data)
1039
471
{
1040
471
    off_t                     length;
1041
471
    nxt_controller_request_t  *r;
1042
1043
471
    r = ctx;
1044
1045
471
    length = nxt_off_t_parse(field->value, field->value_length);
1046
1047
471
    if (nxt_fast_path(length >= 0)) {
1048
1049
375
        if (nxt_slow_path(length > NXT_SIZE_T_MAX)) {
1050
0
            nxt_log_error(NXT_LOG_ERR, &r->conn->log,
1051
0
                          "Content-Length is too big");
1052
0
            return NXT_ERROR;
1053
0
        }
1054
1055
375
        r->length = length;
1056
375
        return NXT_OK;
1057
375
    }
1058
1059
96
    nxt_log_error(NXT_LOG_ERR, &r->conn->log, "Content-Length is invalid");
1060
1061
96
    return NXT_ERROR;
1062
471
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_request_content_length
nxt_http_controller_fuzz.c:nxt_controller_request_content_length
Line
Count
Source
1039
471
{
1040
471
    off_t                     length;
1041
471
    nxt_controller_request_t  *r;
1042
1043
471
    r = ctx;
1044
1045
471
    length = nxt_off_t_parse(field->value, field->value_length);
1046
1047
471
    if (nxt_fast_path(length >= 0)) {
1048
1049
375
        if (nxt_slow_path(length > NXT_SIZE_T_MAX)) {
1050
0
            nxt_log_error(NXT_LOG_ERR, &r->conn->log,
1051
0
                          "Content-Length is too big");
1052
0
            return NXT_ERROR;
1053
0
        }
1054
1055
375
        r->length = length;
1056
375
        return NXT_OK;
1057
375
    }
1058
1059
96
    nxt_log_error(NXT_LOG_ERR, &r->conn->log, "Content-Length is invalid");
1060
1061
96
    return NXT_ERROR;
1062
471
}
1063
1064
1065
static void
1066
nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req)
1067
0
{
1068
0
    uint32_t                   i, count;
1069
0
    nxt_str_t                  path;
1070
0
    nxt_conn_t                 *c;
1071
0
    nxt_conf_value_t           *value;
1072
0
    nxt_controller_response_t  resp;
1073
#if (NXT_TLS)
1074
    nxt_conf_value_t           *certs;
1075
#endif
1076
#if (NXT_HAVE_NJS)
1077
    nxt_conf_value_t           *scripts;
1078
#endif
1079
1080
#if (NXT_TLS)
1081
    static const nxt_str_t certificates = nxt_string("certificates");
1082
#endif
1083
1084
#if (NXT_HAVE_NJS)
1085
    static const nxt_str_t scripts_str = nxt_string("js_modules");
1086
#endif
1087
1088
0
    static const nxt_str_t config = nxt_string("config");
1089
0
    static const nxt_str_t status = nxt_string("status");
1090
1091
0
    c = req->conn;
1092
0
    path = req->parser.path;
1093
1094
0
    if (path.length > 1 && path.start[path.length - 1] == '/') {
1095
0
        path.length--;
1096
0
    }
1097
1098
0
    if (nxt_str_start(&path, "/config", 7)
1099
0
        && (path.length == 7 || path.start[7] == '/'))
1100
0
    {
1101
0
        if (path.length == 7) {
1102
0
            path.length = 1;
1103
1104
0
        } else {
1105
0
            path.length -= 7;
1106
0
            path.start += 7;
1107
0
        }
1108
1109
0
        nxt_controller_process_config(task, req, &path);
1110
0
        return;
1111
0
    }
1112
1113
0
    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1114
1115
0
    if (nxt_str_start(&path, "/status", 7)
1116
0
        && (path.length == 7 || path.start[7] == '/'))
1117
0
    {
1118
0
        if (!nxt_str_eq(&req->parser.method, "GET", 3)) {
1119
0
            goto invalid_method;
1120
0
        }
1121
1122
0
        if (nxt_controller_status == NULL) {
1123
0
            nxt_controller_process_status(task, req);
1124
0
            return;
1125
0
        }
1126
1127
0
        if (path.length == 7) {
1128
0
            path.length = 1;
1129
1130
0
        } else {
1131
0
            path.length -= 7;
1132
0
            path.start += 7;
1133
0
        }
1134
1135
0
        nxt_controller_status_response(task, req, &path);
1136
0
        return;
1137
0
    }
1138
1139
#if (NXT_TLS)
1140
1141
    if (nxt_str_start(&path, "/certificates", 13)
1142
        && (path.length == 13 || path.start[13] == '/'))
1143
    {
1144
        if (path.length == 13) {
1145
            path.length = 1;
1146
1147
        } else {
1148
            path.length -= 13;
1149
            path.start += 13;
1150
        }
1151
1152
        nxt_controller_process_cert(task, req, &path);
1153
        return;
1154
    }
1155
1156
#endif
1157
1158
#if (NXT_HAVE_NJS)
1159
1160
    if (nxt_str_start(&path, "/js_modules", 11)
1161
        && (path.length == 11 || path.start[11] == '/'))
1162
    {
1163
        if (path.length == 11) {
1164
            path.length = 1;
1165
1166
        } else {
1167
            path.length -= 11;
1168
            path.start += 11;
1169
        }
1170
1171
        nxt_controller_process_script(task, req, &path);
1172
        return;
1173
    }
1174
1175
#endif
1176
1177
0
    if (nxt_str_start(&path, "/control/", 9)) {
1178
0
        path.length -= 9;
1179
0
        path.start += 9;
1180
1181
0
        nxt_controller_process_control(task, req, &path);
1182
0
        return;
1183
0
    }
1184
1185
0
    if (path.length == 1 && path.start[0] == '/') {
1186
1187
0
        if (!nxt_str_eq(&req->parser.method, "GET", 3)) {
1188
0
            goto invalid_method;
1189
0
        }
1190
1191
0
        if (nxt_controller_status == NULL) {
1192
0
            nxt_controller_process_status(task, req);
1193
0
            return;
1194
0
        }
1195
1196
0
        count = 2;
1197
#if (NXT_TLS)
1198
        count++;
1199
#endif
1200
#if (NXT_HAVE_NJS)
1201
        count++;
1202
#endif
1203
1204
0
        value = nxt_conf_create_object(c->mem_pool, count);
1205
0
        if (nxt_slow_path(value == NULL)) {
1206
0
            goto alloc_fail;
1207
0
        }
1208
1209
0
        i = 0;
1210
1211
#if (NXT_TLS)
1212
        certs = nxt_cert_info_get_all(c->mem_pool);
1213
        if (nxt_slow_path(certs == NULL)) {
1214
            goto alloc_fail;
1215
        }
1216
1217
        nxt_conf_set_member(value, &certificates, certs, i++);
1218
#endif
1219
1220
#if (NXT_HAVE_NJS)
1221
        scripts = nxt_script_info_get_all(c->mem_pool);
1222
        if (nxt_slow_path(scripts == NULL)) {
1223
            goto alloc_fail;
1224
        }
1225
1226
        nxt_conf_set_member(value, &scripts_str, scripts, i++);
1227
#endif
1228
1229
0
        nxt_conf_set_member(value, &config, nxt_controller_conf.root, i++);
1230
0
        nxt_conf_set_member(value, &status, nxt_controller_status, i);
1231
1232
0
        resp.status = 200;
1233
0
        resp.conf = value;
1234
1235
0
        nxt_controller_response(task, req, &resp);
1236
0
        return;
1237
0
    }
1238
1239
0
    resp.status = 404;
1240
0
    resp.title = (u_char *) "Value doesn't exist.";
1241
0
    resp.offset = -1;
1242
1243
0
    nxt_controller_response(task, req, &resp);
1244
0
    return;
1245
1246
0
invalid_method:
1247
1248
0
    resp.status = 405;
1249
0
    resp.title = (u_char *) "Invalid method.";
1250
0
    resp.offset = -1;
1251
1252
0
    nxt_controller_response(task, req, &resp);
1253
0
    return;
1254
1255
0
alloc_fail:
1256
1257
0
    resp.status = 500;
1258
0
    resp.title = (u_char *) "Memory allocation failed.";
1259
0
    resp.offset = -1;
1260
1261
0
    nxt_controller_response(task, req, &resp);
1262
0
    return;
1263
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_process_request
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_process_request
1264
1265
1266
static void
1267
nxt_controller_process_config(nxt_task_t *task, nxt_controller_request_t *req,
1268
    nxt_str_t *path)
1269
0
{
1270
0
    nxt_mp_t                   *mp;
1271
0
    nxt_int_t                  rc;
1272
0
    nxt_conn_t                 *c;
1273
0
    nxt_bool_t                 post;
1274
0
    nxt_buf_mem_t              *mbuf;
1275
0
    nxt_conf_op_t              *ops;
1276
0
    nxt_conf_value_t           *value;
1277
0
    nxt_conf_validation_t      vldt;
1278
0
    nxt_conf_json_error_t      error;
1279
0
    nxt_controller_response_t  resp;
1280
1281
0
    static const nxt_str_t empty_obj = nxt_string("{}");
1282
1283
0
    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1284
1285
0
    c = req->conn;
1286
1287
0
    if (nxt_str_eq(&req->parser.method, "GET", 3)) {
1288
1289
0
        value = nxt_conf_get_path(nxt_controller_conf.root, path);
1290
1291
0
        if (value == NULL) {
1292
0
            goto not_found;
1293
0
        }
1294
1295
0
        resp.status = 200;
1296
0
        resp.conf = value;
1297
1298
0
        nxt_controller_response(task, req, &resp);
1299
0
        return;
1300
0
    }
1301
1302
0
    if (nxt_str_eq(&req->parser.method, "POST", 4)) {
1303
0
        if (path->length == 1) {
1304
0
            goto not_allowed;
1305
0
        }
1306
1307
0
        post = 1;
1308
1309
0
    } else {
1310
0
        post = 0;
1311
0
    }
1312
1313
0
    if (post || nxt_str_eq(&req->parser.method, "PUT", 3)) {
1314
1315
0
        if (nxt_controller_check_postpone_request(task)) {
1316
0
            nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link);
1317
0
            return;
1318
0
        }
1319
1320
0
        mp = nxt_mp_create(1024, 128, 256, 32);
1321
1322
0
        if (nxt_slow_path(mp == NULL)) {
1323
0
            goto alloc_fail;
1324
0
        }
1325
1326
0
        mbuf = &c->read->mem;
1327
1328
0
        nxt_memzero(&error, sizeof(nxt_conf_json_error_t));
1329
1330
        /* Skip UTF-8 BOM. */
1331
0
        if (nxt_buf_mem_used_size(mbuf) >= 3
1332
0
            && memcmp(mbuf->pos, "\xEF\xBB\xBF", 3) == 0)
1333
0
        {
1334
0
            mbuf->pos += 3;
1335
0
        }
1336
1337
0
        value = nxt_conf_json_parse(mp, mbuf->pos, mbuf->free, &error);
1338
1339
0
        if (value == NULL) {
1340
0
            nxt_mp_destroy(mp);
1341
1342
0
            if (error.pos == NULL) {
1343
0
                goto alloc_fail;
1344
0
            }
1345
1346
0
            resp.status = 400;
1347
0
            resp.title = (u_char *) "Invalid JSON.";
1348
0
            resp.detail.length = nxt_strlen(error.detail);
1349
0
            resp.detail.start = error.detail;
1350
0
            resp.offset = error.pos - mbuf->pos;
1351
1352
0
            nxt_conf_json_position(mbuf->pos, error.pos,
1353
0
                                   &resp.line, &resp.column);
1354
1355
0
            nxt_controller_response(task, req, &resp);
1356
0
            return;
1357
0
        }
1358
1359
0
        if (path->length != 1) {
1360
0
            rc = nxt_conf_op_compile(c->mem_pool, &ops,
1361
0
                                     nxt_controller_conf.root,
1362
0
                                     path, value, post);
1363
1364
0
            if (rc != NXT_CONF_OP_OK) {
1365
0
                nxt_mp_destroy(mp);
1366
1367
0
                switch (rc) {
1368
0
                case NXT_CONF_OP_NOT_FOUND:
1369
0
                    goto not_found;
1370
1371
0
                case NXT_CONF_OP_NOT_ALLOWED:
1372
0
                    goto not_allowed;
1373
0
                }
1374
1375
                /* rc == NXT_CONF_OP_ERROR */
1376
0
                goto alloc_fail;
1377
0
            }
1378
1379
0
            value = nxt_conf_clone(mp, ops, nxt_controller_conf.root);
1380
1381
0
            if (nxt_slow_path(value == NULL)) {
1382
0
                nxt_mp_destroy(mp);
1383
0
                goto alloc_fail;
1384
0
            }
1385
0
        }
1386
1387
0
        nxt_memzero(&vldt, sizeof(nxt_conf_validation_t));
1388
1389
0
        vldt.conf = value;
1390
0
        vldt.pool = c->mem_pool;
1391
0
        vldt.conf_pool = mp;
1392
0
        vldt.ver = NXT_VERNUM;
1393
1394
0
        rc = nxt_conf_validate(&vldt);
1395
1396
0
        if (nxt_slow_path(rc != NXT_OK)) {
1397
0
            nxt_mp_destroy(mp);
1398
1399
0
            if (rc == NXT_DECLINED) {
1400
0
                resp.detail = vldt.error;
1401
0
                goto invalid_conf;
1402
0
            }
1403
1404
            /* rc == NXT_ERROR */
1405
0
            goto alloc_fail;
1406
0
        }
1407
1408
0
        rc = nxt_controller_conf_send(task, mp, value,
1409
0
                                      nxt_controller_conf_handler, req);
1410
1411
0
        if (nxt_slow_path(rc != NXT_OK)) {
1412
0
            nxt_mp_destroy(mp);
1413
1414
            /* rc == NXT_ERROR */
1415
0
            goto alloc_fail;
1416
0
        }
1417
1418
0
        req->conf.root = value;
1419
0
        req->conf.pool = mp;
1420
1421
0
        nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link);
1422
1423
0
        return;
1424
0
    }
1425
1426
0
    if (nxt_str_eq(&req->parser.method, "DELETE", 6)) {
1427
1428
0
        if (nxt_controller_check_postpone_request(task)) {
1429
0
            nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link);
1430
0
            return;
1431
0
        }
1432
1433
0
        if (path->length == 1) {
1434
0
            mp = nxt_mp_create(1024, 128, 256, 32);
1435
1436
0
            if (nxt_slow_path(mp == NULL)) {
1437
0
                goto alloc_fail;
1438
0
            }
1439
1440
0
            value = nxt_conf_json_parse_str(mp, &empty_obj);
1441
1442
0
        } else {
1443
0
            rc = nxt_conf_op_compile(c->mem_pool, &ops,
1444
0
                                     nxt_controller_conf.root,
1445
0
                                     path, NULL, 0);
1446
1447
0
            if (rc != NXT_OK) {
1448
0
                if (rc == NXT_CONF_OP_NOT_FOUND) {
1449
0
                    goto not_found;
1450
0
                }
1451
1452
                /* rc == NXT_CONF_OP_ERROR */
1453
0
                goto alloc_fail;
1454
0
            }
1455
1456
0
            mp = nxt_mp_create(1024, 128, 256, 32);
1457
1458
0
            if (nxt_slow_path(mp == NULL)) {
1459
0
                goto alloc_fail;
1460
0
            }
1461
1462
0
            value = nxt_conf_clone(mp, ops, nxt_controller_conf.root);
1463
0
        }
1464
1465
0
        if (nxt_slow_path(value == NULL)) {
1466
0
            nxt_mp_destroy(mp);
1467
0
            goto alloc_fail;
1468
0
        }
1469
1470
0
        nxt_memzero(&vldt, sizeof(nxt_conf_validation_t));
1471
1472
0
        vldt.conf = value;
1473
0
        vldt.pool = c->mem_pool;
1474
0
        vldt.conf_pool = mp;
1475
0
        vldt.ver = NXT_VERNUM;
1476
1477
0
        rc = nxt_conf_validate(&vldt);
1478
1479
0
        if (nxt_slow_path(rc != NXT_OK)) {
1480
0
            nxt_mp_destroy(mp);
1481
1482
0
            if (rc == NXT_DECLINED) {
1483
0
                resp.detail = vldt.error;
1484
0
                goto invalid_conf;
1485
0
            }
1486
1487
            /* rc == NXT_ERROR */
1488
0
            goto alloc_fail;
1489
0
        }
1490
1491
0
        rc = nxt_controller_conf_send(task, mp, value,
1492
0
                                      nxt_controller_conf_handler, req);
1493
1494
0
        if (nxt_slow_path(rc != NXT_OK)) {
1495
0
            nxt_mp_destroy(mp);
1496
1497
            /* rc == NXT_ERROR */
1498
0
            goto alloc_fail;
1499
0
        }
1500
1501
0
        req->conf.root = value;
1502
0
        req->conf.pool = mp;
1503
1504
0
        nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link);
1505
1506
0
        return;
1507
0
    }
1508
1509
0
not_allowed:
1510
1511
0
    resp.status = 405;
1512
0
    resp.title = (u_char *) "Method isn't allowed.";
1513
0
    resp.offset = -1;
1514
1515
0
    nxt_controller_response(task, req, &resp);
1516
0
    return;
1517
1518
0
not_found:
1519
1520
0
    resp.status = 404;
1521
0
    resp.title = (u_char *) "Value doesn't exist.";
1522
0
    resp.offset = -1;
1523
1524
0
    nxt_controller_response(task, req, &resp);
1525
0
    return;
1526
1527
0
invalid_conf:
1528
1529
0
    resp.status = 400;
1530
0
    resp.title = (u_char *) "Invalid configuration.";
1531
0
    resp.offset = -1;
1532
1533
0
    nxt_controller_response(task, req, &resp);
1534
0
    return;
1535
1536
0
alloc_fail:
1537
1538
0
    resp.status = 500;
1539
0
    resp.title = (u_char *) "Memory allocation failed.";
1540
0
    resp.offset = -1;
1541
1542
0
    nxt_controller_response(task, req, &resp);
1543
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_process_config
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_process_config
1544
1545
1546
static nxt_bool_t
1547
nxt_controller_check_postpone_request(nxt_task_t *task)
1548
0
{
1549
0
    nxt_port_t     *router_port;
1550
0
    nxt_runtime_t  *rt;
1551
1552
0
    if (!nxt_queue_is_empty(&nxt_controller_waiting_requests)
1553
0
        || nxt_controller_waiting_init_conf
1554
0
        || !nxt_controller_router_ready)
1555
0
    {
1556
0
        return 1;
1557
0
    }
1558
1559
0
    rt = task->thread->runtime;
1560
1561
0
    router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
1562
1563
0
    return (router_port == NULL);
1564
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_check_postpone_request
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_check_postpone_request
1565
1566
1567
static void
1568
nxt_controller_process_status(nxt_task_t *task, nxt_controller_request_t *req)
1569
0
{
1570
0
    uint32_t                   stream;
1571
0
    nxt_int_t                  rc;
1572
0
    nxt_port_t                 *router_port, *controller_port;
1573
0
    nxt_runtime_t              *rt;
1574
0
    nxt_controller_response_t  resp;
1575
1576
0
    if (nxt_controller_check_postpone_request(task)) {
1577
0
        nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link);
1578
0
        return;
1579
0
    }
1580
1581
0
    rt = task->thread->runtime;
1582
1583
0
    router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
1584
1585
0
    nxt_assert(router_port != NULL);
1586
0
    nxt_assert(nxt_controller_router_ready);
1587
1588
0
    controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
1589
1590
0
    stream = nxt_port_rpc_register_handler(task, controller_port,
1591
0
                                           nxt_controller_status_handler,
1592
0
                                           nxt_controller_status_handler,
1593
0
                                           router_port->pid, req);
1594
0
    if (nxt_slow_path(stream == 0)) {
1595
0
        goto fail;
1596
0
    }
1597
1598
0
    rc = nxt_port_socket_write(task, router_port, NXT_PORT_MSG_STATUS,
1599
0
                               -1, stream, controller_port->id, NULL);
1600
1601
0
    if (nxt_slow_path(rc != NXT_OK)) {
1602
0
        nxt_port_rpc_cancel(task, controller_port, stream);
1603
1604
0
        goto fail;
1605
0
    }
1606
1607
0
    nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link);
1608
0
    return;
1609
1610
0
fail:
1611
1612
0
    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1613
1614
0
    resp.status = 500;
1615
0
    resp.title = (u_char *) "Failed to get status.";
1616
0
    resp.offset = -1;
1617
1618
0
    nxt_controller_response(task, req, &resp);
1619
0
    return;
1620
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_process_status
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_process_status
1621
1622
1623
static void
1624
nxt_controller_status_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1625
    void *data)
1626
0
{
1627
0
    nxt_conf_value_t           *status;
1628
0
    nxt_controller_request_t   *req;
1629
0
    nxt_controller_response_t  resp;
1630
1631
0
    nxt_debug(task, "controller status handler");
1632
1633
0
    req = data;
1634
1635
0
    if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) {
1636
0
        status = nxt_status_get((nxt_status_report_t *) msg->buf->mem.pos,
1637
0
                                req->conn->mem_pool);
1638
0
    } else {
1639
0
        status = NULL;
1640
0
    }
1641
1642
0
    if (status == NULL) {
1643
0
        nxt_queue_remove(&req->link);
1644
1645
0
        nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1646
1647
0
        resp.status = 500;
1648
0
        resp.title = (u_char *) "Failed to get status.";
1649
0
        resp.offset = -1;
1650
1651
0
        nxt_controller_response(task, req, &resp);
1652
0
    }
1653
1654
0
    nxt_controller_status = status;
1655
1656
0
    nxt_controller_flush_requests(task);
1657
1658
0
    nxt_controller_status = NULL;
1659
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_status_handler
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_status_handler
1660
1661
1662
static void
1663
nxt_controller_status_response(nxt_task_t *task, nxt_controller_request_t *req,
1664
    nxt_str_t *path)
1665
0
{
1666
0
    nxt_conf_value_t           *status;
1667
0
    nxt_controller_response_t  resp;
1668
1669
0
    status = nxt_conf_get_path(nxt_controller_status, path);
1670
1671
0
    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1672
1673
0
    if (status == NULL) {
1674
0
        resp.status = 404;
1675
0
        resp.title = (u_char *) "Invalid path.";
1676
0
        resp.offset = -1;
1677
1678
0
        nxt_controller_response(task, req, &resp);
1679
0
        return;
1680
0
    }
1681
1682
0
    resp.status = 200;
1683
0
    resp.conf = status;
1684
1685
0
    nxt_controller_response(task, req, &resp);
1686
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_status_response
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_status_response
1687
1688
1689
#if (NXT_TLS)
1690
1691
static void
1692
nxt_controller_process_cert(nxt_task_t *task,
1693
    nxt_controller_request_t *req, nxt_str_t *path)
1694
{
1695
    u_char                     *p;
1696
    nxt_str_t                  name;
1697
    nxt_int_t                  ret;
1698
    nxt_conn_t                 *c;
1699
    nxt_cert_t                 *cert;
1700
    nxt_conf_value_t           *value;
1701
    nxt_controller_response_t  resp;
1702
1703
    name.length = path->length - 1;
1704
    name.start = path->start + 1;
1705
1706
    p = memchr(name.start, '/', name.length);
1707
1708
    if (p != NULL) {
1709
        name.length = p - name.start;
1710
1711
        path->length -= p - path->start;
1712
        path->start = p;
1713
1714
    } else {
1715
        path = NULL;
1716
    }
1717
1718
    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1719
1720
    c = req->conn;
1721
1722
    if (nxt_str_eq(&req->parser.method, "GET", 3)) {
1723
1724
        if (name.length != 0) {
1725
            value = nxt_cert_info_get(&name);
1726
            if (value == NULL) {
1727
                goto cert_not_found;
1728
            }
1729
1730
            if (path != NULL) {
1731
                value = nxt_conf_get_path(value, path);
1732
                if (value == NULL) {
1733
                    goto not_found;
1734
                }
1735
            }
1736
1737
        } else {
1738
            value = nxt_cert_info_get_all(c->mem_pool);
1739
            if (value == NULL) {
1740
                goto alloc_fail;
1741
            }
1742
        }
1743
1744
        resp.status = 200;
1745
        resp.conf = value;
1746
1747
        nxt_controller_response(task, req, &resp);
1748
        return;
1749
    }
1750
1751
    if (name.length == 0 || path != NULL) {
1752
        goto invalid_name;
1753
    }
1754
1755
    if (nxt_str_eq(&req->parser.method, "PUT", 3)) {
1756
        value = nxt_cert_info_get(&name);
1757
        if (value != NULL) {
1758
            goto exists_cert;
1759
        }
1760
1761
        cert = nxt_cert_mem(task, &c->read->mem);
1762
        if (cert == NULL) {
1763
            goto invalid_cert;
1764
        }
1765
1766
        ret = nxt_cert_info_save(&name, cert);
1767
1768
        nxt_cert_destroy(cert);
1769
1770
        if (nxt_slow_path(ret != NXT_OK)) {
1771
            goto alloc_fail;
1772
        }
1773
1774
        nxt_cert_store_get(task, &name, c->mem_pool,
1775
                           nxt_controller_process_cert_save, req);
1776
        return;
1777
    }
1778
1779
    if (nxt_str_eq(&req->parser.method, "DELETE", 6)) {
1780
1781
        if (nxt_controller_cert_in_use(&name)) {
1782
            goto cert_in_use;
1783
        }
1784
1785
        if (nxt_cert_info_delete(&name) != NXT_OK) {
1786
            goto cert_not_found;
1787
        }
1788
1789
        nxt_cert_store_delete(task, &name, c->mem_pool);
1790
1791
        resp.status = 200;
1792
        resp.title = (u_char *) "Certificate deleted.";
1793
1794
        nxt_controller_response(task, req, &resp);
1795
        return;
1796
    }
1797
1798
    resp.status = 405;
1799
    resp.title = (u_char *) "Invalid method.";
1800
    resp.offset = -1;
1801
1802
    nxt_controller_response(task, req, &resp);
1803
    return;
1804
1805
invalid_name:
1806
1807
    resp.status = 400;
1808
    resp.title = (u_char *) "Invalid certificate name.";
1809
    resp.offset = -1;
1810
1811
    nxt_controller_response(task, req, &resp);
1812
    return;
1813
1814
invalid_cert:
1815
1816
    resp.status = 400;
1817
    resp.title = (u_char *) "Invalid certificate.";
1818
    resp.offset = -1;
1819
1820
    nxt_controller_response(task, req, &resp);
1821
    return;
1822
1823
exists_cert:
1824
1825
    resp.status = 400;
1826
    resp.title = (u_char *) "Certificate already exists.";
1827
    resp.offset = -1;
1828
1829
    nxt_controller_response(task, req, &resp);
1830
    return;
1831
1832
cert_in_use:
1833
1834
    resp.status = 400;
1835
    resp.title = (u_char *) "Certificate is used in the configuration.";
1836
    resp.offset = -1;
1837
1838
    nxt_controller_response(task, req, &resp);
1839
    return;
1840
1841
cert_not_found:
1842
1843
    resp.status = 404;
1844
    resp.title = (u_char *) "Certificate doesn't exist.";
1845
    resp.offset = -1;
1846
1847
    nxt_controller_response(task, req, &resp);
1848
    return;
1849
1850
not_found:
1851
1852
    resp.status = 404;
1853
    resp.title = (u_char *) "Invalid path.";
1854
    resp.offset = -1;
1855
1856
    nxt_controller_response(task, req, &resp);
1857
    return;
1858
1859
alloc_fail:
1860
1861
    resp.status = 500;
1862
    resp.title = (u_char *) "Memory allocation failed.";
1863
    resp.offset = -1;
1864
1865
    nxt_controller_response(task, req, &resp);
1866
    return;
1867
}
1868
1869
1870
static void
1871
nxt_controller_process_cert_save(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1872
    void *data)
1873
{
1874
    nxt_conn_t                *c;
1875
    nxt_buf_mem_t             *mbuf;
1876
    nxt_controller_request_t  *req;
1877
    nxt_controller_response_t  resp;
1878
1879
    req = data;
1880
1881
    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1882
1883
    if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) {
1884
        resp.status = 500;
1885
        resp.title = (u_char *) "Failed to store certificate.";
1886
1887
        nxt_controller_response(task, req, &resp);
1888
        return;
1889
    }
1890
1891
    c = req->conn;
1892
1893
    mbuf = &c->read->mem;
1894
1895
    nxt_fd_write(msg->fd[0], mbuf->pos, nxt_buf_mem_used_size(mbuf));
1896
1897
    nxt_fd_close(msg->fd[0]);
1898
1899
    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1900
1901
    resp.status = 200;
1902
    resp.title = (u_char *) "Certificate chain uploaded.";
1903
1904
    nxt_controller_response(task, req, &resp);
1905
}
1906
1907
1908
static nxt_bool_t
1909
nxt_controller_cert_in_use(nxt_str_t *name)
1910
{
1911
    uint32_t          i, n, next;
1912
    nxt_str_t         str;
1913
    nxt_conf_value_t  *listeners, *listener, *value, *element;
1914
1915
    static const nxt_str_t  listeners_path = nxt_string("/listeners");
1916
    static const nxt_str_t  certificate_path = nxt_string("/tls/certificate");
1917
1918
    listeners = nxt_conf_get_path(nxt_controller_conf.root, &listeners_path);
1919
1920
    if (listeners != NULL) {
1921
        next = 0;
1922
1923
        for ( ;; ) {
1924
            listener = nxt_conf_next_object_member(listeners, &str, &next);
1925
            if (listener == NULL) {
1926
                break;
1927
            }
1928
1929
            value = nxt_conf_get_path(listener, &certificate_path);
1930
            if (value == NULL) {
1931
                continue;
1932
            }
1933
1934
            if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
1935
                n = nxt_conf_array_elements_count(value);
1936
1937
                for (i = 0; i < n; i++) {
1938
                    element = nxt_conf_get_array_element(value, i);
1939
1940
                    nxt_conf_get_string(element, &str);
1941
1942
                    if (nxt_strstr_eq(&str, name)) {
1943
                        return 1;
1944
                    }
1945
                }
1946
1947
            } else {
1948
                /* NXT_CONF_STRING */
1949
1950
                nxt_conf_get_string(value, &str);
1951
1952
                if (nxt_strstr_eq(&str, name)) {
1953
                    return 1;
1954
                }
1955
            }
1956
        }
1957
    }
1958
1959
    return 0;
1960
}
1961
1962
#endif
1963
1964
1965
#if (NXT_HAVE_NJS)
1966
1967
static void
1968
nxt_controller_process_script(nxt_task_t *task,
1969
    nxt_controller_request_t *req, nxt_str_t *path)
1970
{
1971
    u_char                     *p;
1972
    nxt_int_t                  ret;
1973
    nxt_str_t                  name;
1974
    nxt_conn_t                 *c;
1975
    nxt_script_t               *script;
1976
    nxt_buf_mem_t              *bm;
1977
    nxt_conf_value_t           *value;
1978
    nxt_controller_response_t  resp;
1979
    u_char                     error[NXT_MAX_ERROR_STR];
1980
1981
    name.length = path->length - 1;
1982
    name.start = path->start + 1;
1983
1984
    p = memchr(name.start, '/', name.length);
1985
1986
    if (p != NULL) {
1987
        name.length = p - name.start;
1988
1989
        path->length -= p - path->start;
1990
        path->start = p;
1991
1992
    } else {
1993
        path = NULL;
1994
    }
1995
1996
    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1997
1998
    c = req->conn;
1999
2000
    if (nxt_str_eq(&req->parser.method, "GET", 3)) {
2001
2002
        if (name.length != 0) {
2003
            value = nxt_script_info_get(&name);
2004
            if (value == NULL) {
2005
                goto script_not_found;
2006
            }
2007
2008
            if (path != NULL) {
2009
                value = nxt_conf_get_path(value, path);
2010
                if (value == NULL) {
2011
                    goto not_found;
2012
                }
2013
            }
2014
2015
        } else {
2016
            value = nxt_script_info_get_all(c->mem_pool);
2017
            if (value == NULL) {
2018
                goto alloc_fail;
2019
            }
2020
        }
2021
2022
        resp.status = 200;
2023
        resp.conf = value;
2024
2025
        nxt_controller_response(task, req, &resp);
2026
        return;
2027
    }
2028
2029
    if (name.length == 0 || path != NULL) {
2030
        goto invalid_name;
2031
    }
2032
2033
    if (nxt_str_eq(&req->parser.method, "PUT", 3)) {
2034
        value = nxt_script_info_get(&name);
2035
        if (value != NULL) {
2036
            goto exists_script;
2037
        }
2038
2039
        bm = &c->read->mem;
2040
2041
        script = nxt_script_new(task, &name, bm->pos,
2042
                                nxt_buf_mem_used_size(bm), error);
2043
        if (script == NULL) {
2044
            goto invalid_script;
2045
        }
2046
2047
        ret = nxt_script_info_save(&name, script);
2048
2049
        nxt_script_destroy(script);
2050
2051
        if (nxt_slow_path(ret != NXT_OK)) {
2052
            goto alloc_fail;
2053
        }
2054
2055
        nxt_script_store_get(task, &name, c->mem_pool,
2056
                             nxt_controller_process_script_save, req);
2057
        return;
2058
    }
2059
2060
    if (nxt_str_eq(&req->parser.method, "DELETE", 6)) {
2061
2062
        if (nxt_controller_script_in_use(&name)) {
2063
            goto script_in_use;
2064
        }
2065
2066
        if (nxt_script_info_delete(&name) != NXT_OK) {
2067
            goto script_not_found;
2068
        }
2069
2070
        nxt_script_store_delete(task, &name, c->mem_pool);
2071
2072
        resp.status = 200;
2073
        resp.title = (u_char *) "JS module deleted.";
2074
2075
        nxt_controller_response(task, req, &resp);
2076
        return;
2077
    }
2078
2079
    resp.status = 405;
2080
    resp.title = (u_char *) "Invalid method.";
2081
    resp.offset = -1;
2082
2083
    nxt_controller_response(task, req, &resp);
2084
    return;
2085
2086
invalid_name:
2087
2088
    resp.status = 400;
2089
    resp.title = (u_char *) "Invalid JS module name.";
2090
    resp.offset = -1;
2091
2092
    nxt_controller_response(task, req, &resp);
2093
    return;
2094
2095
invalid_script:
2096
2097
    resp.status = 400;
2098
    resp.title = (u_char *) "Invalid JS module.";
2099
    resp.offset = -1;
2100
2101
    resp.detail.start = error;
2102
    resp.detail.length = nxt_strlen(error);
2103
2104
    nxt_controller_response(task, req, &resp);
2105
    return;
2106
2107
exists_script:
2108
2109
    resp.status = 400;
2110
    resp.title = (u_char *) "JS module already exists.";
2111
    resp.offset = -1;
2112
2113
    nxt_controller_response(task, req, &resp);
2114
    return;
2115
2116
script_in_use:
2117
2118
    resp.status = 400;
2119
    resp.title = (u_char *) "JS module is used in the configuration.";
2120
    resp.offset = -1;
2121
2122
    nxt_controller_response(task, req, &resp);
2123
    return;
2124
2125
script_not_found:
2126
2127
    resp.status = 404;
2128
    resp.title = (u_char *) "JS module doesn't exist.";
2129
    resp.offset = -1;
2130
2131
    nxt_controller_response(task, req, &resp);
2132
    return;
2133
2134
not_found:
2135
2136
    resp.status = 404;
2137
    resp.title = (u_char *) "Invalid path.";
2138
    resp.offset = -1;
2139
2140
    nxt_controller_response(task, req, &resp);
2141
    return;
2142
2143
alloc_fail:
2144
2145
    resp.status = 500;
2146
    resp.title = (u_char *) "Memory allocation failed.";
2147
    resp.offset = -1;
2148
2149
    nxt_controller_response(task, req, &resp);
2150
}
2151
2152
2153
static void
2154
nxt_controller_process_script_save(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2155
    void *data)
2156
{
2157
    nxt_conn_t                 *c;
2158
    nxt_buf_mem_t              *mbuf;
2159
    nxt_controller_request_t   *req;
2160
    nxt_controller_response_t  resp;
2161
2162
    req = data;
2163
2164
    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
2165
2166
    if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) {
2167
        resp.status = 500;
2168
        resp.title = (u_char *) "Failed to store script.";
2169
2170
        nxt_controller_response(task, req, &resp);
2171
        return;
2172
    }
2173
2174
    c = req->conn;
2175
2176
    mbuf = &c->read->mem;
2177
2178
    nxt_fd_write(msg->fd[0], mbuf->pos, nxt_buf_mem_used_size(mbuf));
2179
2180
    nxt_fd_close(msg->fd[0]);
2181
2182
    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
2183
2184
    resp.status = 200;
2185
    resp.title = (u_char *) "JS module uploaded.";
2186
2187
    nxt_controller_response(task, req, &resp);
2188
}
2189
2190
2191
static nxt_bool_t
2192
nxt_controller_script_in_use(nxt_str_t *name)
2193
{
2194
    uint32_t          i, n;
2195
    nxt_str_t         str;
2196
    nxt_conf_value_t  *js_module, *element;
2197
2198
    static const nxt_str_t  js_module_path = nxt_string("/settings/js_module");
2199
2200
    js_module = nxt_conf_get_path(nxt_controller_conf.root,
2201
                                    &js_module_path);
2202
2203
    if (js_module != NULL) {
2204
2205
        if (nxt_conf_type(js_module) == NXT_CONF_ARRAY) {
2206
            n = nxt_conf_array_elements_count(js_module);
2207
2208
            for (i = 0; i < n; i++) {
2209
                element = nxt_conf_get_array_element(js_module, i);
2210
2211
                nxt_conf_get_string(element, &str);
2212
2213
                if (nxt_strstr_eq(&str, name)) {
2214
                    return 1;
2215
                }
2216
            }
2217
2218
        } else {
2219
            /* NXT_CONF_STRING */
2220
2221
            nxt_conf_get_string(js_module, &str);
2222
2223
            if (nxt_strstr_eq(&str, name)) {
2224
                return 1;
2225
            }
2226
        }
2227
    }
2228
2229
    return 0;
2230
}
2231
2232
2233
static void
2234
nxt_controller_script_cleanup(nxt_task_t *task, void *obj, void *data)
2235
{
2236
    pid_t          main_pid;
2237
    nxt_array_t    *scripts;
2238
    nxt_runtime_t  *rt;
2239
2240
    scripts = obj;
2241
    rt = data;
2242
2243
    main_pid = rt->port_by_type[NXT_PROCESS_MAIN]->pid;
2244
2245
    if (nxt_pid == main_pid && scripts != NULL) {
2246
        nxt_script_store_release(scripts);
2247
    }
2248
}
2249
2250
#endif
2251
2252
2253
static void
2254
nxt_controller_conf_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2255
    void *data)
2256
0
{
2257
0
    nxt_controller_request_t   *req;
2258
0
    nxt_controller_response_t  resp;
2259
2260
0
    req = data;
2261
2262
0
    nxt_debug(task, "controller conf ready: %*s",
2263
0
              nxt_buf_mem_used_size(&msg->buf->mem), msg->buf->mem.pos);
2264
2265
0
    nxt_queue_remove(&req->link);
2266
2267
0
    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
2268
2269
0
    if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) {
2270
0
        nxt_mp_destroy(nxt_controller_conf.pool);
2271
2272
0
        nxt_controller_conf = req->conf;
2273
2274
0
        nxt_controller_conf_store(task, req->conf.root);
2275
2276
0
        resp.status = 200;
2277
0
        resp.title = (u_char *) "Reconfiguration done.";
2278
2279
0
    } else {
2280
0
        nxt_mp_destroy(req->conf.pool);
2281
2282
0
        resp.status = 500;
2283
0
        resp.title = (u_char *) "Failed to apply new configuration.";
2284
0
        resp.offset = -1;
2285
0
    }
2286
2287
0
    nxt_controller_response(task, req, &resp);
2288
2289
0
    nxt_controller_flush_requests(task);
2290
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_conf_handler
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_conf_handler
2291
2292
2293
static void
2294
nxt_controller_process_control(nxt_task_t *task,
2295
    nxt_controller_request_t *req, nxt_str_t *path)
2296
0
{
2297
0
    uint32_t                   stream;
2298
0
    nxt_buf_t                  *b;
2299
0
    nxt_int_t                  rc;
2300
0
    nxt_port_t                 *router_port, *controller_port;
2301
0
    nxt_runtime_t              *rt;
2302
0
    nxt_conf_value_t           *value;
2303
0
    nxt_controller_response_t  resp;
2304
2305
0
    static const nxt_str_t applications = nxt_string("applications");
2306
2307
0
    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
2308
2309
0
    if (!nxt_str_eq(&req->parser.method, "GET", 3)) {
2310
0
        goto not_allowed;
2311
0
    }
2312
2313
0
    if (!nxt_str_start(path, "applications/", 13)
2314
0
        || memcmp(path->start + path->length - 8, "/restart", 8) != 0)
2315
0
    {
2316
0
        goto not_found;
2317
0
    }
2318
2319
0
    path->start += 13;
2320
0
    path->length -= 13 + 8;
2321
2322
0
    if (nxt_controller_check_postpone_request(task)) {
2323
0
        nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link);
2324
0
        return;
2325
0
    }
2326
2327
0
    value = nxt_controller_conf.root;
2328
0
    if (value == NULL) {
2329
0
        goto not_found;
2330
0
    }
2331
2332
0
    value = nxt_conf_get_object_member(value, &applications, NULL);
2333
0
    if (value == NULL) {
2334
0
        goto not_found;
2335
0
    }
2336
2337
0
    value = nxt_conf_get_object_member(value, path, NULL);
2338
0
    if (value == NULL) {
2339
0
        goto not_found;
2340
0
    }
2341
2342
0
    b = nxt_buf_mem_alloc(req->conn->mem_pool, path->length, 0);
2343
0
    if (nxt_slow_path(b == NULL)) {
2344
0
        goto alloc_fail;
2345
0
    }
2346
2347
0
    b->mem.free = nxt_cpymem(b->mem.pos, path->start, path->length);
2348
2349
0
    rt = task->thread->runtime;
2350
2351
0
    controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
2352
0
    router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
2353
2354
0
    stream = nxt_port_rpc_register_handler(task, controller_port,
2355
0
                                           nxt_controller_app_restart_handler,
2356
0
                                           nxt_controller_app_restart_handler,
2357
0
                                           router_port->pid, req);
2358
0
    if (nxt_slow_path(stream == 0)) {
2359
0
        goto alloc_fail;
2360
0
    }
2361
2362
0
    rc = nxt_port_socket_write(task, router_port, NXT_PORT_MSG_APP_RESTART,
2363
0
                               -1, stream, 0, b);
2364
0
    if (nxt_slow_path(rc != NXT_OK)) {
2365
0
        nxt_port_rpc_cancel(task, controller_port, stream);
2366
2367
0
        goto fail;
2368
0
    }
2369
2370
0
    nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link);
2371
2372
0
    return;
2373
2374
0
not_allowed:
2375
2376
0
    resp.status = 405;
2377
0
    resp.title = (u_char *) "Method isn't allowed.";
2378
0
    resp.offset = -1;
2379
2380
0
    nxt_controller_response(task, req, &resp);
2381
0
    return;
2382
2383
0
not_found:
2384
2385
0
    resp.status = 404;
2386
0
    resp.title = (u_char *) "Value doesn't exist.";
2387
0
    resp.offset = -1;
2388
2389
0
    nxt_controller_response(task, req, &resp);
2390
0
    return;
2391
2392
0
alloc_fail:
2393
2394
0
    resp.status = 500;
2395
0
    resp.title = (u_char *) "Memory allocation failed.";
2396
0
    resp.offset = -1;
2397
2398
0
    nxt_controller_response(task, req, &resp);
2399
0
    return;
2400
2401
0
fail:
2402
2403
0
    resp.status = 500;
2404
0
    resp.title = (u_char *) "Send restart failed.";
2405
0
    resp.offset = -1;
2406
2407
0
    nxt_controller_response(task, req, &resp);
2408
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_process_control
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_process_control
2409
2410
2411
static void
2412
nxt_controller_app_restart_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2413
    void *data)
2414
0
{
2415
0
    nxt_controller_request_t   *req;
2416
0
    nxt_controller_response_t  resp;
2417
2418
0
    req = data;
2419
2420
0
    nxt_debug(task, "controller app restart handler");
2421
2422
0
    nxt_queue_remove(&req->link);
2423
2424
0
    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
2425
2426
0
    if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) {
2427
0
        resp.status = 200;
2428
0
        resp.title = (u_char *) "Ok";
2429
2430
0
    } else {
2431
0
        resp.status = 500;
2432
0
        resp.title = (u_char *) "Failed to restart app.";
2433
0
        resp.offset = -1;
2434
0
    }
2435
2436
0
    nxt_controller_response(task, req, &resp);
2437
2438
0
    nxt_controller_flush_requests(task);
2439
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_app_restart_handler
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_app_restart_handler
2440
2441
2442
static void
2443
nxt_controller_conf_store(nxt_task_t *task, nxt_conf_value_t *conf)
2444
0
{
2445
0
    void           *mem;
2446
0
    u_char         *end;
2447
0
    size_t         size;
2448
0
    nxt_fd_t       fd;
2449
0
    nxt_buf_t      *b;
2450
0
    nxt_port_t     *main_port;
2451
0
    nxt_runtime_t  *rt;
2452
2453
0
    rt = task->thread->runtime;
2454
2455
0
    main_port = rt->port_by_type[NXT_PROCESS_MAIN];
2456
2457
0
    size = nxt_conf_json_length(conf, NULL);
2458
2459
0
    fd = nxt_shm_open(task, size);
2460
0
    if (nxt_slow_path(fd == -1)) {
2461
0
        return;
2462
0
    }
2463
2464
0
    mem = nxt_mem_mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
2465
0
    if (nxt_slow_path(mem == MAP_FAILED)) {
2466
0
        goto fail;
2467
0
    }
2468
2469
0
    end = nxt_conf_json_print(mem, conf, NULL);
2470
2471
0
    nxt_mem_munmap(mem, size);
2472
2473
0
    size = end - (u_char *) mem;
2474
2475
0
    b = nxt_buf_mem_alloc(task->thread->engine->mem_pool, sizeof(size_t), 0);
2476
0
    if (nxt_slow_path(b == NULL)) {
2477
0
        goto fail;
2478
0
    }
2479
2480
0
    b->mem.free = nxt_cpymem(b->mem.pos, &size, sizeof(size_t));
2481
2482
0
    (void) nxt_port_socket_write(task, main_port,
2483
0
                                NXT_PORT_MSG_CONF_STORE | NXT_PORT_MSG_CLOSE_FD,
2484
0
                                 fd, 0, -1, b);
2485
2486
0
    return;
2487
2488
0
fail:
2489
2490
0
    nxt_fd_close(fd);
2491
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_conf_store
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_conf_store
2492
2493
2494
static void
2495
nxt_controller_response(nxt_task_t *task, nxt_controller_request_t *req,
2496
    nxt_controller_response_t *resp)
2497
0
{
2498
0
    size_t                  size;
2499
0
    nxt_str_t               status_line, str;
2500
0
    nxt_buf_t               *b, *body;
2501
0
    nxt_conn_t              *c;
2502
0
    nxt_uint_t              n;
2503
0
    nxt_conf_value_t        *value, *location;
2504
0
    nxt_conf_json_pretty_t  pretty;
2505
2506
0
    static const nxt_str_t  success_str = nxt_string("success");
2507
0
    static const nxt_str_t  error_str = nxt_string("error");
2508
0
    static const nxt_str_t  detail_str = nxt_string("detail");
2509
0
    static const nxt_str_t  location_str = nxt_string("location");
2510
0
    static const nxt_str_t  offset_str = nxt_string("offset");
2511
0
    static const nxt_str_t  line_str = nxt_string("line");
2512
0
    static const nxt_str_t  column_str = nxt_string("column");
2513
2514
0
    static nxt_time_string_t  date_cache = {
2515
0
        (nxt_atomic_uint_t) -1,
2516
0
        nxt_controller_date,
2517
0
        "%s, %02d %s %4d %02d:%02d:%02d GMT",
2518
0
        nxt_length("Wed, 31 Dec 1986 16:40:00 GMT"),
2519
0
        NXT_THREAD_TIME_GMT,
2520
0
        NXT_THREAD_TIME_SEC,
2521
0
    };
2522
2523
0
    switch (resp->status) {
2524
2525
0
    case 200:
2526
0
        nxt_str_set(&status_line, "200 OK");
2527
0
        break;
2528
2529
0
    case 400:
2530
0
        nxt_str_set(&status_line, "400 Bad Request");
2531
0
        break;
2532
2533
0
    case 404:
2534
0
        nxt_str_set(&status_line, "404 Not Found");
2535
0
        break;
2536
2537
0
    case 405:
2538
0
        nxt_str_set(&status_line, "405 Method Not Allowed");
2539
0
        break;
2540
2541
0
    default:
2542
0
        nxt_str_set(&status_line, "500 Internal Server Error");
2543
0
        break;
2544
0
    }
2545
2546
0
    c = req->conn;
2547
0
    value = resp->conf;
2548
2549
0
    if (value == NULL) {
2550
0
        n = 1
2551
0
            + (resp->detail.length != 0)
2552
0
            + (resp->status >= 400 && resp->offset != -1);
2553
2554
0
        value = nxt_conf_create_object(c->mem_pool, n);
2555
2556
0
        if (nxt_slow_path(value == NULL)) {
2557
0
            nxt_controller_conn_close(task, c, req);
2558
0
            return;
2559
0
        }
2560
2561
0
        str.length = nxt_strlen(resp->title);
2562
0
        str.start = resp->title;
2563
2564
0
        if (resp->status < 400) {
2565
0
            nxt_conf_set_member_string(value, &success_str, &str, 0);
2566
2567
0
        } else {
2568
0
            nxt_conf_set_member_string(value, &error_str, &str, 0);
2569
0
        }
2570
2571
0
        n = 0;
2572
2573
0
        if (resp->detail.length != 0) {
2574
0
            n++;
2575
2576
0
            nxt_conf_set_member_string(value, &detail_str, &resp->detail, n);
2577
0
        }
2578
2579
0
        if (resp->status >= 400 && resp->offset != -1) {
2580
0
            n++;
2581
2582
0
            location = nxt_conf_create_object(c->mem_pool,
2583
0
                                              resp->line != 0 ? 3 : 1);
2584
2585
0
            nxt_conf_set_member(value, &location_str, location, n);
2586
2587
0
            nxt_conf_set_member_integer(location, &offset_str, resp->offset, 0);
2588
2589
0
            if (resp->line != 0) {
2590
0
                nxt_conf_set_member_integer(location, &line_str,
2591
0
                                            resp->line, 1);
2592
2593
0
                nxt_conf_set_member_integer(location, &column_str,
2594
0
                                            resp->column, 2);
2595
0
            }
2596
0
        }
2597
0
    }
2598
2599
0
    nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t));
2600
2601
0
    size = nxt_conf_json_length(value, &pretty) + 2;
2602
2603
0
    body = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2604
0
    if (nxt_slow_path(body == NULL)) {
2605
0
        nxt_controller_conn_close(task, c, req);
2606
0
        return;
2607
0
    }
2608
2609
0
    nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t));
2610
2611
0
    body->mem.free = nxt_conf_json_print(body->mem.free, value, &pretty);
2612
2613
0
    body->mem.free = nxt_cpymem(body->mem.free, "\r\n", 2);
2614
2615
0
    size = nxt_length("HTTP/1.1 " "\r\n") + status_line.length
2616
0
           + nxt_length("Server: " NXT_SERVER "\r\n")
2617
0
           + nxt_length("Date: Wed, 31 Dec 1986 16:40:00 GMT\r\n")
2618
0
           + nxt_length("Content-Type: application/json\r\n")
2619
0
           + nxt_length("Content-Length: " "\r\n") + NXT_SIZE_T_LEN
2620
0
           + nxt_length("Connection: close\r\n")
2621
0
           + nxt_length("\r\n");
2622
2623
0
    b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2624
0
    if (nxt_slow_path(b == NULL)) {
2625
0
        nxt_controller_conn_close(task, c, req);
2626
0
        return;
2627
0
    }
2628
2629
0
    b->next = body;
2630
2631
0
    nxt_str_set(&str, "HTTP/1.1 ");
2632
2633
0
    b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length);
2634
0
    b->mem.free = nxt_cpymem(b->mem.free, status_line.start,
2635
0
                             status_line.length);
2636
2637
0
    nxt_str_set(&str, "\r\n"
2638
0
                      "Server: " NXT_SERVER "\r\n"
2639
0
                      "Date: ");
2640
2641
0
    b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length);
2642
2643
0
    b->mem.free = nxt_thread_time_string(task->thread, &date_cache,
2644
0
                                         b->mem.free);
2645
2646
0
    nxt_str_set(&str, "\r\n"
2647
0
                      "Content-Type: application/json\r\n"
2648
0
                      "Content-Length: ");
2649
2650
0
    b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length);
2651
2652
0
    b->mem.free = nxt_sprintf(b->mem.free, b->mem.end, "%uz",
2653
0
                              nxt_buf_mem_used_size(&body->mem));
2654
2655
0
    nxt_str_set(&str, "\r\n"
2656
0
                      "Connection: close\r\n"
2657
0
                      "\r\n");
2658
2659
0
    b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length);
2660
2661
0
    c->write = b;
2662
0
    c->write_state = &nxt_controller_conn_write_state;
2663
2664
0
    nxt_conn_write(task->thread->engine, c);
2665
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_response
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_response
2666
2667
2668
static u_char *
2669
nxt_controller_date(u_char *buf, nxt_realtime_t *now, struct tm *tm,
2670
    size_t size, const char *format)
2671
0
{
2672
0
    static const char * const  week[] = { "Sun", "Mon", "Tue", "Wed", "Thu",
2673
0
                                          "Fri", "Sat" };
2674
2675
0
    static const char * const  month[] = { "Jan", "Feb", "Mar", "Apr", "May",
2676
0
                                           "Jun", "Jul", "Aug", "Sep", "Oct",
2677
0
                                           "Nov", "Dec" };
2678
2679
0
    return nxt_sprintf(buf, buf + size, format,
2680
0
                       week[tm->tm_wday], tm->tm_mday,
2681
0
                       month[tm->tm_mon], tm->tm_year + 1900,
2682
0
                       tm->tm_hour, tm->tm_min, tm->tm_sec);
2683
0
}
Unexecuted instantiation: nxt_controller.c:nxt_controller_date
Unexecuted instantiation: nxt_http_controller_fuzz.c:nxt_controller_date