Coverage Report

Created: 2024-02-25 06:30

/src/unit/src/nxt_controller.c
Line
Count
Source (jump to first uncovered line)
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
}
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
}
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
}
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
}
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
}
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
}
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
}
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
}
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
}
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
}
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
}
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_parent((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
}
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
}
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
}
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
}
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
}
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
}
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
}
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
}
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
}
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
}
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
}
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
0
{
1040
0
    off_t                     length;
1041
0
    nxt_controller_request_t  *r;
1042
1043
0
    r = ctx;
1044
1045
0
    length = nxt_off_t_parse(field->value, field->value_length);
1046
1047
0
    if (nxt_fast_path(length >= 0)) {
1048
1049
0
        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
0
        r->length = length;
1056
0
        return NXT_OK;
1057
0
    }
1058
1059
0
    nxt_log_error(NXT_LOG_ERR, &r->conn->log, "Content-Length is invalid");
1060
1061
0
    return NXT_ERROR;
1062
0
}
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 nxt_str_t certificates = nxt_string("certificates");
1082
#endif
1083
1084
#if (NXT_HAVE_NJS)
1085
    static nxt_str_t scripts_str = nxt_string("js_modules");
1086
#endif
1087
1088
0
    static nxt_str_t config = nxt_string("config");
1089
0
    static 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
}
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
}
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
}
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
}
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
}
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
}
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          next;
1912
    nxt_str_t         str;
1913
    nxt_conf_value_t  *listeners, *listener, *value;
1914
1915
    static nxt_str_t  listeners_path = nxt_string("/listeners");
1916
    static 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
            nxt_conf_get_string(value, &str);
1935
1936
            if (nxt_strstr_eq(&str, name)) {
1937
                return 1;
1938
            }
1939
        }
1940
    }
1941
1942
    return 0;
1943
}
1944
1945
#endif
1946
1947
1948
#if (NXT_HAVE_NJS)
1949
1950
static void
1951
nxt_controller_process_script(nxt_task_t *task,
1952
    nxt_controller_request_t *req, nxt_str_t *path)
