xref: /unit/src/nxt_application.c (revision 564)
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>
150Sigor@sysoev.ru 
16216Sigor@sysoev.ru #include <glob.h>
170Sigor@sysoev.ru 
18216Sigor@sysoev.ru 
19216Sigor@sysoev.ru typedef struct {
20356Svbart@nginx.com     nxt_app_type_t  type;
21356Svbart@nginx.com     nxt_str_t       version;
22356Svbart@nginx.com     nxt_str_t       file;
23216Sigor@sysoev.ru } nxt_module_t;
24216Sigor@sysoev.ru 
25216Sigor@sysoev.ru 
26216Sigor@sysoev.ru static nxt_buf_t *nxt_discovery_modules(nxt_task_t *task, const char *path);
27216Sigor@sysoev.ru static nxt_int_t nxt_discovery_module(nxt_task_t *task, nxt_mp_t *mp,
28216Sigor@sysoev.ru     nxt_array_t *modules, const char *name);
29549Svbart@nginx.com static void nxt_discovery_completion_handler(nxt_task_t *task, void *obj,
30549Svbart@nginx.com     void *data);
31549Svbart@nginx.com static void nxt_discovery_quit(nxt_task_t *task, nxt_port_recv_msg_t *msg,
32549Svbart@nginx.com     void *data);
33216Sigor@sysoev.ru static nxt_app_module_t *nxt_app_module_load(nxt_task_t *task,
34216Sigor@sysoev.ru     const char *name);
350Sigor@sysoev.ru 
36431Sigor@sysoev.ru static void nxt_app_http_release(nxt_task_t *task, void *obj, void *data);
370Sigor@sysoev.ru 
38216Sigor@sysoev.ru 
39258Sigor@sysoev.ru static uint32_t  compat[] = {
40360Sigor@sysoev.ru     NXT_VERNUM, NXT_DEBUG,
41258Sigor@sysoev.ru };
42258Sigor@sysoev.ru 
43258Sigor@sysoev.ru 
44417Svbart@nginx.com static nxt_thread_mutex_t        nxt_app_mutex;
45417Svbart@nginx.com static nxt_thread_cond_t         nxt_app_cond;
46417Svbart@nginx.com 
47417Svbart@nginx.com static nxt_application_module_t  *nxt_app;
48417Svbart@nginx.com 
49417Svbart@nginx.com 
50216Sigor@sysoev.ru nxt_int_t
51216Sigor@sysoev.ru nxt_discovery_start(nxt_task_t *task, void *data)
52216Sigor@sysoev.ru {
53549Svbart@nginx.com     uint32_t       stream;
54549Svbart@nginx.com     nxt_buf_t      *b;
55549Svbart@nginx.com     nxt_int_t      ret;
56549Svbart@nginx.com     nxt_port_t     *main_port, *discovery_port;
57549Svbart@nginx.com     nxt_runtime_t  *rt;
58216Sigor@sysoev.ru 
59216Sigor@sysoev.ru     nxt_debug(task, "DISCOVERY");
60216Sigor@sysoev.ru 
61233Sigor@sysoev.ru     rt = task->thread->runtime;
62216Sigor@sysoev.ru 
63233Sigor@sysoev.ru     b = nxt_discovery_modules(task, rt->modules);
64250Sigor@sysoev.ru     if (nxt_slow_path(b == NULL)) {
65549Svbart@nginx.com         return NXT_ERROR;
66250Sigor@sysoev.ru     }
67233Sigor@sysoev.ru 
68240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
69549Svbart@nginx.com     discovery_port = rt->port_by_type[NXT_PROCESS_DISCOVERY];
70216Sigor@sysoev.ru 
71549Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, discovery_port,
72549Svbart@nginx.com                                            nxt_discovery_quit,
73549Svbart@nginx.com                                            nxt_discovery_quit,
74549Svbart@nginx.com                                            main_port->pid, NULL);
75549Svbart@nginx.com 
76549Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_MODULES, -1,
77549Svbart@nginx.com                                 stream, discovery_port->id, b);
78549Svbart@nginx.com 
79549Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
80549Svbart@nginx.com         nxt_port_rpc_cancel(task, discovery_port, stream);
81549Svbart@nginx.com         return NXT_ERROR;
82549Svbart@nginx.com     }
83216Sigor@sysoev.ru 
84216Sigor@sysoev.ru     return NXT_OK;
85216Sigor@sysoev.ru }
86216Sigor@sysoev.ru 
87216Sigor@sysoev.ru 
88216Sigor@sysoev.ru static nxt_buf_t *
89216Sigor@sysoev.ru nxt_discovery_modules(nxt_task_t *task, const char *path)
90216Sigor@sysoev.ru {
91216Sigor@sysoev.ru     char          *name;
92216Sigor@sysoev.ru     u_char        *p, *end;
93216Sigor@sysoev.ru     size_t        size;
94216Sigor@sysoev.ru     glob_t        glb;
95216Sigor@sysoev.ru     nxt_mp_t      *mp;
96216Sigor@sysoev.ru     nxt_buf_t     *b;
97216Sigor@sysoev.ru     nxt_int_t     ret;
98216Sigor@sysoev.ru     nxt_uint_t    i, n;
99216Sigor@sysoev.ru     nxt_array_t   *modules;
100216Sigor@sysoev.ru     nxt_module_t  *module;
101216Sigor@sysoev.ru 
102216Sigor@sysoev.ru     b = NULL;
103216Sigor@sysoev.ru 
104216Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
105216Sigor@sysoev.ru     if (mp == NULL) {
106216Sigor@sysoev.ru         return b;
107216Sigor@sysoev.ru     }
108216Sigor@sysoev.ru 
109216Sigor@sysoev.ru     ret = glob(path, 0, NULL, &glb);
110216Sigor@sysoev.ru 
111250Sigor@sysoev.ru     n = glb.gl_pathc;
112250Sigor@sysoev.ru 
113250Sigor@sysoev.ru     if (ret != 0) {
114250Sigor@sysoev.ru         nxt_log(task, NXT_LOG_NOTICE,
115250Sigor@sysoev.ru                 "no modules matching: \"%s\" found", path);
116250Sigor@sysoev.ru         n = 0;
117250Sigor@sysoev.ru     }
118216Sigor@sysoev.ru 
119250Sigor@sysoev.ru     modules = nxt_array_create(mp, n, sizeof(nxt_module_t));
120250Sigor@sysoev.ru     if (modules == NULL) {
121250Sigor@sysoev.ru         goto fail;
122250Sigor@sysoev.ru     }
123250Sigor@sysoev.ru 
124250Sigor@sysoev.ru     for (i = 0; i < n; i++) {
125250Sigor@sysoev.ru         name = glb.gl_pathv[i];
126250Sigor@sysoev.ru 
127250Sigor@sysoev.ru         ret = nxt_discovery_module(task, mp, modules, name);
128250Sigor@sysoev.ru         if (ret != NXT_OK) {
129216Sigor@sysoev.ru             goto fail;
130216Sigor@sysoev.ru         }
131250Sigor@sysoev.ru     }
132216Sigor@sysoev.ru 
133250Sigor@sysoev.ru     size = sizeof("[]") - 1;
134250Sigor@sysoev.ru     module = modules->elts;
135250Sigor@sysoev.ru     n = modules->nelts;
136216Sigor@sysoev.ru 
137250Sigor@sysoev.ru     for (i = 0; i < n; i++) {
138356Svbart@nginx.com         nxt_debug(task, "module: %d %V %V",
139356Svbart@nginx.com                   module[i].type, &module[i].version, &module[i].file);
140216Sigor@sysoev.ru 
141356Svbart@nginx.com         size += sizeof("{\"type\": ,") - 1;
142250Sigor@sysoev.ru         size += sizeof(" \"version\": \"\",") - 1;
143250Sigor@sysoev.ru         size += sizeof(" \"file\": \"\"},") - 1;
144216Sigor@sysoev.ru 
145356Svbart@nginx.com         size += NXT_INT_T_LEN
146250Sigor@sysoev.ru                 + module[i].version.length
147250Sigor@sysoev.ru                 + module[i].file.length;
148250Sigor@sysoev.ru     }
149216Sigor@sysoev.ru 
150250Sigor@sysoev.ru     b = nxt_buf_mem_alloc(mp, size, 0);
151250Sigor@sysoev.ru     if (b == NULL) {
152250Sigor@sysoev.ru         goto fail;
153250Sigor@sysoev.ru     }
154216Sigor@sysoev.ru 
155250Sigor@sysoev.ru     b->completion_handler = nxt_discovery_completion_handler;
156216Sigor@sysoev.ru 
157250Sigor@sysoev.ru     p = b->mem.free;
158250Sigor@sysoev.ru     end = b->mem.end;
159250Sigor@sysoev.ru     *p++ = '[';
160216Sigor@sysoev.ru 
161250Sigor@sysoev.ru     for (i = 0; i < n; i++) {
162250Sigor@sysoev.ru         p = nxt_sprintf(p, end,
163356Svbart@nginx.com                       "{\"type\": %d, \"version\": \"%V\", \"file\": \"%V\"},",
164356Svbart@nginx.com                       module[i].type, &module[i].version, &module[i].file);
165250Sigor@sysoev.ru     }
166216Sigor@sysoev.ru 
167250Sigor@sysoev.ru     *p++ = ']';
168250Sigor@sysoev.ru     b->mem.free = p;
169216Sigor@sysoev.ru 
170216Sigor@sysoev.ru fail:
171216Sigor@sysoev.ru 
172216Sigor@sysoev.ru     globfree(&glb);
173216Sigor@sysoev.ru 
174216Sigor@sysoev.ru     return b;
175216Sigor@sysoev.ru }
176216Sigor@sysoev.ru 
177216Sigor@sysoev.ru 
178216Sigor@sysoev.ru static nxt_int_t
179216Sigor@sysoev.ru nxt_discovery_module(nxt_task_t *task, nxt_mp_t *mp, nxt_array_t *modules,
180216Sigor@sysoev.ru     const char *name)
181216Sigor@sysoev.ru {
182216Sigor@sysoev.ru     void                      *dl;
183216Sigor@sysoev.ru     nxt_str_t                 *s;
184216Sigor@sysoev.ru     nxt_int_t                 ret;
185216Sigor@sysoev.ru     nxt_uint_t                i, n;
186216Sigor@sysoev.ru     nxt_module_t              *module;
187356Svbart@nginx.com     nxt_app_type_t            type;
188216Sigor@sysoev.ru     nxt_application_module_t  *app;
189216Sigor@sysoev.ru 
190216Sigor@sysoev.ru     /*
191216Sigor@sysoev.ru      * Only memory allocation failure should return NXT_ERROR.
192216Sigor@sysoev.ru      * Any module processing errors are ignored.
193216Sigor@sysoev.ru      */
194216Sigor@sysoev.ru     ret = NXT_ERROR;
195216Sigor@sysoev.ru 
196216Sigor@sysoev.ru     dl = dlopen(name, RTLD_GLOBAL | RTLD_NOW);
197216Sigor@sysoev.ru 
198216Sigor@sysoev.ru     if (dl == NULL) {
199*564Svbart@nginx.com         nxt_alert(task, "dlopen(\"%s\"), failed: \"%s\"", name, dlerror());
200216Sigor@sysoev.ru         return NXT_OK;
201216Sigor@sysoev.ru     }
202216Sigor@sysoev.ru 
203216Sigor@sysoev.ru     app = dlsym(dl, "nxt_app_module");
204216Sigor@sysoev.ru 
205216Sigor@sysoev.ru     if (app != NULL) {
206258Sigor@sysoev.ru         nxt_log(task, NXT_LOG_NOTICE, "module: %V %V \"%s\"",
207258Sigor@sysoev.ru                 &app->type, &app->version, name);
208258Sigor@sysoev.ru 
209258Sigor@sysoev.ru         if (app->compat_length != sizeof(compat)
210258Sigor@sysoev.ru             || nxt_memcmp(app->compat, compat, sizeof(compat)) != 0)
211258Sigor@sysoev.ru         {
212258Sigor@sysoev.ru             nxt_log(task, NXT_LOG_NOTICE, "incompatible module %s", name);
213258Sigor@sysoev.ru 
214258Sigor@sysoev.ru             goto done;
215258Sigor@sysoev.ru         }
216216Sigor@sysoev.ru 
217356Svbart@nginx.com         type = nxt_app_parse_type(app->type.start, app->type.length);
218356Svbart@nginx.com 
219356Svbart@nginx.com         if (type == NXT_APP_UNKNOWN) {
220494Spluknet@nginx.com             nxt_log(task, NXT_LOG_NOTICE, "unknown module type %V", &app->type);
221356Svbart@nginx.com 
222356Svbart@nginx.com             goto done;
223356Svbart@nginx.com         }
224356Svbart@nginx.com 
225216Sigor@sysoev.ru         module = modules->elts;
226216Sigor@sysoev.ru         n = modules->nelts;
227216Sigor@sysoev.ru 
228216Sigor@sysoev.ru         for (i = 0; i < n; i++) {
229356Svbart@nginx.com             if (type == module[i].type
230258Sigor@sysoev.ru                 && nxt_strstr_eq(&app->version, &module[i].version))
231258Sigor@sysoev.ru             {
232216Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_NOTICE,
233216Sigor@sysoev.ru                         "ignoring %s module with the same "
234267Sigor@sysoev.ru                         "application language version %V %V as in %V",
235356Svbart@nginx.com                         name, &app->type, &app->version,
236258Sigor@sysoev.ru                         &module[i].file);
237216Sigor@sysoev.ru 
238216Sigor@sysoev.ru                 goto done;
239216Sigor@sysoev.ru             }
240216Sigor@sysoev.ru         }
241216Sigor@sysoev.ru 
242216Sigor@sysoev.ru         module = nxt_array_add(modules);
243216Sigor@sysoev.ru         if (module == NULL) {
244216Sigor@sysoev.ru             goto fail;
245216Sigor@sysoev.ru         }
246216Sigor@sysoev.ru 
247356Svbart@nginx.com         module->type = type;
248216Sigor@sysoev.ru 
249216Sigor@sysoev.ru         s = nxt_str_dup(mp, &module->version, &app->version);
250216Sigor@sysoev.ru         if (s == NULL) {
251216Sigor@sysoev.ru             goto fail;
252216Sigor@sysoev.ru         }
253216Sigor@sysoev.ru 
254216Sigor@sysoev.ru         module->file.length = nxt_strlen(name);
255216Sigor@sysoev.ru 
256216Sigor@sysoev.ru         module->file.start = nxt_mp_alloc(mp, module->file.length);
257216Sigor@sysoev.ru         if (module->file.start == NULL) {
258216Sigor@sysoev.ru             goto fail;
259216Sigor@sysoev.ru         }
260216Sigor@sysoev.ru 
261216Sigor@sysoev.ru         nxt_memcpy(module->file.start, name, module->file.length);
262216Sigor@sysoev.ru 
263216Sigor@sysoev.ru     } else {
264*564Svbart@nginx.com         nxt_alert(task, "dlsym(\"%s\"), failed: \"%s\"", name, dlerror());
265216Sigor@sysoev.ru     }
266216Sigor@sysoev.ru 
267216Sigor@sysoev.ru done:
268216Sigor@sysoev.ru 
269216Sigor@sysoev.ru     ret = NXT_OK;
270216Sigor@sysoev.ru 
271216Sigor@sysoev.ru fail:
272216Sigor@sysoev.ru 
273216Sigor@sysoev.ru     if (dlclose(dl) != 0) {
274*564Svbart@nginx.com         nxt_alert(task, "dlclose(\"%s\"), failed: \"%s\"", name, dlerror());
275216Sigor@sysoev.ru     }
276216Sigor@sysoev.ru 
277216Sigor@sysoev.ru     return ret;
278216Sigor@sysoev.ru }
279216Sigor@sysoev.ru 
280216Sigor@sysoev.ru 
281549Svbart@nginx.com static void
282549Svbart@nginx.com nxt_discovery_completion_handler(nxt_task_t *task, void *obj, void *data)
283549Svbart@nginx.com {
284549Svbart@nginx.com     nxt_mp_t   *mp;
285549Svbart@nginx.com     nxt_buf_t  *b;
286549Svbart@nginx.com 
287549Svbart@nginx.com     b = obj;
288549Svbart@nginx.com     mp = b->data;
289549Svbart@nginx.com 
290549Svbart@nginx.com     nxt_mp_destroy(mp);
291549Svbart@nginx.com }
292549Svbart@nginx.com 
293549Svbart@nginx.com 
294549Svbart@nginx.com static void
295549Svbart@nginx.com nxt_discovery_quit(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
296549Svbart@nginx.com {
297549Svbart@nginx.com     nxt_worker_process_quit_handler(task, msg);
298549Svbart@nginx.com }
299549Svbart@nginx.com 
300549Svbart@nginx.com 
3010Sigor@sysoev.ru nxt_int_t
302141Smax.romanov@nginx.com nxt_app_start(nxt_task_t *task, void *data)
3030Sigor@sysoev.ru {
304216Sigor@sysoev.ru     nxt_int_t              ret;
305216Sigor@sysoev.ru     nxt_app_lang_module_t  *lang;
306216Sigor@sysoev.ru     nxt_common_app_conf_t  *app_conf;
307141Smax.romanov@nginx.com 
308141Smax.romanov@nginx.com     app_conf = data;
309141Smax.romanov@nginx.com 
310216Sigor@sysoev.ru     lang = nxt_app_lang_module(task->thread->runtime, &app_conf->type);
311216Sigor@sysoev.ru     if (nxt_slow_path(lang == NULL)) {
312*564Svbart@nginx.com         nxt_alert(task, "unknown application type: \"%V\"", &app_conf->type);
313216Sigor@sysoev.ru         return NXT_ERROR;
314216Sigor@sysoev.ru     }
315216Sigor@sysoev.ru 
316216Sigor@sysoev.ru     nxt_app = lang->module;
317216Sigor@sysoev.ru 
318216Sigor@sysoev.ru     if (nxt_app == NULL) {
319354Svbart@nginx.com         nxt_debug(task, "application language module: %s \"%s\"",
320354Svbart@nginx.com                   lang->version, lang->file);
321216Sigor@sysoev.ru 
322216Sigor@sysoev.ru         nxt_app = nxt_app_module_load(task, lang->file);
323216Sigor@sysoev.ru     }
324216Sigor@sysoev.ru 
325277Sigor@sysoev.ru     if (app_conf->working_directory != NULL
326277Sigor@sysoev.ru         && app_conf->working_directory[0] != 0)
327271Smax.romanov@nginx.com     {
328271Smax.romanov@nginx.com         ret = chdir(app_conf->working_directory);
329271Smax.romanov@nginx.com 
330271Smax.romanov@nginx.com         if (nxt_slow_path(ret != 0)) {
331271Smax.romanov@nginx.com             nxt_log(task, NXT_LOG_WARN, "chdir(%s) failed %E",
332271Smax.romanov@nginx.com                     app_conf->working_directory, nxt_errno);
333271Smax.romanov@nginx.com 
334271Smax.romanov@nginx.com             return NXT_ERROR;
335271Smax.romanov@nginx.com         }
336271Smax.romanov@nginx.com     }
337271Smax.romanov@nginx.com 
3380Sigor@sysoev.ru     if (nxt_slow_path(nxt_thread_mutex_create(&nxt_app_mutex) != NXT_OK)) {
3390Sigor@sysoev.ru         return NXT_ERROR;
3400Sigor@sysoev.ru     }
3410Sigor@sysoev.ru 
3420Sigor@sysoev.ru     if (nxt_slow_path(nxt_thread_cond_create(&nxt_app_cond) != NXT_OK)) {
3430Sigor@sysoev.ru         return NXT_ERROR;
3440Sigor@sysoev.ru     }
3450Sigor@sysoev.ru 
346141Smax.romanov@nginx.com     ret = nxt_app->init(task, data);
347141Smax.romanov@nginx.com 
348141Smax.romanov@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
34984Smax.romanov@nginx.com         nxt_debug(task, "application init failed");
350141Smax.romanov@nginx.com 
351141Smax.romanov@nginx.com     } else {
352141Smax.romanov@nginx.com         nxt_debug(task, "application init done");
35320Sigor@sysoev.ru     }
35420Sigor@sysoev.ru 
355141Smax.romanov@nginx.com     return ret;
35620Sigor@sysoev.ru }
35720Sigor@sysoev.ru 
35820Sigor@sysoev.ru 
359216Sigor@sysoev.ru static nxt_app_module_t *
360216Sigor@sysoev.ru nxt_app_module_load(nxt_task_t *task, const char *name)
361216Sigor@sysoev.ru {
362216Sigor@sysoev.ru     void  *dl;
363216Sigor@sysoev.ru 
364216Sigor@sysoev.ru     dl = dlopen(name, RTLD_GLOBAL | RTLD_LAZY);
365216Sigor@sysoev.ru 
366216Sigor@sysoev.ru     if (dl != NULL) {
367216Sigor@sysoev.ru         return dlsym(dl, "nxt_app_module");
368216Sigor@sysoev.ru     }
369216Sigor@sysoev.ru 
370*564Svbart@nginx.com     nxt_alert(task, "dlopen(\"%s\"), failed: \"%s\"", name, dlerror());
371216Sigor@sysoev.ru 
372216Sigor@sysoev.ru     return NULL;
373216Sigor@sysoev.ru }
374216Sigor@sysoev.ru 
375216Sigor@sysoev.ru 
37684Smax.romanov@nginx.com void
377421Smax.romanov@nginx.com nxt_app_quit_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
378421Smax.romanov@nginx.com {
379421Smax.romanov@nginx.com     if (nxt_app->atexit != NULL) {
380421Smax.romanov@nginx.com         nxt_app->atexit(task);
381421Smax.romanov@nginx.com     }
382421Smax.romanov@nginx.com 
383421Smax.romanov@nginx.com     nxt_worker_process_quit_handler(task, msg);
384421Smax.romanov@nginx.com }
385421Smax.romanov@nginx.com 
386421Smax.romanov@nginx.com 
387421Smax.romanov@nginx.com void
388421Smax.romanov@nginx.com nxt_app_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
38984Smax.romanov@nginx.com {
39084Smax.romanov@nginx.com     size_t          dump_size;
39184Smax.romanov@nginx.com     nxt_buf_t       *b;
39284Smax.romanov@nginx.com     nxt_port_t      *port;
39384Smax.romanov@nginx.com     nxt_app_rmsg_t  rmsg = { msg->buf };
39484Smax.romanov@nginx.com     nxt_app_wmsg_t  wmsg;
3950Sigor@sysoev.ru 
39684Smax.romanov@nginx.com     b = msg->buf;
39784Smax.romanov@nginx.com     dump_size = b->mem.free - b->mem.pos;
3980Sigor@sysoev.ru 
39984Smax.romanov@nginx.com     if (dump_size > 300) {
40084Smax.romanov@nginx.com         dump_size = 300;
40184Smax.romanov@nginx.com     }
4020Sigor@sysoev.ru 
40384Smax.romanov@nginx.com     nxt_debug(task, "app data: %*s ...", dump_size, b->mem.pos);
4040Sigor@sysoev.ru 
40584Smax.romanov@nginx.com     port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid,
40684Smax.romanov@nginx.com                                  msg->port_msg.reply_port);
40784Smax.romanov@nginx.com     if (nxt_slow_path(port == NULL)) {
408423Smax.romanov@nginx.com         nxt_debug(task, "stream #%uD: reply port %d not found",
409423Smax.romanov@nginx.com                   msg->port_msg.stream, msg->port_msg.reply_port);
410423Smax.romanov@nginx.com         return;
41184Smax.romanov@nginx.com     }
4124Sigor@sysoev.ru 
41384Smax.romanov@nginx.com     wmsg.port = port;
41484Smax.romanov@nginx.com     wmsg.write = NULL;
41584Smax.romanov@nginx.com     wmsg.buf = &wmsg.write;
41684Smax.romanov@nginx.com     wmsg.stream = msg->port_msg.stream;
4170Sigor@sysoev.ru 
41884Smax.romanov@nginx.com     nxt_app->run(task, &rmsg, &wmsg);
4190Sigor@sysoev.ru }
4200Sigor@sysoev.ru 
4210Sigor@sysoev.ru 
42284Smax.romanov@nginx.com u_char *
42384Smax.romanov@nginx.com nxt_app_msg_write_get_buf(nxt_task_t *task, nxt_app_wmsg_t *msg, size_t size)
42484Smax.romanov@nginx.com {
42584Smax.romanov@nginx.com     size_t      free_size;
42684Smax.romanov@nginx.com     u_char      *res;
42784Smax.romanov@nginx.com     nxt_buf_t   *b;
4280Sigor@sysoev.ru 
42984Smax.romanov@nginx.com     res = NULL;
43084Smax.romanov@nginx.com 
43184Smax.romanov@nginx.com     do {
43284Smax.romanov@nginx.com         b = *msg->buf;
4330Sigor@sysoev.ru 
43484Smax.romanov@nginx.com         if (b == NULL) {
435423Smax.romanov@nginx.com             b = nxt_port_mmap_get_buf(task, msg->port, size);
43684Smax.romanov@nginx.com             if (nxt_slow_path(b == NULL)) {
43784Smax.romanov@nginx.com                 return NULL;
43884Smax.romanov@nginx.com             }
4390Sigor@sysoev.ru 
44084Smax.romanov@nginx.com             *msg->buf = b;
44184Smax.romanov@nginx.com 
44284Smax.romanov@nginx.com             free_size = nxt_buf_mem_free_size(&b->mem);
4430Sigor@sysoev.ru 
44484Smax.romanov@nginx.com             if (nxt_slow_path(free_size < size)) {
445273Smax.romanov@nginx.com                 nxt_log(task, NXT_LOG_WARN, "requested buffer too big "
446273Smax.romanov@nginx.com                         "(%z < %z)", free_size, size);
44784Smax.romanov@nginx.com                 return NULL;
44884Smax.romanov@nginx.com             }
44984Smax.romanov@nginx.com 
45084Smax.romanov@nginx.com         }
45184Smax.romanov@nginx.com 
45284Smax.romanov@nginx.com         free_size = nxt_buf_mem_free_size(&b->mem);
4530Sigor@sysoev.ru 
45484Smax.romanov@nginx.com         if (free_size >= size) {
45584Smax.romanov@nginx.com             res = b->mem.free;
45684Smax.romanov@nginx.com             b->mem.free += size;
45784Smax.romanov@nginx.com 
45884Smax.romanov@nginx.com             return res;
45984Smax.romanov@nginx.com         }
4601Sigor@sysoev.ru 
461206Smax.romanov@nginx.com         if (nxt_port_mmap_increase_buf(task, b, size, size) == NXT_OK) {
46284Smax.romanov@nginx.com             res = b->mem.free;
46384Smax.romanov@nginx.com             b->mem.free += size;
4640Sigor@sysoev.ru 
46584Smax.romanov@nginx.com             return res;
46684Smax.romanov@nginx.com         }
46784Smax.romanov@nginx.com 
46884Smax.romanov@nginx.com         msg->buf = &b->next;
46984Smax.romanov@nginx.com     } while(1);
4700Sigor@sysoev.ru }
4710Sigor@sysoev.ru 
4720Sigor@sysoev.ru 
47384Smax.romanov@nginx.com nxt_int_t
47484Smax.romanov@nginx.com nxt_app_msg_write(nxt_task_t *task, nxt_app_wmsg_t *msg, u_char *c, size_t size)
4750Sigor@sysoev.ru {
47684Smax.romanov@nginx.com     u_char  *dst;
47784Smax.romanov@nginx.com     size_t  dst_length;
4780Sigor@sysoev.ru 
47984Smax.romanov@nginx.com     if (c != NULL) {
48084Smax.romanov@nginx.com         dst_length = size + (size < 128 ? 1 : 4) + 1;
4810Sigor@sysoev.ru 
48284Smax.romanov@nginx.com         dst = nxt_app_msg_write_get_buf(task, msg, dst_length);
48384Smax.romanov@nginx.com         if (nxt_slow_path(dst == NULL)) {
48484Smax.romanov@nginx.com             nxt_debug(task, "nxt_app_msg_write: get_buf(%uz) failed",
48584Smax.romanov@nginx.com                       dst_length);
48684Smax.romanov@nginx.com             return NXT_ERROR;
4870Sigor@sysoev.ru         }
4880Sigor@sysoev.ru 
48984Smax.romanov@nginx.com         dst = nxt_app_msg_write_length(dst, size + 1); /* +1 for trailing 0 */
4900Sigor@sysoev.ru 
49184Smax.romanov@nginx.com         nxt_memcpy(dst, c, size);
49284Smax.romanov@nginx.com         dst[size] = 0;
4930Sigor@sysoev.ru 
494493Spluknet@nginx.com         nxt_debug(task, "nxt_app_msg_write: %uz %*s", size, size, c);
495493Spluknet@nginx.com 
49684Smax.romanov@nginx.com     } else {
49784Smax.romanov@nginx.com         dst_length = 1;
4980Sigor@sysoev.ru 
49984Smax.romanov@nginx.com         dst = nxt_app_msg_write_get_buf(task, msg, dst_length);
50084Smax.romanov@nginx.com         if (nxt_slow_path(dst == NULL)) {
50184Smax.romanov@nginx.com             nxt_debug(task, "nxt_app_msg_write: get_buf(%uz) failed",
50284Smax.romanov@nginx.com                       dst_length);
50384Smax.romanov@nginx.com             return NXT_ERROR;
5040Sigor@sysoev.ru         }
5050Sigor@sysoev.ru 
50684Smax.romanov@nginx.com         dst = nxt_app_msg_write_length(dst, 0);
50784Smax.romanov@nginx.com 
50884Smax.romanov@nginx.com         nxt_debug(task, "nxt_app_msg_write: NULL");
5090Sigor@sysoev.ru     }
5100Sigor@sysoev.ru 
51184Smax.romanov@nginx.com     return NXT_OK;
5120Sigor@sysoev.ru }
5130Sigor@sysoev.ru 
5140Sigor@sysoev.ru 
51584Smax.romanov@nginx.com nxt_int_t
51684Smax.romanov@nginx.com nxt_app_msg_write_prefixed_upcase(nxt_task_t *task, nxt_app_wmsg_t *msg,
517417Svbart@nginx.com     const nxt_str_t *prefix, u_char *c, size_t size)
5180Sigor@sysoev.ru {
51984Smax.romanov@nginx.com     u_char  *dst, *src;
52084Smax.romanov@nginx.com     size_t  i, length, dst_length;
52184Smax.romanov@nginx.com 
522417Svbart@nginx.com     length = prefix->length + size;
5230Sigor@sysoev.ru 
52484Smax.romanov@nginx.com     dst_length = length + (length < 128 ? 1 : 4) + 1;
52584Smax.romanov@nginx.com 
52684Smax.romanov@nginx.com     dst = nxt_app_msg_write_get_buf(task, msg, dst_length);
52784Smax.romanov@nginx.com     if (nxt_slow_path(dst == NULL)) {
52884Smax.romanov@nginx.com         return NXT_ERROR;
5290Sigor@sysoev.ru     }
5300Sigor@sysoev.ru 
53184Smax.romanov@nginx.com     dst = nxt_app_msg_write_length(dst, length + 1); /* +1 for trailing 0 */
53284Smax.romanov@nginx.com 
53384Smax.romanov@nginx.com     nxt_memcpy(dst, prefix->start, prefix->length);
53484Smax.romanov@nginx.com     dst += prefix->length;
5350Sigor@sysoev.ru 
536417Svbart@nginx.com     src = c;
537417Svbart@nginx.com     for (i = 0; i < size; i++, dst++, src++) {
53884Smax.romanov@nginx.com 
53984Smax.romanov@nginx.com         if (*src >= 'a' && *src <= 'z') {
54084Smax.romanov@nginx.com             *dst = *src & ~0x20;
54184Smax.romanov@nginx.com             continue;
5420Sigor@sysoev.ru         }
5430Sigor@sysoev.ru 
54484Smax.romanov@nginx.com         if (*src == '-') {
54584Smax.romanov@nginx.com             *dst = '_';
54684Smax.romanov@nginx.com             continue;
5470Sigor@sysoev.ru         }
5480Sigor@sysoev.ru 
54984Smax.romanov@nginx.com         *dst = *src;
5500Sigor@sysoev.ru     }
5510Sigor@sysoev.ru 
55284Smax.romanov@nginx.com     *dst = 0;
5530Sigor@sysoev.ru 
55484Smax.romanov@nginx.com     return NXT_OK;
5550Sigor@sysoev.ru }
5560Sigor@sysoev.ru 
5570Sigor@sysoev.ru 
558423Smax.romanov@nginx.com nxt_inline nxt_int_t
559423Smax.romanov@nginx.com nxt_app_msg_read_size_(nxt_task_t *task, nxt_app_rmsg_t *msg, size_t *size)
5600Sigor@sysoev.ru {
56184Smax.romanov@nginx.com     nxt_buf_t  *buf;
5620Sigor@sysoev.ru 
56384Smax.romanov@nginx.com     do {
56484Smax.romanov@nginx.com         buf = msg->buf;
56584Smax.romanov@nginx.com 
56684Smax.romanov@nginx.com         if (nxt_slow_path(buf == NULL)) {
56784Smax.romanov@nginx.com             return NXT_DONE;
5680Sigor@sysoev.ru         }
5690Sigor@sysoev.ru 
57084Smax.romanov@nginx.com         if (nxt_slow_path(nxt_buf_mem_used_size(&buf->mem) < 1)) {
57184Smax.romanov@nginx.com             if (nxt_fast_path(nxt_buf_mem_used_size(&buf->mem) == 0)) {
57284Smax.romanov@nginx.com                 msg->buf = buf->next;
57384Smax.romanov@nginx.com                 continue;
57484Smax.romanov@nginx.com             }
57584Smax.romanov@nginx.com             return NXT_ERROR;
5760Sigor@sysoev.ru         }
5770Sigor@sysoev.ru 
57884Smax.romanov@nginx.com         if (buf->mem.pos[0] >= 128) {
57984Smax.romanov@nginx.com             if (nxt_slow_path(nxt_buf_mem_used_size(&buf->mem) < 4)) {
58084Smax.romanov@nginx.com                 return NXT_ERROR;
58184Smax.romanov@nginx.com             }
58284Smax.romanov@nginx.com         }
5830Sigor@sysoev.ru 
58484Smax.romanov@nginx.com         break;
58584Smax.romanov@nginx.com     } while (1);
5860Sigor@sysoev.ru 
587423Smax.romanov@nginx.com     buf->mem.pos = nxt_app_msg_read_length(buf->mem.pos, size);
588423Smax.romanov@nginx.com 
589423Smax.romanov@nginx.com     return NXT_OK;
590423Smax.romanov@nginx.com }
591423Smax.romanov@nginx.com 
592423Smax.romanov@nginx.com 
593423Smax.romanov@nginx.com nxt_int_t
594423Smax.romanov@nginx.com nxt_app_msg_read_str(nxt_task_t *task, nxt_app_rmsg_t *msg, nxt_str_t *str)
595423Smax.romanov@nginx.com {
596423Smax.romanov@nginx.com     size_t      length;
597423Smax.romanov@nginx.com     nxt_int_t   ret;
598423Smax.romanov@nginx.com     nxt_buf_t  *buf;
599423Smax.romanov@nginx.com 
600423Smax.romanov@nginx.com     ret = nxt_app_msg_read_size_(task, msg, &length);
601423Smax.romanov@nginx.com     if (ret != NXT_OK) {
602423Smax.romanov@nginx.com         return ret;
603423Smax.romanov@nginx.com     }
604423Smax.romanov@nginx.com 
605423Smax.romanov@nginx.com     buf = msg->buf;
60684Smax.romanov@nginx.com 
607277Sigor@sysoev.ru     if (nxt_slow_path(nxt_buf_mem_used_size(&buf->mem) < (intptr_t) length)) {
60884Smax.romanov@nginx.com         return NXT_ERROR;
6090Sigor@sysoev.ru     }
6100Sigor@sysoev.ru 
61184Smax.romanov@nginx.com     if (length > 0) {
61284Smax.romanov@nginx.com         str->start = buf->mem.pos;
61384Smax.romanov@nginx.com         str->length = length - 1;
6140Sigor@sysoev.ru 
61584Smax.romanov@nginx.com         buf->mem.pos += length;
6160Sigor@sysoev.ru 
617493Spluknet@nginx.com         nxt_debug(task, "nxt_read_str: %uz %*s", length - 1,
618493Spluknet@nginx.com                         length - 1, str->start);
619493Spluknet@nginx.com 
62084Smax.romanov@nginx.com     } else {
62184Smax.romanov@nginx.com         str->start = NULL;
62284Smax.romanov@nginx.com         str->length = 0;
6230Sigor@sysoev.ru 
62484Smax.romanov@nginx.com         nxt_debug(task, "nxt_read_str: NULL");
6250Sigor@sysoev.ru     }
6260Sigor@sysoev.ru 
6270Sigor@sysoev.ru     return NXT_OK;
6280Sigor@sysoev.ru }
6290Sigor@sysoev.ru 
6300Sigor@sysoev.ru 
631206Smax.romanov@nginx.com size_t
632206Smax.romanov@nginx.com nxt_app_msg_read_raw(nxt_task_t *task, nxt_app_rmsg_t *msg, void *dst,
633206Smax.romanov@nginx.com     size_t size)
634206Smax.romanov@nginx.com {
635206Smax.romanov@nginx.com     size_t     res, read_size;
636206Smax.romanov@nginx.com     nxt_buf_t  *buf;
637206Smax.romanov@nginx.com 
638206Smax.romanov@nginx.com     res = 0;
639206Smax.romanov@nginx.com 
640206Smax.romanov@nginx.com     while (size > 0) {
641206Smax.romanov@nginx.com         buf = msg->buf;
642206Smax.romanov@nginx.com 
643206Smax.romanov@nginx.com         if (nxt_slow_path(buf == NULL)) {
644206Smax.romanov@nginx.com             break;
645206Smax.romanov@nginx.com         }
646206Smax.romanov@nginx.com 
647206Smax.romanov@nginx.com         if (nxt_slow_path(nxt_buf_mem_used_size(&buf->mem) == 0)) {
648206Smax.romanov@nginx.com             msg->buf = buf->next;
649206Smax.romanov@nginx.com             continue;
650206Smax.romanov@nginx.com         }
651206Smax.romanov@nginx.com 
652206Smax.romanov@nginx.com         read_size = nxt_buf_mem_used_size(&buf->mem);
653206Smax.romanov@nginx.com         read_size = nxt_min(read_size, size);
654206Smax.romanov@nginx.com 
655206Smax.romanov@nginx.com         dst = nxt_cpymem(dst, buf->mem.pos, read_size);
656206Smax.romanov@nginx.com 
657206Smax.romanov@nginx.com         size -= read_size;
658206Smax.romanov@nginx.com         buf->mem.pos += read_size;
659206Smax.romanov@nginx.com         res += read_size;
660206Smax.romanov@nginx.com     }
661206Smax.romanov@nginx.com 
662206Smax.romanov@nginx.com     nxt_debug(task, "nxt_read_raw: %uz", res);
663206Smax.romanov@nginx.com 
664206Smax.romanov@nginx.com     return res;
665206Smax.romanov@nginx.com }
666206Smax.romanov@nginx.com 
667206Smax.romanov@nginx.com 
66884Smax.romanov@nginx.com nxt_int_t
66984Smax.romanov@nginx.com nxt_app_msg_read_nvp(nxt_task_t *task, nxt_app_rmsg_t *rmsg, nxt_str_t *n,
67084Smax.romanov@nginx.com     nxt_str_t *v)
6710Sigor@sysoev.ru {
67284Smax.romanov@nginx.com     nxt_int_t rc;
6730Sigor@sysoev.ru 
67484Smax.romanov@nginx.com     rc = nxt_app_msg_read_str(task, rmsg, n);
67584Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
67684Smax.romanov@nginx.com         return rc;
6770Sigor@sysoev.ru     }
6780Sigor@sysoev.ru 
67984Smax.romanov@nginx.com     rc = nxt_app_msg_read_str(task, rmsg, v);
68084Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
68184Smax.romanov@nginx.com         return rc;
68284Smax.romanov@nginx.com     }
6830Sigor@sysoev.ru 
68484Smax.romanov@nginx.com     return rc;
6850Sigor@sysoev.ru }
6860Sigor@sysoev.ru 
6870Sigor@sysoev.ru 
6880Sigor@sysoev.ru nxt_int_t
68984Smax.romanov@nginx.com nxt_app_msg_read_size(nxt_task_t *task, nxt_app_rmsg_t *msg, size_t *size)
6900Sigor@sysoev.ru {
691423Smax.romanov@nginx.com     nxt_int_t  ret;
6920Sigor@sysoev.ru 
693423Smax.romanov@nginx.com     ret = nxt_app_msg_read_size_(task, msg, size);
69484Smax.romanov@nginx.com 
695277Sigor@sysoev.ru     nxt_debug(task, "nxt_read_size: %d", (int) *size);
6960Sigor@sysoev.ru 
697423Smax.romanov@nginx.com     return ret;
6980Sigor@sysoev.ru }
6990Sigor@sysoev.ru 
7000Sigor@sysoev.ru 
701431Sigor@sysoev.ru nxt_int_t
702431Sigor@sysoev.ru nxt_app_http_req_done(nxt_task_t *task, nxt_app_parse_ctx_t *ar)
70384Smax.romanov@nginx.com {
704431Sigor@sysoev.ru     ar->timer.handler = nxt_app_http_release;
705431Sigor@sysoev.ru     nxt_timer_add(task->thread->engine, &ar->timer, 0);
70684Smax.romanov@nginx.com 
70784Smax.romanov@nginx.com     return NXT_OK;
70884Smax.romanov@nginx.com }
70984Smax.romanov@nginx.com 
7100Sigor@sysoev.ru 
711431Sigor@sysoev.ru static void
712431Sigor@sysoev.ru nxt_app_http_release(nxt_task_t *task, void *obj, void *data)
71384Smax.romanov@nginx.com {
714431Sigor@sysoev.ru     nxt_timer_t          *timer;
715431Sigor@sysoev.ru     nxt_app_parse_ctx_t  *ar;
716206Smax.romanov@nginx.com 
717431Sigor@sysoev.ru     timer = obj;
718206Smax.romanov@nginx.com 
719431Sigor@sysoev.ru     nxt_debug(task, "http app release");
720206Smax.romanov@nginx.com 
721431Sigor@sysoev.ru     ar = nxt_timer_data(timer, nxt_app_parse_ctx_t, timer);
722206Smax.romanov@nginx.com 
723431Sigor@sysoev.ru     nxt_mp_release(ar->request->mem_pool);
7240Sigor@sysoev.ru }
7250Sigor@sysoev.ru 
7260Sigor@sysoev.ru 
72784Smax.romanov@nginx.com nxt_int_t
72884Smax.romanov@nginx.com nxt_app_msg_flush(nxt_task_t *task, nxt_app_wmsg_t *msg, nxt_bool_t last)
7290Sigor@sysoev.ru {
73084Smax.romanov@nginx.com     nxt_int_t   rc;
73184Smax.romanov@nginx.com     nxt_buf_t   *b;
73284Smax.romanov@nginx.com 
73384Smax.romanov@nginx.com     rc = NXT_OK;
7340Sigor@sysoev.ru 
73584Smax.romanov@nginx.com     if (nxt_slow_path(last == 1)) {
73684Smax.romanov@nginx.com         do {
73784Smax.romanov@nginx.com             b = *msg->buf;
7380Sigor@sysoev.ru 
73984Smax.romanov@nginx.com             if (b == NULL) {
740423Smax.romanov@nginx.com                 b = nxt_buf_sync_alloc(msg->port->mem_pool, NXT_BUF_SYNC_LAST);
74184Smax.romanov@nginx.com                 *msg->buf = b;
74284Smax.romanov@nginx.com                 break;
74384Smax.romanov@nginx.com             }
7440Sigor@sysoev.ru 
74584Smax.romanov@nginx.com             msg->buf = &b->next;
74684Smax.romanov@nginx.com         } while(1);
74784Smax.romanov@nginx.com     }
7480Sigor@sysoev.ru 
74984Smax.romanov@nginx.com     if (nxt_slow_path(msg->write != NULL)) {
750423Smax.romanov@nginx.com         rc = nxt_port_socket_write(task, msg->port, NXT_PORT_MSG_DATA,
75184Smax.romanov@nginx.com                                    -1, msg->stream, 0, msg->write);
75284Smax.romanov@nginx.com 
75384Smax.romanov@nginx.com         msg->write = NULL;
75484Smax.romanov@nginx.com         msg->buf = &msg->write;
75584Smax.romanov@nginx.com     }
75684Smax.romanov@nginx.com 
75784Smax.romanov@nginx.com     return rc;
7580Sigor@sysoev.ru }
7590Sigor@sysoev.ru 
7600Sigor@sysoev.ru 
76184Smax.romanov@nginx.com nxt_int_t
76284Smax.romanov@nginx.com nxt_app_msg_write_raw(nxt_task_t *task, nxt_app_wmsg_t *msg, const u_char *c,
76384Smax.romanov@nginx.com     size_t size)
7640Sigor@sysoev.ru {
765206Smax.romanov@nginx.com     size_t      free_size, copy_size;
766206Smax.romanov@nginx.com     nxt_buf_t   *b;
767206Smax.romanov@nginx.com 
768206Smax.romanov@nginx.com     nxt_debug(task, "nxt_app_msg_write_raw: %uz", size);
769206Smax.romanov@nginx.com 
770206Smax.romanov@nginx.com     while (size > 0) {
771206Smax.romanov@nginx.com         b = *msg->buf;
772206Smax.romanov@nginx.com 
773206Smax.romanov@nginx.com         if (b == NULL) {
774423Smax.romanov@nginx.com             b = nxt_port_mmap_get_buf(task, msg->port, size);
775206Smax.romanov@nginx.com             if (nxt_slow_path(b == NULL)) {
776206Smax.romanov@nginx.com                 return NXT_ERROR;
777206Smax.romanov@nginx.com             }
77884Smax.romanov@nginx.com 
779206Smax.romanov@nginx.com             *msg->buf = b;
780206Smax.romanov@nginx.com         }
781206Smax.romanov@nginx.com 
782206Smax.romanov@nginx.com         do {
783206Smax.romanov@nginx.com             free_size = nxt_buf_mem_free_size(&b->mem);
784206Smax.romanov@nginx.com 
785206Smax.romanov@nginx.com             if (free_size > 0) {
786206Smax.romanov@nginx.com                 copy_size = nxt_min(free_size, size);
787206Smax.romanov@nginx.com 
788206Smax.romanov@nginx.com                 b->mem.free = nxt_cpymem(b->mem.free, c, copy_size);
789206Smax.romanov@nginx.com 
790206Smax.romanov@nginx.com                 size -= copy_size;
791206Smax.romanov@nginx.com                 c += copy_size;
792206Smax.romanov@nginx.com 
793206Smax.romanov@nginx.com                 if (size == 0) {
794206Smax.romanov@nginx.com                     return NXT_OK;
795206Smax.romanov@nginx.com                 }
796206Smax.romanov@nginx.com             }
797206Smax.romanov@nginx.com         } while (nxt_port_mmap_increase_buf(task, b, size, 1) == NXT_OK);
798206Smax.romanov@nginx.com 
799206Smax.romanov@nginx.com         msg->buf = &b->next;
8000Sigor@sysoev.ru     }
8010Sigor@sysoev.ru 
80284Smax.romanov@nginx.com     return NXT_OK;
8030Sigor@sysoev.ru }
804141Smax.romanov@nginx.com 
805141Smax.romanov@nginx.com 
806216Sigor@sysoev.ru nxt_app_lang_module_t *
807216Sigor@sysoev.ru nxt_app_lang_module(nxt_runtime_t *rt, nxt_str_t *name)
808216Sigor@sysoev.ru {
809216Sigor@sysoev.ru     u_char                 *p, *end, *version;
810356Svbart@nginx.com     size_t                 version_length;
811216Sigor@sysoev.ru     nxt_uint_t             i, n;
812356Svbart@nginx.com     nxt_app_type_t         type;
813216Sigor@sysoev.ru     nxt_app_lang_module_t  *lang;
814216Sigor@sysoev.ru 
815216Sigor@sysoev.ru     end = name->start + name->length;
816216Sigor@sysoev.ru     version = end;
817216Sigor@sysoev.ru 
818216Sigor@sysoev.ru     for (p = name->start; p < end; p++) {
819216Sigor@sysoev.ru         if (*p == ' ') {
820216Sigor@sysoev.ru             version = p + 1;
821216Sigor@sysoev.ru             break;
822216Sigor@sysoev.ru         }
823216Sigor@sysoev.ru 
824216Sigor@sysoev.ru         if (*p >= '0' && *p <= '9') {
825216Sigor@sysoev.ru             version = p;
826216Sigor@sysoev.ru             break;
827216Sigor@sysoev.ru         }
828216Sigor@sysoev.ru     }
829216Sigor@sysoev.ru 
830356Svbart@nginx.com     type = nxt_app_parse_type(name->start, p - name->start);
831356Svbart@nginx.com 
832356Svbart@nginx.com     if (type == NXT_APP_UNKNOWN) {
833356Svbart@nginx.com         return NULL;
834356Svbart@nginx.com     }
835356Svbart@nginx.com 
836216Sigor@sysoev.ru     version_length = end - version;
837216Sigor@sysoev.ru 
838216Sigor@sysoev.ru     lang = rt->languages->elts;
839216Sigor@sysoev.ru     n = rt->languages->nelts;
840216Sigor@sysoev.ru 
841216Sigor@sysoev.ru     for (i = 0; i < n; i++) {
842354Svbart@nginx.com 
843354Svbart@nginx.com         /*
844354Svbart@nginx.com          * Versions are sorted in descending order
845354Svbart@nginx.com          * so first match chooses the highest version.
846354Svbart@nginx.com          */
847354Svbart@nginx.com 
848356Svbart@nginx.com         if (lang[i].type == type
849354Svbart@nginx.com             && nxt_strvers_match(lang[i].version, version, version_length))
850216Sigor@sysoev.ru         {
851216Sigor@sysoev.ru             return &lang[i];
852216Sigor@sysoev.ru         }
853216Sigor@sysoev.ru     }
854216Sigor@sysoev.ru 
855216Sigor@sysoev.ru     return NULL;
856216Sigor@sysoev.ru }
857216Sigor@sysoev.ru 
858216Sigor@sysoev.ru 
859510Salexander.borisov@nginx.com nxt_app_type_t
860356Svbart@nginx.com nxt_app_parse_type(u_char *p, size_t length)
861141Smax.romanov@nginx.com {
862356Svbart@nginx.com     nxt_str_t str;
863356Svbart@nginx.com 
864356Svbart@nginx.com     str.length = length;
865356Svbart@nginx.com     str.start = p;
866356Svbart@nginx.com 
867356Svbart@nginx.com     if (nxt_str_eq(&str, "python", 6)) {
868141Smax.romanov@nginx.com         return NXT_APP_PYTHON;
869141Smax.romanov@nginx.com 
870356Svbart@nginx.com     } else if (nxt_str_eq(&str, "php", 3)) {
871141Smax.romanov@nginx.com         return NXT_APP_PHP;
872141Smax.romanov@nginx.com 
873356Svbart@nginx.com     } else if (nxt_str_eq(&str, "go", 2)) {
874141Smax.romanov@nginx.com         return NXT_APP_GO;
875141Smax.romanov@nginx.com 
876510Salexander.borisov@nginx.com     } else if (nxt_str_eq(&str, "perl", 4)) {
877510Salexander.borisov@nginx.com         return NXT_APP_PERL;
878141Smax.romanov@nginx.com     }
879141Smax.romanov@nginx.com 
880141Smax.romanov@nginx.com     return NXT_APP_UNKNOWN;
881141Smax.romanov@nginx.com }
882