xref: /unit/src/test/nxt_unit_app_test.c (revision 1669:37e2a3ea1bf1)
1 
2 /*
3  * Copyright (C) NGINX, Inc.
4  */
5 
6 #include <nxt_auto_config.h>
7 #include <nxt_version.h>
8 #include <nxt_unit.h>
9 #include <nxt_unit_request.h>
10 #include <nxt_clang.h>
11 #include <pthread.h>
12 #include <string.h>
13 #include <stdlib.h>
14 
15 
16 #define CONTENT_TYPE  "Content-Type"
17 #define TEXT_PLAIN    "text/plain"
18 #define HELLO_WORLD   "Hello world!\n"
19 
20 #define NEW_LINE      "\n"
21 
22 #define REQUEST_DATA  "Request data:\n"
23 #define METHOD        "  Method: "
24 #define PROTOCOL      "  Protocol: "
25 #define REMOTE_ADDR   "  Remote addr: "
26 #define LOCAL_ADDR    "  Local addr: "
27 #define TARGET        "  Target: "
28 #define PATH          "  Path: "
29 #define QUERY         "  Query: "
30 #define FIELDS        "  Fields:\n"
31 #define FIELD_PAD     "    "
32 #define FIELD_SEP     ": "
33 #define BODY          "  Body:\n"
34 
35 
36 static int ready_handler(nxt_unit_ctx_t *ctx);
37 static void *worker(void *main_ctx);
38 static void greeting_app_request_handler(nxt_unit_request_info_t *req);
39 static inline char *copy(char *p, const void *src, uint32_t len);
40 
41 
42 static int        thread_count;
43 static pthread_t  *threads;
44 
45 
46 int
47 main(int argc, char **argv)
48 {
49     int              i, err;
50     nxt_unit_ctx_t   *ctx;
51     nxt_unit_init_t  init;
52 
53     if (argc == 3 && strcmp(argv[1], "-t") == 0) {
54         thread_count = atoi(argv[2]);
55     }
56 
57     memset(&init, 0, sizeof(nxt_unit_init_t));
58 
59     init.callbacks.request_handler = greeting_app_request_handler;
60     init.callbacks.ready_handler = ready_handler;
61 
62     ctx = nxt_unit_init(&init);
63     if (ctx == NULL) {
64         return 1;
65     }
66 
67     err = nxt_unit_run(ctx);
68 
69     nxt_unit_debug(ctx, "main worker finished with %d code", err);
70 
71     if (thread_count > 1) {
72         for (i = 0; i < thread_count - 1; i++) {
73             err = pthread_join(threads[i], NULL);
74 
75             nxt_unit_debug(ctx, "join thread #%d: %d", i, err);
76         }
77 
78         nxt_unit_free(ctx, threads);
79     }
80 
81     nxt_unit_done(ctx);
82 
83     nxt_unit_debug(NULL, "main worker done");
84 
85     return 0;
86 }
87 
88 
89 static int
90 ready_handler(nxt_unit_ctx_t *ctx)
91 {
92     int  i, err;
93 
94     nxt_unit_debug(ctx, "ready");
95 
96     if (!nxt_unit_is_main_ctx(ctx) || thread_count <= 1) {
97         return NXT_UNIT_OK;
98     }
99 
100     threads = nxt_unit_malloc(ctx, sizeof(pthread_t) * (thread_count - 1));
101     if (threads == NULL) {
102         return NXT_UNIT_ERROR;
103     }
104 
105     for (i = 0; i < thread_count - 1; i++) {
106         err = pthread_create(&threads[i], NULL, worker, ctx);
107         if (err != 0) {
108             return NXT_UNIT_ERROR;
109         }
110     }
111 
112     return NXT_UNIT_OK;
113 }
114 
115 
116 static void *
117 worker(void *main_ctx)
118 {
119     int             rc;
120     nxt_unit_ctx_t  *ctx;
121 
122     ctx = nxt_unit_ctx_alloc(main_ctx, NULL);
123     if (ctx == NULL) {
124         return NULL;
125     }
126 
127     nxt_unit_debug(ctx, "start worker");
128 
129     rc = nxt_unit_run(ctx);
130 
131     nxt_unit_debug(ctx, "worker finished with %d code", rc);
132 
133     nxt_unit_done(ctx);
134 
135     return NULL;
136 }
137 
138 
139 static void
140 greeting_app_request_handler(nxt_unit_request_info_t *req)
141 {
142     int                 rc;
143     char                *p;
144     ssize_t             res;
145     uint32_t            i;
146     nxt_unit_buf_t      *buf;
147     nxt_unit_field_t    *f;
148     nxt_unit_request_t  *r;
149 
150     rc = nxt_unit_response_init(req, 200 /* Status code. */,
151                                 1 /* Number of response headers. */,
152                                 nxt_length(CONTENT_TYPE)
153                                 + nxt_length(TEXT_PLAIN)
154                                 + nxt_length(HELLO_WORLD));
155     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
156         goto fail;
157     }
158 
159     rc = nxt_unit_response_add_field(req,
160                                      CONTENT_TYPE, nxt_length(CONTENT_TYPE),
161                                      TEXT_PLAIN, nxt_length(TEXT_PLAIN));
162     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
163         goto fail;
164     }
165 
166     rc = nxt_unit_response_add_content(req, HELLO_WORLD,
167                                        nxt_length(HELLO_WORLD));
168     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
169         goto fail;
170     }
171 
172     rc = nxt_unit_response_send(req);
173     if (nxt_slow_path(rc != NXT_UNIT_OK)) {
174         goto fail;
175     }
176 
177     r = req->request;
178 
179     buf = nxt_unit_response_buf_alloc(req, (req->request_buf->end
180                                             - req->request_buf->start)
181                                       + nxt_length(REQUEST_DATA)
182                                       + nxt_length(METHOD)
183                                       + nxt_length(NEW_LINE)
184                                       + nxt_length(PROTOCOL)
185                                       + nxt_length(NEW_LINE)
186                                       + nxt_length(REMOTE_ADDR)
187                                       + nxt_length(NEW_LINE)
188                                       + nxt_length(LOCAL_ADDR)
189                                       + nxt_length(NEW_LINE)
190                                       + nxt_length(TARGET)
191                                       + nxt_length(NEW_LINE)
192                                       + nxt_length(PATH)
193                                       + nxt_length(NEW_LINE)
194                                       + nxt_length(QUERY)
195                                       + nxt_length(NEW_LINE)
196                                       + nxt_length(FIELDS)
197                                       + r->fields_count * (
198                                           nxt_length(FIELD_PAD)
199                                           + nxt_length(FIELD_SEP))
200                                       + nxt_length(BODY));
201     if (nxt_slow_path(buf == NULL)) {
202         rc = NXT_UNIT_ERROR;
203 
204         goto fail;
205     }
206 
207     p = buf->free;
208 
209     p = copy(p, REQUEST_DATA, nxt_length(REQUEST_DATA));
210 
211     p = copy(p, METHOD, nxt_length(METHOD));
212     p = copy(p, nxt_unit_sptr_get(&r->method), r->method_length);
213     *p++ = '\n';
214 
215     p = copy(p, PROTOCOL, nxt_length(PROTOCOL));
216     p = copy(p, nxt_unit_sptr_get(&r->version), r->version_length);
217     *p++ = '\n';
218 
219     p = copy(p, REMOTE_ADDR, nxt_length(REMOTE_ADDR));
220     p = copy(p, nxt_unit_sptr_get(&r->remote), r->remote_length);
221     *p++ = '\n';
222 
223     p = copy(p, LOCAL_ADDR, nxt_length(LOCAL_ADDR));
224     p = copy(p, nxt_unit_sptr_get(&r->local), r->local_length);
225     *p++ = '\n';
226 
227     p = copy(p, TARGET, nxt_length(TARGET));
228     p = copy(p, nxt_unit_sptr_get(&r->target), r->target_length);
229     *p++ = '\n';
230 
231     p = copy(p, PATH, nxt_length(PATH));
232     p = copy(p, nxt_unit_sptr_get(&r->path), r->path_length);
233     *p++ = '\n';
234 
235     if (r->query.offset) {
236         p = copy(p, QUERY, nxt_length(QUERY));
237         p = copy(p, nxt_unit_sptr_get(&r->query), r->query_length);
238         *p++ = '\n';
239     }
240 
241     p = copy(p, FIELDS, nxt_length(FIELDS));
242 
243     for (i = 0; i < r->fields_count; i++) {
244         f = r->fields + i;
245 
246         p = copy(p, FIELD_PAD, nxt_length(FIELD_PAD));
247         p = copy(p, nxt_unit_sptr_get(&f->name), f->name_length);
248         p = copy(p, FIELD_SEP, nxt_length(FIELD_SEP));
249         p = copy(p, nxt_unit_sptr_get(&f->value), f->value_length);
250         *p++ = '\n';
251     }
252 
253     if (r->content_length > 0) {
254         p = copy(p, BODY, nxt_length(BODY));
255 
256         res = nxt_unit_request_read(req, buf->free, buf->end - buf->free);
257         buf->free += res;
258 
259     }
260 
261     buf->free = p;
262 
263     rc = nxt_unit_buf_send(buf);
264 
265 fail:
266 
267     nxt_unit_request_done(req, rc);
268 }
269 
270 
271 static inline char *
272 copy(char *p, const void *src, uint32_t len)
273 {
274     memcpy(p, src, len);
275 
276     return p + len;
277 }
278