1953
{
1954
    u_char                     *p;
1955
    nxt_int_t                  ret;
1956
    nxt_str_t                  name;
1957
    nxt_conn_t                 *c;
1958
    nxt_script_t               *script;
1959
    nxt_buf_mem_t              *bm;
1960
    nxt_conf_value_t           *value;
1961
    nxt_controller_response_t  resp;
1962
    u_char                     error[NXT_MAX_ERROR_STR];
1963
1964
    name.length = path->length - 1;
1965
    name.start = path->start + 1;
1966
1967
    p = memchr(name.start, '/', name.length);
1968
1969
    if (p != NULL) {
1970
        name.length = p - name.start;
1971
1972
        path->length -= p - path->start;
1973
        path->start = p;
1974
1975
    } else {
1976
        path = NULL;
1977
    }
1978
1979
    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1980
1981
    c = req->conn;
1982
1983
    if (nxt_str_eq(&req->parser.method, "GET", 3)) {
1984
1985
        if (name.length != 0) {
1986
            value = nxt_script_info_get(&name);
1987
            if (value == NULL) {
1988
                goto script_not_found;
1989
            }
1990
1991
            if (path != NULL) {
1992
                value = nxt_conf_get_path(value, path);
1993
                if (value == NULL) {
1994
                    goto not_found;
1995
                }
1996
            }
1997
1998
        } else {
1999
            value = nxt_script_info_get_all(c->mem_pool);
2000
            if (value == NULL) {
2001
                goto alloc_fail;
2002
            }
2003
        }
2004
2005
        resp.status = 200;
2006
        resp.conf = value;
2007
2008
        nxt_controller_response(task, req, &resp);
2009
        return;
2010
    }
2011
2012
    if (name.length == 0 || path != NULL) {
2013
        goto invalid_name;
2014
    }
2015
2016
    if (nxt_str_eq(&req->parser.method, "PUT", 3)) {
2017
        value = nxt_script_info_get(&name);
2018
        if (value != NULL) {
2019
            goto exists_script;
2020
        }
2021
2022
        bm = &c->read->mem;
2023
2024
        script = nxt_script_new(task, &name, bm->pos,
2025
                                nxt_buf_mem_used_size(bm), error);
2026
        if (script == NULL) {
2027
            goto invalid_script;
2028
        }
2029
2030
        ret = nxt_script_info_save(&name, script);
2031
2032
        nxt_script_destroy(script);
2033
2034
        if (nxt_slow_path(ret != NXT_OK)) {
2035
            goto alloc_fail;
2036
        }
2037
2038
        nxt_script_store_get(task, &name, c->mem_pool,
2039
                             nxt_controller_process_script_save, req);
2040
        return;
2041
    }
2042
2043
    if (nxt_str_eq(&req->parser.method, "DELETE", 6)) {
2044
2045
        if (nxt_controller_script_in_use(&name)) {
2046
            goto script_in_use;
2047
        }
2048
2049
        if (nxt_script_info_delete(&name) != NXT_OK) {
2050
            goto script_not_found;
2051
        }
2052
2053
        nxt_script_store_delete(task, &name, c->mem_pool);
2054
2055
        resp.status = 200;
2056
        resp.title = (u_char *) "JS module deleted.";
2057
2058
        nxt_controller_response(task, req, &resp);
2059
        return;
2060
    }
2061
2062
    resp.status = 405;
2063
    resp.title = (u_char *) "Invalid method.";
2064
    resp.offset = -1;
2065
2066
    nxt_controller_response(task, req, &resp);
2067
    return;
2068
2069
invalid_name:
2070
2071
    resp.status = 400;
2072
    resp.title = (u_char *) "Invalid JS module name.";
2073
    resp.offset = -1;
2074
2075
    nxt_controller_response(task, req, &resp);
2076
    return;
2077
2078
invalid_script:
2079
2080
    resp.status = 400;
2081
    resp.title = (u_char *) "Invalid JS module.";
2082
    resp.offset = -1;
2083
2084
    resp.detail.start = error;
2085
    resp.detail.length = nxt_strlen(error);
2086
2087
    nxt_controller_response(task, req, &resp);
2088
    return;
2089
2090
exists_script:
2091
2092
    resp.status = 400;
2093
    resp.title = (u_char *) "JS module already exists.";
2094
    resp.offset = -1;
2095
2096
    nxt_controller_response(task, req, &resp);
2097
    return;
2098
2099
script_in_use:
2100
2101
    resp.status = 400;
2102
    resp.title = (u_char *) "JS module is used in the configuration.";
2103
    resp.offset = -1;
2104
2105
    nxt_controller_response(task, req, &resp);
2106
    return;
2107
2108
script_not_found:
2109
2110
    resp.status = 404;
2111
    resp.title = (u_char *) "JS module doesn't exist.";
2112
    resp.offset = -1;
2113
2114
    nxt_controller_response(task, req, &resp);
2115
    return;
2116
2117
not_found:
2118
2119
    resp.status = 404;
2120
    resp.title = (u_char *) "Invalid path.";
2121
    resp.offset = -1;
2122
2123
    nxt_controller_response(task, req, &resp);
2124
    return;
2125
2126
alloc_fail:
2127
2128
    resp.status = 500;
2129
    resp.title = (u_char *) "Memory allocation failed.";
2130
    resp.offset = -1;
2131
2132
    nxt_controller_response(task, req, &resp);
2133
}
2134
2135
2136
static void
2137
nxt_controller_process_script_save(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2138
    void *data)
2139
{
2140
    nxt_conn_t                 *c;
2141
    nxt_buf_mem_t              *mbuf;
2142
    nxt_controller_request_t   *req;
2143
    nxt_controller_response_t  resp;
2144
2145
    req = data;
2146
2147
    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
2148
2149
    if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) {
2150
        resp.status = 500;
2151
        resp.title = (u_char *) "Failed to store script.";
2152
2153
        nxt_controller_response(task, req, &resp);
2154
        return;
2155
    }
2156
2157
    c = req->conn;
2158
2159
    mbuf = &c->read->mem;
2160
2161
    nxt_fd_write(msg->fd[0], mbuf->pos, nxt_buf_mem_used_size(mbuf));
2162
2163
    nxt_fd_close(msg->fd[0]);
2164
2165
    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
2166
2167
    resp.status = 200;
2168
    resp.title = (u_char *) "JS module uploaded.";
2169
2170
    nxt_controller_response(task, req, &resp);
