xref: /unit/src/nxt_application.c (revision 743)
10Sigor@sysoev.ru 
20Sigor@sysoev.ru /*
384Smax.romanov@nginx.com  * Copyright (C) Max Romanov
40Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
50Sigor@sysoev.ru  * Copyright (C) Valentin V. Bartenev
60Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
70Sigor@sysoev.ru  */
80Sigor@sysoev.ru 
90Sigor@sysoev.ru #include <nxt_main.h>
1020Sigor@sysoev.ru #include <nxt_runtime.h>
11240Sigor@sysoev.ru #include <nxt_main_process.h>
12431Sigor@sysoev.ru #include <nxt_router.h>
13431Sigor@sysoev.ru #include <nxt_http.h>
14444Sigor@sysoev.ru #include <nxt_application.h>
15*743Smax.romanov@nginx.com #include <nxt_unit.h>
16723Smax.romanov@nginx.com #include <nxt_port_memory_int.h>
170Sigor@sysoev.ru 
18216Sigor@sysoev.ru #include <glob.h>
190Sigor@sysoev.ru 
20216Sigor@sysoev.ru 
21216Sigor@sysoev.ru typedef struct {
22356Svbart@nginx.com     nxt_app_type_t  type;
23356Svbart@nginx.com     nxt_str_t       version;
24356Svbart@nginx.com     nxt_str_t       file;
25216Sigor@sysoev.ru } nxt_module_t;
26216Sigor@sysoev.ru 
27216Sigor@sysoev.ru 
28216Sigor@sysoev.ru static nxt_buf_t *nxt_discovery_modules(nxt_task_t *task, const char *path);
29216Sigor@sysoev.ru static nxt_int_t nxt_discovery_module(nxt_task_t *task, nxt_mp_t *mp,
30216Sigor@sysoev.ru     nxt_array_t *modules, const char *name);
31549Svbart@nginx.com static void nxt_discovery_completion_handler(nxt_task_t *task, void *obj,
32549Svbart@nginx.com     void *data);
33549Svbart@nginx.com static void nxt_discovery_quit(nxt_task_t *task, nxt_port_recv_msg_t *msg,
34549Svbart@nginx.com     void *data);
35216Sigor@sysoev.ru static nxt_app_module_t *nxt_app_module_load(nxt_task_t *task,
36216Sigor@sysoev.ru     const char *name);
37678Svbart@nginx.com static nxt_int_t nxt_app_set_environment(nxt_conf_value_t *environment);
380Sigor@sysoev.ru 
39431Sigor@sysoev.ru static void nxt_app_http_release(nxt_task_t *task, void *obj, void *data);
400Sigor@sysoev.ru 
41216Sigor@sysoev.ru 
42258Sigor@sysoev.ru static uint32_t  compat[] = {
43360Sigor@sysoev.ru     NXT_VERNUM, NXT_DEBUG,
44258Sigor@sysoev.ru };
45258Sigor@sysoev.ru 
46258Sigor@sysoev.ru 
47673Svbart@nginx.com nxt_str_t  nxt_server = nxt_string(NXT_SERVER);
48673Svbart@nginx.com 
49673Svbart@nginx.com 
50*743Smax.romanov@nginx.com static nxt_app_module_t  *nxt_app;
51417Svbart@nginx.com 
52417Svbart@nginx.com 
53216Sigor@sysoev.ru nxt_int_t
54216Sigor@sysoev.ru nxt_discovery_start(nxt_task_t *task, void *data)
55216Sigor@sysoev.ru {
56549Svbart@nginx.com     uint32_t       stream;
57549Svbart@nginx.com     nxt_buf_t      *b;
58549Svbart@nginx.com     nxt_int_t      ret;
59549Svbart@nginx.com     nxt_port_t     *main_port, *discovery_port;
60549Svbart@nginx.com     nxt_runtime_t  *rt;
61216Sigor@sysoev.ru 
62216Sigor@sysoev.ru     nxt_debug(task, "DISCOVERY");
63216Sigor@sysoev.ru 
64233Sigor@sysoev.ru     rt = task->thread->runtime;
65216Sigor@sysoev.ru 
66233Sigor@sysoev.ru     b = nxt_discovery_modules(task, rt->modules);
67250Sigor@sysoev.ru     if (nxt_slow_path(b == NULL)) {
68549Svbart@nginx.com         return NXT_ERROR;
69250Sigor@sysoev.ru     }
70233Sigor@sysoev.ru 
71240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
72549Svbart@nginx.com     discovery_port = rt->port_by_type[NXT_PROCESS_DISCOVERY];
73216Sigor@sysoev.ru 
74549Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, discovery_port,
75549Svbart@nginx.com                                            nxt_discovery_quit,
76549Svbart@nginx.com                                            nxt_discovery_quit,
77549Svbart@nginx.com                                            main_port->pid, NULL);
78549Svbart@nginx.com 
79645Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
80645Svbart@nginx.com         return NXT_ERROR;
81645Svbart@nginx.com     }
82645Svbart@nginx.com 
83549Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_MODULES, -1,
84549Svbart@nginx.com                                 stream, discovery_port->id, b);
85549Svbart@nginx.com 
86549Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
87549Svbart@nginx.com         nxt_port_rpc_cancel(task, discovery_port, stream);
88549Svbart@nginx.com         return NXT_ERROR;
89549Svbart@nginx.com     }
90216Sigor@sysoev.ru 
91216Sigor@sysoev.ru     return NXT_OK;
92216Sigor@sysoev.ru }
93216Sigor@sysoev.ru 
94216Sigor@sysoev.ru 
95216Sigor@sysoev.ru static nxt_buf_t *
96216Sigor@sysoev.ru nxt_discovery_modules(nxt_task_t *task, const char *path)
97216Sigor@sysoev.ru {
98216Sigor@sysoev.ru     char          *name;
99216Sigor@sysoev.ru     u_char        *p, *end;
100216Sigor@sysoev.ru     size_t        size;
101216Sigor@sysoev.ru     glob_t        glb;
102216Sigor@sysoev.ru     nxt_mp_t      *mp;
103216Sigor@sysoev.ru     nxt_buf_t     *b;
104216Sigor@sysoev.ru     nxt_int_t     ret;
105216Sigor@sysoev.ru     nxt_uint_t    i, n;
106216Sigor@sysoev.ru     nxt_array_t   *modules;
107216Sigor@sysoev.ru     nxt_module_t  *module;
108216Sigor@sysoev.ru 
109216Sigor@sysoev.ru     b = NULL;
110216Sigor@sysoev.ru 
111216Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
112216Sigor@sysoev.ru     if (mp == NULL) {
113216Sigor@sysoev.ru         return b;
114216Sigor@sysoev.ru     }
115216Sigor@sysoev.ru 
116216Sigor@sysoev.ru     ret = glob(path, 0, NULL, &glb);
117216Sigor@sysoev.ru 
118250Sigor@sysoev.ru     n = glb.gl_pathc;
119250Sigor@sysoev.ru 
120250Sigor@sysoev.ru     if (ret != 0) {
121250Sigor@sysoev.ru         nxt_log(task, NXT_LOG_NOTICE,
122250Sigor@sysoev.ru                 "no modules matching: \"%s\" found", path);
123250Sigor@sysoev.ru         n = 0;
124250Sigor@sysoev.ru     }
125216Sigor@sysoev.ru 
126250Sigor@sysoev.ru     modules = nxt_array_create(mp, n, sizeof(nxt_module_t));
127250Sigor@sysoev.ru     if (modules == NULL) {
128250Sigor@sysoev.ru         goto fail;
129250Sigor@sysoev.ru     }
130250Sigor@sysoev.ru 
131250Sigor@sysoev.ru     for (i = 0; i < n; i++) {
132250Sigor@sysoev.ru         name = glb.gl_pathv[i];
133250Sigor@sysoev.ru 
134250Sigor@sysoev.ru         ret = nxt_discovery_module(task, mp, modules, name);
135250Sigor@sysoev.ru         if (ret != NXT_OK) {
136216Sigor@sysoev.ru             goto fail;
137216Sigor@sysoev.ru         }
138250Sigor@sysoev.ru     }
139216Sigor@sysoev.ru 
140703Svbart@nginx.com     size = nxt_length("[]");
141250Sigor@sysoev.ru     module = modules->elts;
142250Sigor@sysoev.ru     n = modules->nelts;
143216Sigor@sysoev.ru 
144250Sigor@sysoev.ru     for (i = 0; i < n; i++) {
145356Svbart@nginx.com         nxt_debug(task, "module: %d %V %V",
146356Svbart@nginx.com                   module[i].type, &module[i].version, &module[i].file);
147216Sigor@sysoev.ru 
148703Svbart@nginx.com         size += nxt_length("{\"type\": ,");
149703Svbart@nginx.com         size += nxt_length(" \"version\": \"\",");
150703Svbart@nginx.com         size += nxt_length(" \"file\": \"\"},");
151216Sigor@sysoev.ru 
152356Svbart@nginx.com         size += NXT_INT_T_LEN
153250Sigor@sysoev.ru                 + module[i].version.length
154250Sigor@sysoev.ru                 + module[i].file.length;
155250Sigor@sysoev.ru     }
156216Sigor@sysoev.ru 
157250Sigor@sysoev.ru     b = nxt_buf_mem_alloc(mp, size, 0);
158250Sigor@sysoev.ru     if (b == NULL) {
159250Sigor@sysoev.ru         goto fail;
160250Sigor@sysoev.ru     }
161216Sigor@sysoev.ru 
162250Sigor@sysoev.ru     b->completion_handler = nxt_discovery_completion_handler;
163216Sigor@sysoev.ru 
164250Sigor@sysoev.ru     p = b->mem.free;
165250Sigor@sysoev.ru     end = b->mem.end;
166250Sigor@sysoev.ru     *p++ = '[';
167216Sigor@sysoev.ru 
168250Sigor@sysoev.ru     for (i = 0; i < n; i++) {
169250Sigor@sysoev.ru         p = nxt_sprintf(p, end,
170356Svbart@nginx.com                       "{\"type\": %d, \"version\": \"%V\", \"file\": \"%V\"},",
171356Svbart@nginx.com                       module[i].type, &module[i].version, &module[i].file);
172250Sigor@sysoev.ru     }
173216Sigor@sysoev.ru 
174250Sigor@sysoev.ru     *p++ = ']';
175250Sigor@sysoev.ru     b->mem.free = p;
176216Sigor@sysoev.ru 
177216Sigor@sysoev.ru fail:
178216Sigor@sysoev.ru 
179216Sigor@sysoev.ru     globfree(&glb);
180216Sigor@sysoev.ru 
181216Sigor@sysoev.ru     return b;
182216Sigor@sysoev.ru }
183216Sigor@sysoev.ru 
184216Sigor@sysoev.ru 
185216Sigor@sysoev.ru static nxt_int_t
186216Sigor@sysoev.ru nxt_discovery_module(nxt_task_t *task, nxt_mp_t *mp, nxt_array_t *modules,
187216Sigor@sysoev.ru     const char *name)
188216Sigor@sysoev.ru {
189*743Smax.romanov@nginx.com     void              *dl;
190*743Smax.romanov@nginx.com     nxt_str_t         version;
191*743Smax.romanov@nginx.com     nxt_int_t         ret;
192*743Smax.romanov@nginx.com     nxt_uint_t        i, n;
193*743Smax.romanov@nginx.com     nxt_module_t      *module;
194*743Smax.romanov@nginx.com     nxt_app_type_t    type;
195*743Smax.romanov@nginx.com     nxt_app_module_t  *app;
196216Sigor@sysoev.ru 
197216Sigor@sysoev.ru     /*
198216Sigor@sysoev.ru      * Only memory allocation failure should return NXT_ERROR.
199216Sigor@sysoev.ru      * Any module processing errors are ignored.
200216Sigor@sysoev.ru      */
201216Sigor@sysoev.ru     ret = NXT_ERROR;
202216Sigor@sysoev.ru 
203216Sigor@sysoev.ru     dl = dlopen(name, RTLD_GLOBAL | RTLD_NOW);
204216Sigor@sysoev.ru 
205216Sigor@sysoev.ru     if (dl == NULL) {
206564Svbart@nginx.com         nxt_alert(task, "dlopen(\"%s\"), failed: \"%s\"", name, dlerror());
207216Sigor@sysoev.ru         return NXT_OK;
208216Sigor@sysoev.ru     }
209216Sigor@sysoev.ru 
210216Sigor@sysoev.ru     app = dlsym(dl, "nxt_app_module");
211216Sigor@sysoev.ru 
212216Sigor@sysoev.ru     if (app != NULL) {
213612Salexander.borisov@nginx.com         nxt_log(task, NXT_LOG_NOTICE, "module: %V %s \"%s\"",
214612Salexander.borisov@nginx.com                 &app->type, app->version, name);
215258Sigor@sysoev.ru 
216258Sigor@sysoev.ru         if (app->compat_length != sizeof(compat)
217258Sigor@sysoev.ru             || nxt_memcmp(app->compat, compat, sizeof(compat)) != 0)
218258Sigor@sysoev.ru         {
219258Sigor@sysoev.ru             nxt_log(task, NXT_LOG_NOTICE, "incompatible module %s", name);
220258Sigor@sysoev.ru 
221258Sigor@sysoev.ru             goto done;
222258Sigor@sysoev.ru         }
223216Sigor@sysoev.ru 
224356Svbart@nginx.com         type = nxt_app_parse_type(app->type.start, app->type.length);
225356Svbart@nginx.com 
226356Svbart@nginx.com         if (type == NXT_APP_UNKNOWN) {
227494Spluknet@nginx.com             nxt_log(task, NXT_LOG_NOTICE, "unknown module type %V", &app->type);
228356Svbart@nginx.com 
229356Svbart@nginx.com             goto done;
230356Svbart@nginx.com         }
231356Svbart@nginx.com 
232216Sigor@sysoev.ru         module = modules->elts;
233216Sigor@sysoev.ru         n = modules->nelts;
234216Sigor@sysoev.ru 
235612Salexander.borisov@nginx.com         version.start = (u_char *) app->version;
236612Salexander.borisov@nginx.com         version.length = nxt_strlen(app->version);
237612Salexander.borisov@nginx.com 
238216Sigor@sysoev.ru         for (i = 0; i < n; i++) {
239356Svbart@nginx.com             if (type == module[i].type
240612Salexander.borisov@nginx.com                 && nxt_strstr_eq(&module[i].version, &version))
241258Sigor@sysoev.ru             {
242216Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_NOTICE,
243216Sigor@sysoev.ru                         "ignoring %s module with the same "
244267Sigor@sysoev.ru                         "application language version %V %V as in %V",
245655Svbart@nginx.com                         name, &app->type, &version, &module[i].file);
246216Sigor@sysoev.ru 
247216Sigor@sysoev.ru                 goto done;
248216Sigor@sysoev.ru             }
249216Sigor@sysoev.ru         }
250216Sigor@sysoev.ru 
251216Sigor@sysoev.ru         module = nxt_array_add(modules);
252216Sigor@sysoev.ru         if (module == NULL) {
253216Sigor@sysoev.ru             goto fail;
254216Sigor@sysoev.ru         }
255216Sigor@sysoev.ru 
256356Svbart@nginx.com         module->type = type;
257216Sigor@sysoev.ru 
258612Salexander.borisov@nginx.com         nxt_str_dup(mp, &module->version, &version);
259612Salexander.borisov@nginx.com         if (module->version.start == NULL) {
260216Sigor@sysoev.ru             goto fail;
261216Sigor@sysoev.ru         }
262216Sigor@sysoev.ru 
263216Sigor@sysoev.ru         module->file.length = nxt_strlen(name);
264216Sigor@sysoev.ru 
265216Sigor@sysoev.ru         module->file.start = nxt_mp_alloc(mp, module->file.length);
266216Sigor@sysoev.ru         if (module->file.start == NULL) {
267216Sigor@sysoev.ru             goto fail;
268216Sigor@sysoev.ru         }
269216Sigor@sysoev.ru 
270216Sigor@sysoev.ru         nxt_memcpy(module->file.start, name, module->file.length);
271216Sigor@sysoev.ru 
272216Sigor@sysoev.ru     } else {
273564Svbart@nginx.com         nxt_alert(task, "dlsym(\"%s\"), failed: \"%s\"", name, dlerror());
274216Sigor@sysoev.ru     }
275216Sigor@sysoev.ru 
276216Sigor@sysoev.ru done:
277216Sigor@sysoev.ru 
278216Sigor@sysoev.ru     ret = NXT_OK;
279216Sigor@sysoev.ru 
280216Sigor@sysoev.ru fail:
281216Sigor@sysoev.ru 
282216Sigor@sysoev.ru     if (dlclose(dl) != 0) {
283564Svbart@nginx.com         nxt_alert(task, "dlclose(\"%s\"), failed: \"%s\"", name, dlerror());
284216Sigor@sysoev.ru     }
285216Sigor@sysoev.ru 
286216Sigor@sysoev.ru     return ret;
287216Sigor@sysoev.ru }
288216Sigor@sysoev.ru 
289216Sigor@sysoev.ru 
290549Svbart@nginx.com static void
291549Svbart@nginx.com nxt_discovery_completion_handler(nxt_task_t *task, void *obj, void *data)
292549Svbart@nginx.com {
293549Svbart@nginx.com     nxt_mp_t   *mp;
294549Svbart@nginx.com     nxt_buf_t  *b;
295549Svbart@nginx.com 
296549Svbart@nginx.com     b = obj;
297549Svbart@nginx.com     mp = b->data;
298549Svbart@nginx.com 
299549Svbart@nginx.com     nxt_mp_destroy(mp);
300549Svbart@nginx.com }
301549Svbart@nginx.com 
302549Svbart@nginx.com 
303549Svbart@nginx.com static void
304549Svbart@nginx.com nxt_discovery_quit(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
305549Svbart@nginx.com {
306549Svbart@nginx.com     nxt_worker_process_quit_handler(task, msg);
307549Svbart@nginx.com }
308549Svbart@nginx.com 
309549Svbart@nginx.com 
3100Sigor@sysoev.ru nxt_int_t
311141Smax.romanov@nginx.com nxt_app_start(nxt_task_t *task, void *data)
3120Sigor@sysoev.ru {
313216Sigor@sysoev.ru     nxt_int_t              ret;
314216Sigor@sysoev.ru     nxt_app_lang_module_t  *lang;
315216Sigor@sysoev.ru     nxt_common_app_conf_t  *app_conf;
316141Smax.romanov@nginx.com 
317141Smax.romanov@nginx.com     app_conf = data;
318141Smax.romanov@nginx.com 
319216Sigor@sysoev.ru     lang = nxt_app_lang_module(task->thread->runtime, &app_conf->type);
320216Sigor@sysoev.ru     if (nxt_slow_path(lang == NULL)) {
321564Svbart@nginx.com         nxt_alert(task, "unknown application type: \"%V\"", &app_conf->type);
322216Sigor@sysoev.ru         return NXT_ERROR;
323216Sigor@sysoev.ru     }
324216Sigor@sysoev.ru 
325216Sigor@sysoev.ru     nxt_app = lang->module;
326216Sigor@sysoev.ru 
327216Sigor@sysoev.ru     if (nxt_app == NULL) {
328354Svbart@nginx.com         nxt_debug(task, "application language module: %s \"%s\"",
329354Svbart@nginx.com                   lang->version, lang->file);
330216Sigor@sysoev.ru 
331216Sigor@sysoev.ru         nxt_app = nxt_app_module_load(task, lang->file);
332216Sigor@sysoev.ru     }
333216Sigor@sysoev.ru 
334277Sigor@sysoev.ru     if (app_conf->working_directory != NULL
335277Sigor@sysoev.ru         && app_conf->working_directory[0] != 0)
336271Smax.romanov@nginx.com     {
337271Smax.romanov@nginx.com         ret = chdir(app_conf->working_directory);
338271Smax.romanov@nginx.com 
339271Smax.romanov@nginx.com         if (nxt_slow_path(ret != 0)) {
340271Smax.romanov@nginx.com             nxt_log(task, NXT_LOG_WARN, "chdir(%s) failed %E",
341271Smax.romanov@nginx.com                     app_conf->working_directory, nxt_errno);
342271Smax.romanov@nginx.com 
343271Smax.romanov@nginx.com             return NXT_ERROR;
344271Smax.romanov@nginx.com         }
345271Smax.romanov@nginx.com     }
346271Smax.romanov@nginx.com 
347678Svbart@nginx.com     if (nxt_slow_path(nxt_app_set_environment(app_conf->environment)
348678Svbart@nginx.com                       != NXT_OK))
349678Svbart@nginx.com     {
350678Svbart@nginx.com         nxt_alert(task, "failed to set environment");
351678Svbart@nginx.com         return NXT_ERROR;
352678Svbart@nginx.com     }
353678Svbart@nginx.com 
354141Smax.romanov@nginx.com     ret = nxt_app->init(task, data);
355141Smax.romanov@nginx.com 
356141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
35784Smax.romanov@nginx.com         nxt_debug(task, "application init failed");
358141Smax.romanov@nginx.com 
359141Smax.romanov@nginx.com     } else {
360141Smax.romanov@nginx.com         nxt_debug(task, "application init done");
36120Sigor@sysoev.ru     }
36220Sigor@sysoev.ru 
363141Smax.romanov@nginx.com     return ret;
36420Sigor@sysoev.ru }
36520Sigor@sysoev.ru 
36620Sigor@sysoev.ru 
367216Sigor@sysoev.ru static nxt_app_module_t *
368216Sigor@sysoev.ru nxt_app_module_load(nxt_task_t *task, const char *name)
369216Sigor@sysoev.ru {
370216Sigor@sysoev.ru     void  *dl;
371216Sigor@sysoev.ru 
372216Sigor@sysoev.ru     dl = dlopen(name, RTLD_GLOBAL | RTLD_LAZY);
373216Sigor@sysoev.ru 
374216Sigor@sysoev.ru     if (dl != NULL) {
375216Sigor@sysoev.ru         return dlsym(dl, "nxt_app_module");
376216Sigor@sysoev.ru     }
377216Sigor@sysoev.ru 
378564Svbart@nginx.com     nxt_alert(task, "dlopen(\"%s\"), failed: \"%s\"", name, dlerror());
379216Sigor@sysoev.ru 
380216Sigor@sysoev.ru     return NULL;
381216Sigor@sysoev.ru }
382216Sigor@sysoev.ru 
383216Sigor@sysoev.ru 
384678Svbart@nginx.com static nxt_int_t
385678Svbart@nginx.com nxt_app_set_environment(nxt_conf_value_t *environment)
386678Svbart@nginx.com {
387678Svbart@nginx.com     char              *env, *p;
388678Svbart@nginx.com     uint32_t          next;
389678Svbart@nginx.com     nxt_str_t         name, value;
390678Svbart@nginx.com     nxt_conf_value_t  *value_obj;
391678Svbart@nginx.com 
392678Svbart@nginx.com     if (environment != NULL) {
393678Svbart@nginx.com         next = 0;
394678Svbart@nginx.com 
395678Svbart@nginx.com         for ( ;; ) {
396678Svbart@nginx.com             value_obj = nxt_conf_next_object_member(environment, &name, &next);
397678Svbart@nginx.com             if (value_obj == NULL) {
398678Svbart@nginx.com                 break;
399678Svbart@nginx.com             }
400678Svbart@nginx.com 
401678Svbart@nginx.com             nxt_conf_get_string(value_obj, &value);
402678Svbart@nginx.com 
403678Svbart@nginx.com             env = nxt_malloc(name.length + value.length + 2);
404678Svbart@nginx.com             if (nxt_slow_path(env == NULL)) {
405678Svbart@nginx.com                 return NXT_ERROR;
406678Svbart@nginx.com             }
407678Svbart@nginx.com 
408678Svbart@nginx.com             p = nxt_cpymem(env, name.start, name.length);
409678Svbart@nginx.com             *p++ = '=';
410678Svbart@nginx.com             p = nxt_cpymem(p, value.start, value.length);
411678Svbart@nginx.com             *p = '\0';
412678Svbart@nginx.com 
413678Svbart@nginx.com             if (nxt_slow_path(putenv(env) != 0)) {
414678Svbart@nginx.com                 return NXT_ERROR;
415678Svbart@nginx.com             }
416678Svbart@nginx.com         }
417678Svbart@nginx.com     }
418678Svbart@nginx.com 
419678Svbart@nginx.com     return NXT_OK;
420678Svbart@nginx.com }
421678Svbart@nginx.com 
422678Svbart@nginx.com 
423431Sigor@sysoev.ru nxt_int_t
424431Sigor@sysoev.ru nxt_app_http_req_done(nxt_task_t *task, nxt_app_parse_ctx_t *ar)
42584Smax.romanov@nginx.com {
426431Sigor@sysoev.ru     ar->timer.handler = nxt_app_http_release;
427431Sigor@sysoev.ru     nxt_timer_add(task->thread->engine, &ar->timer, 0);
42884Smax.romanov@nginx.com 
42984Smax.romanov@nginx.com     return NXT_OK;
43084Smax.romanov@nginx.com }
43184Smax.romanov@nginx.com 
4320Sigor@sysoev.ru 
433431Sigor@sysoev.ru static void
434431Sigor@sysoev.ru nxt_app_http_release(nxt_task_t *task, void *obj, void *data)
43584Smax.romanov@nginx.com {
436431Sigor@sysoev.ru     nxt_timer_t          *timer;
437431Sigor@sysoev.ru     nxt_app_parse_ctx_t  *ar;
438206Smax.romanov@nginx.com 
439431Sigor@sysoev.ru     timer = obj;
440206Smax.romanov@nginx.com 
441431Sigor@sysoev.ru     nxt_debug(task, "http app release");
442206Smax.romanov@nginx.com 
443431Sigor@sysoev.ru     ar = nxt_timer_data(timer, nxt_app_parse_ctx_t, timer);
444206Smax.romanov@nginx.com 
445431Sigor@sysoev.ru     nxt_mp_release(ar->request->mem_pool);
4460Sigor@sysoev.ru }
4470Sigor@sysoev.ru 
4480Sigor@sysoev.ru 
449216Sigor@sysoev.ru nxt_app_lang_module_t *
450216Sigor@sysoev.ru nxt_app_lang_module(nxt_runtime_t *rt, nxt_str_t *name)
451216Sigor@sysoev.ru {
452216Sigor@sysoev.ru     u_char                 *p, *end, *version;
453356Svbart@nginx.com     size_t                 version_length;
454216Sigor@sysoev.ru     nxt_uint_t             i, n;
455356Svbart@nginx.com     nxt_app_type_t         type;
456216Sigor@sysoev.ru     nxt_app_lang_module_t  *lang;
457216Sigor@sysoev.ru 
458216Sigor@sysoev.ru     end = name->start + name->length;
459216Sigor@sysoev.ru     version = end;
460216Sigor@sysoev.ru 
461216Sigor@sysoev.ru     for (p = name->start; p < end; p++) {
462216Sigor@sysoev.ru         if (*p == ' ') {
463216Sigor@sysoev.ru             version = p + 1;
464216Sigor@sysoev.ru             break;
465216Sigor@sysoev.ru         }
466216Sigor@sysoev.ru 
467216Sigor@sysoev.ru         if (*p >= '0' && *p <= '9') {
468216Sigor@sysoev.ru             version = p;
469216Sigor@sysoev.ru             break;
470216Sigor@sysoev.ru         }
471216Sigor@sysoev.ru     }
472216Sigor@sysoev.ru 
473356Svbart@nginx.com     type = nxt_app_parse_type(name->start, p - name->start);
474356Svbart@nginx.com 
475356Svbart@nginx.com     if (type == NXT_APP_UNKNOWN) {
476356Svbart@nginx.com         return NULL;
477356Svbart@nginx.com     }
478356Svbart@nginx.com 
479216Sigor@sysoev.ru     version_length = end - version;
480216Sigor@sysoev.ru 
481216Sigor@sysoev.ru     lang = rt->languages->elts;
482216Sigor@sysoev.ru     n = rt->languages->nelts;
483216Sigor@sysoev.ru 
484216Sigor@sysoev.ru     for (i = 0; i < n; i++) {
485354Svbart@nginx.com 
486354Svbart@nginx.com         /*
487354Svbart@nginx.com          * Versions are sorted in descending order
488354Svbart@nginx.com          * so first match chooses the highest version.
489354Svbart@nginx.com          */
490354Svbart@nginx.com 
491356Svbart@nginx.com         if (lang[i].type == type
492354Svbart@nginx.com             && nxt_strvers_match(lang[i].version, version, version_length))
493216Sigor@sysoev.ru         {
494216Sigor@sysoev.ru             return &lang[i];
495216Sigor@sysoev.ru         }
496216Sigor@sysoev.ru     }
497216Sigor@sysoev.ru 
498216Sigor@sysoev.ru     return NULL;
499216Sigor@sysoev.ru }
500216Sigor@sysoev.ru 
501216Sigor@sysoev.ru 
502510Salexander.borisov@nginx.com nxt_app_type_t
503356Svbart@nginx.com nxt_app_parse_type(u_char *p, size_t length)
504141Smax.romanov@nginx.com {
505356Svbart@nginx.com     nxt_str_t str;
506356Svbart@nginx.com 
507356Svbart@nginx.com     str.length = length;
508356Svbart@nginx.com     str.start = p;
509356Svbart@nginx.com 
510356Svbart@nginx.com     if (nxt_str_eq(&str, "python", 6)) {
511141Smax.romanov@nginx.com         return NXT_APP_PYTHON;
512141Smax.romanov@nginx.com 
513356Svbart@nginx.com     } else if (nxt_str_eq(&str, "php", 3)) {
514141Smax.romanov@nginx.com         return NXT_APP_PHP;
515141Smax.romanov@nginx.com 
516356Svbart@nginx.com     } else if (nxt_str_eq(&str, "go", 2)) {
517141Smax.romanov@nginx.com         return NXT_APP_GO;
518141Smax.romanov@nginx.com 
519510Salexander.borisov@nginx.com     } else if (nxt_str_eq(&str, "perl", 4)) {
520510Salexander.borisov@nginx.com         return NXT_APP_PERL;
521584Salexander.borisov@nginx.com 
522584Salexander.borisov@nginx.com     } else if (nxt_str_eq(&str, "ruby", 4)) {
523584Salexander.borisov@nginx.com         return NXT_APP_RUBY;
524141Smax.romanov@nginx.com     }
525141Smax.romanov@nginx.com 
526141Smax.romanov@nginx.com     return NXT_APP_UNKNOWN;
527141Smax.romanov@nginx.com }
528*743Smax.romanov@nginx.com 
529*743Smax.romanov@nginx.com 
530*743Smax.romanov@nginx.com nxt_int_t
531*743Smax.romanov@nginx.com nxt_unit_default_init(nxt_task_t *task, nxt_unit_init_t *init)
532*743Smax.romanov@nginx.com {
533*743Smax.romanov@nginx.com     nxt_port_t     *my_port, *main_port;
534*743Smax.romanov@nginx.com     nxt_runtime_t  *rt;
535*743Smax.romanov@nginx.com 
536*743Smax.romanov@nginx.com     nxt_memzero(init, sizeof(nxt_unit_init_t));
537*743Smax.romanov@nginx.com 
538*743Smax.romanov@nginx.com     rt = task->thread->runtime;
539*743Smax.romanov@nginx.com 
540*743Smax.romanov@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
541*743Smax.romanov@nginx.com     if (nxt_slow_path(main_port == NULL)) {
542*743Smax.romanov@nginx.com         return NXT_ERROR;
543*743Smax.romanov@nginx.com     }
544*743Smax.romanov@nginx.com 
545*743Smax.romanov@nginx.com     my_port = nxt_runtime_port_find(rt, nxt_pid, 0);
546*743Smax.romanov@nginx.com     if (nxt_slow_path(my_port == NULL)) {
547*743Smax.romanov@nginx.com         return NXT_ERROR;
548*743Smax.romanov@nginx.com     }
549*743Smax.romanov@nginx.com 
550*743Smax.romanov@nginx.com     init->ready_port.id.pid = main_port->pid;
551*743Smax.romanov@nginx.com     init->ready_port.id.id = main_port->id;
552*743Smax.romanov@nginx.com     init->ready_port.out_fd = main_port->pair[1];
553*743Smax.romanov@nginx.com 
554*743Smax.romanov@nginx.com     nxt_fd_blocking(task, main_port->pair[1]);
555*743Smax.romanov@nginx.com 
556*743Smax.romanov@nginx.com     init->ready_stream = my_port->process->init->stream;
557*743Smax.romanov@nginx.com 
558*743Smax.romanov@nginx.com     init->read_port.id.pid = my_port->pid;
559*743Smax.romanov@nginx.com     init->read_port.id.id = my_port->id;
560*743Smax.romanov@nginx.com     init->read_port.in_fd = my_port->pair[0];
561*743Smax.romanov@nginx.com 
562*743Smax.romanov@nginx.com     nxt_fd_blocking(task, my_port->pair[0]);
563*743Smax.romanov@nginx.com 
564*743Smax.romanov@nginx.com     init->log_fd = 2;
565*743Smax.romanov@nginx.com 
566*743Smax.romanov@nginx.com     return NXT_OK;
567*743Smax.romanov@nginx.com }
568