2171
}
2172
2173
2174
static nxt_bool_t
2175
nxt_controller_script_in_use(nxt_str_t *name)
2176
{
2177
    uint32_t          i, n;
2178
    nxt_str_t         str;
2179
    nxt_conf_value_t  *js_module, *element;
2180
2181
    static nxt_str_t  js_module_path = nxt_string("/settings/js_module");
2182
2183
    js_module = nxt_conf_get_path(nxt_controller_conf.root,
2184
                                    &js_module_path);
2185
2186
    if (js_module != NULL) {
2187
2188
        if (nxt_conf_type(js_module) == NXT_CONF_ARRAY) {
2189
            n = nxt_conf_array_elements_count(js_module);
2190
2191
            for (i = 0; i < n; i++) {
2192
                element = nxt_conf_get_array_element(js_module, i);
2193
2194
                nxt_conf_get_string(element, &str);
2195
2196
                if (nxt_strstr_eq(&str, name)) {
2197
                    return 1;
2198
                }
2199
            }
2200
2201
        } else {
2202
            /* NXT_CONF_STRING */
2203
2204
            nxt_conf_get_string(js_module, &str);
2205
2206
            if (nxt_strstr_eq(&str, name)) {
2207
                return 1;
2208
            }
2209
        }
2210
    }
2211
2212
    return 0;
2213
}
2214
2215
2216
static void
2217
nxt_controller_script_cleanup(nxt_task_t *task, void *obj, void *data)
2218
{
2219
    pid_t          main_pid;
2220
    nxt_array_t    *scripts;
2221
    nxt_runtime_t  *rt;
2222
2223
    scripts = obj;
2224
    rt = data;
2225
2226
    main_pid = rt->port_by_type[NXT_PROCESS_MAIN]->pid;
2227
2228
    if (nxt_pid == main_pid && scripts != NULL) {
2229
        nxt_script_store_release(scripts);
2230
    }
2231
}
2232
2233
#endif
2234
2235
2236
static void
2237
nxt_controller_conf_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2238
    void *data)
2239
0
{
2240
0
    nxt_controller_request_t   *req;
2241
0
    nxt_controller_response_t  resp;
2242
2243
0
    req = data;
2244
2245
0
    nxt_debug(task, "controller conf ready: %*s",
2246
0
              nxt_buf_mem_used_size(&msg->buf->mem), msg->buf->mem.pos);
2247
2248
0
    nxt_queue_remove(&req->link);
2249
2250
0
    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
2251
2252
0
    if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) {
2253
0
        nxt_mp_destroy(nxt_controller_conf.pool);
2254
2255
0
        nxt_controller_conf = req->conf;
2256
2257
0
        nxt_controller_conf_store(task, req->conf.root);
2258
2259
0
        resp.status = 200;
2260
0
        resp.title = (u_char *) "Reconfiguration done.";
2261
2262
0
    } else {
2263
0
        nxt_mp_destroy(req->conf.pool);
2264
2265
0
        resp.status = 500;
2266
0
        resp.title = (u_char *) "Failed to apply new configuration.";
2267
0
        resp.offset = -1;
2268
0
    }
2269
2270
0
    nxt_controller_response(task, req, &resp);
2271
2272
0
    nxt_controller_flush_requests(task);
2273
0
}
2274
2275
2276
static void
2277
nxt_controller_process_control(nxt_task_t *task,
2278
    nxt_controller_request_t *req, nxt_str_t *path)
2279
0
{
2280
0
    uint32_t                   stream;
2281
0
    nxt_buf_t                  *b;
2282
0
    nxt_int_t                  rc;
2283
0
    nxt_port_t                 *router_port, *controller_port;
2284
0
    nxt_runtime_t              *rt;
2285
0
    nxt_conf_value_t           *value;
2286
0
    nxt_controller_response_t  resp;
2287
2288
0
    static nxt_str_t applications = nxt_string("applications");
2289
2290
0
    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
2291
2292
0
    if (!nxt_str_eq(&req->parser.method, "GET", 3)) {
2293
0
        goto not_allowed;
2294
0
    }
2295
2296
0
    if (!nxt_str_start(path, "applications/", 13)
2297
0
        || memcmp(path->start + path->length - 8, "/restart", 8) != 0)
2298
0
    {
2299
0
        goto not_found;
2300
0
    }
2301
2302
0
    path->start += 13;
2303
0
    path->length -= 13 + 8;
2304
2305
0
    if (nxt_controller_check_postpone_request(task)) {
2306
0
        nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link);
2307
0
        return;
2308
0
    }
2309
2310
0
    value = nxt_controller_conf.root;
2311
0
    if (value == NULL) {
2312
0
        goto not_found;
2313
0
    }
2314
2315
0
    value = nxt_conf_get_object_member(value, &applications, NULL);
2316
0
    if (value == NULL) {
2317
0
        goto not_found;
2318
0
    }
2319
2320
0
    value = nxt_conf_get_object_member(value, path, NULL);
2321
0
    if (value == NULL) {
2322
0
        goto not_found;
2323
0
    }
2324
2325
0
    b = nxt_buf_mem_alloc(req->conn->mem_pool, path->length, 0);
2326
0
    if (nxt_slow_path(b == NULL)) {
2327
0
        goto alloc_fail;
2328
0
    }
2329
2330
0
    b->mem.free = nxt_cpymem(b->mem.pos, path->start, path->length);
2331
2332
0
    rt = task->thread->runtime;
2333
2334
0
    controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
2335
0
    router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
2336
2337
0
    stream = nxt_port_rpc_register_handler(task, controller_port,
2338
0
                                           nxt_controller_app_restart_handler,
2339
0
                                           nxt_controller_app_restart_handler,
2340
0
                                           router_port->pid, req);
2341
0
    if (nxt_slow_path(stream == 0)) {
2342
0
        goto alloc_fail;
2343
0
    }
2344
2345
0
    rc = nxt_port_socket_write(task, router_port, NXT_PORT_MSG_APP_RESTART,
2346
0
                               -1, stream, 0, b);
2347
0
    if (nxt_slow_path(rc != NXT_OK)) {
2348
0
        nxt_port_rpc_cancel(task, controller_port, stream);
2349
2350
0
        goto fail;
2351
0
    }
2352
2353
0
    nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link);
2354
2355
0
    return;
2356
2357
0
not_allowed:
2358
2359
0
    resp.status = 405;
2360
0
    resp.title = (u_char *) "Method isn't allowed.";
2361
0
    resp.offset = -1;
2362
2363
0
    nxt_controller_response(task, req, &resp);
2364
0
    return;
2365
2366
0
not_found:
2367
2368
0
    resp.status = 404;
2369
0
    resp.title = (u_char *) "Value doesn't exist.";
2370
0
    resp.offset = -1;
2371
2372
0
    nxt_controller_response(task, req, &resp);
2373
0
    return;
2374
2375
0
alloc_fail:
2376
2377
0
    resp.status = 500;
2378
0
    resp.title = (u_char *) "Memory allocation failed.";
2379
0
    resp.offset = -1;
2380
2381
0
    nxt_controller_response(task, req, &resp);
2382
0
    return;
2383
2384
0
fail:
2385
2386
0
    resp.status = 500;
2387
0
    resp.title = (u_char *) "Send restart failed.";
2388
0
    resp.offset = -1;
2389
2390
0
    nxt_controller_response(task, req, &resp);
2391
0
}
2392
2393
2394
static void
2395
nxt_controller_app_restart_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2396
    void *data)
2397
0
{
2398
0
    nxt_controller_request_t   *req;
2399
0
    nxt_controller_response_t  resp;
2400
2401
0
    req = data;
2402
2403
0
    nxt_debug(task, "controller app restart handler");
2404
2405
0
    nxt_queue_remove(&req->link);
2406
2407
0
    nxt_memzero(&resp, sizeof(nxt_controller_response_t));
2408
2409
0
    if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) {
2410
0
        resp.status = 200;
2411
0
        resp.title = (u_char *) "Ok";
2412
2413
0
    } else {
2414
0
        resp.status = 500;
2415
0
        resp.title = (u_char *) "Failed to restart app.";
2416
0
        resp.offset = -1;
2417
0
    }
2418
2419
0
    nxt_controller_response(task, req, &resp);
2420
2421
0
    nxt_controller_flush_requests(task);
2422
0
}
2423
2424
2425
static void
2426
nxt_controller_conf_store(nxt_task_t *task, nxt_conf_value_t *conf)
2427
0
{
2428
0
    void           *mem;
2429
0
    u_char         *end;
2430
0
    size_t         size;
2431
0
    nxt_fd_t       fd;
2432
0
    nxt_buf_t      *b;
2433
0
    nxt_port_t     *main_port;
2434
0
    nxt_runtime_t  *rt;
2435
2436
0
    rt = task->thread->runtime;
2437
2438
0
    main_port = rt->port_by_type[NXT_PROCESS_MAIN];
2439
2440
0
    size = nxt_conf_json_length(conf, NULL);
2441
2442
0
    fd = nxt_shm_open(task, size);
2443
0
    if (nxt_slow_path(fd == -1)) {
2444
0
        return;
2445
0
    }
2446
2447
0
    mem = nxt_mem_mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
2448
0
    if (nxt_slow_path(mem == MAP_FAILED)) {
2449
0
        goto fail;
2450
0
    }
2451
2452
0
    end = nxt_conf_json_print(mem, conf, NULL);
2453
2454
0
    nxt_mem_munmap(mem, size);
2455
2456
0
    size = end - (u_char *) mem;
2457
2458
0
    b = nxt_buf_mem_alloc(task->thread->engine->mem_pool, sizeof(size_t), 0);
2459
0
    if (nxt_slow_path(b == NULL)) {
2460
0
        goto fail;
2461
0
    }
2462
2463
0
    b->mem.free = nxt_cpymem(b->mem.pos, &size, sizeof(size_t));
2464
2465
0
    (void) nxt_port_socket_write(task, main_port,
2466
0
                                NXT_PORT_MSG_CONF_STORE | NXT_PORT_MSG_CLOSE_FD,
2467
0
                                 fd, 0, -1, b);
2468
2469
0
    return;
2470
2471
0
fail:
2472
2473
0
    nxt_fd_close(fd);
2474
0
}
2475
2476
2477
static void
2478
nxt_controller_response(nxt_task_t *task, nxt_controller_request_t *req,
2479
    nxt_controller_response_t *resp)
2480
0
{
2481
0
    size_t                  size;
2482
0
    nxt_str_t               status_line, str;
2483
0
    nxt_buf_t               *b, *body;
2484
0
    nxt_conn_t              *c;
2485
0
    nxt_uint_t              n;
2486
0
    nxt_conf_value_t        *value, *location;
2487
0
    nxt_conf_json_pretty_t  pretty;
2488
2489
0
    static nxt_str_t  success_str = nxt_string("success");
2490
0
    static nxt_str_t  error_str = nxt_string("error");
2491
0
    static nxt_str_t  detail_str = nxt_string("detail");
2492
0
    static nxt_str_t  location_str = nxt_string("location");
2493
0
    static nxt_str_t  offset_str = nxt_string("offset");
2494
0
    static nxt_str_t  line_str = nxt_string("line");
2495
0
    static nxt_str_t  column_str = nxt_string("column");
2496
2497
0
    static nxt_time_string_t  date_cache = {
2498
0
        (nxt_atomic_uint_t) -1,
2499
0
        nxt_controller_date,
2500
0
        "%s, %02d %s %4d %02d:%02d:%02d GMT",
2501
0
        nxt_length("Wed, 31 Dec 1986 16:40:00 GMT"),
2502
0
        NXT_THREAD_TIME_GMT,
2503
0
        NXT_THREAD_TIME_SEC,
2504
0
    };
2505
2506
0
    switch (resp->status) {
2507
2508
0
    case 200:
2509
0
        nxt_str_set(&status_line, "200 OK");
2510
0
        break;
2511
2512
0
    case 400:
2513
0
        nxt_str_set(&status_line, "400 Bad Request");
2514
0
        break;
2515
2516
0
    case 404:
2517
0
        nxt_str_set(&status_line, "404 Not Found");
2518
0
        break;
2519
2520
0
    case 405:
2521
0
        nxt_str_set(&status_line, "405 Method Not Allowed");
2522
0
        break;
2523
2524
0
    default:
2525
0
        nxt_str_set(&status_line, "500 Internal Server Error");
2526
0
        break;
2527
0
    }
2528
2529
0
    c = req->conn;
2530
0
    value = resp->conf;
2531
2532
0
    if (value == NULL) {
2533
0
        n = 1
2534
0
            + (resp->detail.length != 0)
2535
0
            + (resp->status >= 400 && resp->offset != -1);
2536
2537
0
        value = nxt_conf_create_object(c->mem_pool, n);
2538
2539
0
        if (nxt_slow_path(value == NULL)) {
2540
0
            nxt_controller_conn_close(task, c, req);
2541
0
            return;
2542
0
        }
2543
2544
0
        str.length = nxt_strlen(resp->title);
2545
0
        str.start = resp->title;
2546
2547
0
        if (resp->status < 400) {
2548
0
            nxt_conf_set_member_string(value, &success_str, &str, 0);
2549
2550
0
        } else {
2551
0
            nxt_conf_set_member_string(value, &error_str, &str, 0);
2552
0
        }
2553
2554
0
        n = 0;
2555
2556
0
        if (resp->detail.length != 0) {
2557
0
            n++;
2558
2559
0
            nxt_conf_set_member_string(value, &detail_str, &resp->detail, n);
2560
0
        }
2561
2562
0
        if (resp->status >= 400 && resp->offset != -1) {
2563
0
            n++;
2564
2565
0
            location = nxt_conf_create_object(c->mem_pool,
2566
0
                                              resp->line != 0 ? 3 : 1);
2567
2568
0
            nxt_conf_set_member(value, &location_str, location, n);
2569
2570
0
            nxt_conf_set_member_integer(location, &offset_str, resp->offset, 0);
2571
2572
0
            if (resp->line != 0) {
2573
0
                nxt_conf_set_member_integer(location, &line_str,
2574
0
                                            resp->line, 1);
2575
2576
0
                nxt_conf_set_member_integer(location, &column_str,
2577
0
                                            resp->column, 2);
2578
0
            }
2579
0
        }
2580
0
    }
2581
2582
0
    nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t));
2583
2584
0
    size = nxt_conf_json_length(value, &pretty) + 2;
2585
2586
0
    body = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2587
0
    if (nxt_slow_path(body == NULL)) {
2588
0
        nxt_controller_conn_close(task, c, req);
2589
0
        return;
2590
0
    }
2591
2592
0
    nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t));
2593
2594
0
    body->mem.free = nxt_conf_json_print(body->mem.free, value, &pretty);
2595
2596
0
    body->mem.free = nxt_cpymem(body->mem.free, "\r\n", 2);
2597
2598
0
    size = nxt_length("HTTP/1.1 " "\r\n") + status_line.length
2599
0
           + nxt_length("Server: " NXT_SERVER "\r\n")
2600
0
           + nxt_length("Date: Wed, 31 Dec 1986 16:40:00 GMT\r\n")
2601
0
           + nxt_length("Content-Type: application/json\r\n")
2602
0
           + nxt_length("Content-Length: " "\r\n") + NXT_SIZE_T_LEN
2603
0
           + nxt_length("Connection: close\r\n")
2604
0
           + nxt_length("\r\n");
2605
2606
0
    b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2607
0
    if (nxt_slow_path(b == NULL)) {
2608
0
        nxt_controller_conn_close(task, c, req);
2609
0
        return;
2610
0
    }
2611
2612
0
    b->next = body;
2613
2614
0
    nxt_str_set(&str, "HTTP/1.1 ");
2615
2616
0
    b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length);
2617
0
    b->mem.free = nxt_cpymem(b->mem.free, status_line.start,
2618
0
                             status_line.length);
2619
2620
0
    nxt_str_set(&str, "\r\n"
2621
0
                      "Server: " NXT_SERVER "\r\n"
2622
0
                      "Date: ");
2623
2624
0
    b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length);
2625
2626
0
    b->mem.free = nxt_thread_time_string(task->thread, &date_cache,
2627
0
                                         b->mem.free);
2628
2629
0
    nxt_str_set(&str, "\r\n"
2630
0
                      "Content-Type: application/json\r\n"
2631
0
                      "Content-Length: ");
2632
2633
0
    b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length);
2634
2635
0
    b->mem.free = nxt_sprintf(b->mem.free, b->mem.end, "%uz",
2636
0
                              nxt_buf_mem_used_size(&body->mem));
2637
2638
0
    nxt_str_set(&str, "\r\n"
2639
0
                      "Connection: close\r\n"
2640
0
                      "\r\n");
2641
2642
0
    b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length);
2643
2644
0
    c->write = b;
2645
0
    c->write_state = &nxt_controller_conn_write_state;
2646
2647
0
    nxt_conn_write(task->thread->engine, c);
2648
0
}
2649
2650
2651
static u_char *
2652
nxt_controller_date(u_char *buf, nxt_realtime_t *now, struct tm *tm,
2653
    size_t size, const char *format)
2654
0
{
2655
0
    static const char  *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri",
2656
0
                                   "Sat" };
2657
2658
0
    static const char  *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
2659
0
                                    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
2660
2661
0
    return nxt_sprintf(buf, buf + size, format,
2662
0
                       week[tm->tm_wday], tm->tm_mday,
2663
0
                       month[tm->tm_mon], tm->tm_year + 1900,
2664
0
                       tm->tm_hour, tm->tm_min, tm->tm_sec);
2665
0
}