nxt_http_source.c (0:a63ceefd6ab0) nxt_http_source.c (1:fdc027c56872)
1
2/*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7#include <nxt_main.h>
8
9
10typedef struct {
11 nxt_http_chunk_parse_t parse;
12 nxt_source_hook_t next;
13} nxt_http_source_chunk_t;
14
15
16static nxt_buf_t *nxt_http_source_request_create(nxt_http_source_t *hs);
17
1
2/*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7#include <nxt_main.h>
8
9
10typedef struct {
11 nxt_http_chunk_parse_t parse;
12 nxt_source_hook_t next;
13} nxt_http_source_chunk_t;
14
15
16static nxt_buf_t *nxt_http_source_request_create(nxt_http_source_t *hs);
17
18static void nxt_http_source_status_filter(nxt_thread_t *thr, void *obj,
18static void nxt_http_source_status_filter(nxt_task_t *task, void *obj,
19 void *data);
19 void *data);
20static void nxt_http_source_header_filter(nxt_thread_t *thr, void *obj,
20static void nxt_http_source_header_filter(nxt_task_t *task, void *obj,
21 void *data);
22
23static nxt_int_t nxt_http_source_header_line_process(nxt_http_source_t *hs);
24static nxt_int_t nxt_http_source_content_length(nxt_upstream_source_t *us,
25 nxt_name_value_t *nv);
26static nxt_int_t nxt_http_source_transfer_encoding(nxt_upstream_source_t *us,
27 nxt_name_value_t *nv);
28
21 void *data);
22
23static nxt_int_t nxt_http_source_header_line_process(nxt_http_source_t *hs);
24static nxt_int_t nxt_http_source_content_length(nxt_upstream_source_t *us,
25 nxt_name_value_t *nv);
26static nxt_int_t nxt_http_source_transfer_encoding(nxt_upstream_source_t *us,
27 nxt_name_value_t *nv);
28
29static void nxt_http_source_header_ready(nxt_http_source_t *hs,
30 nxt_buf_t *rest);
31static void nxt_http_source_chunk_filter(nxt_thread_t *thr, void *obj,
29static void nxt_http_source_header_ready(nxt_task_t *task,
30 nxt_http_source_t *hs, nxt_buf_t *rest);
31static void nxt_http_source_chunk_filter(nxt_task_t *task, void *obj,
32 void *data);
32 void *data);
33static void nxt_http_source_chunk_error(nxt_thread_t *thr, void *obj,
33static void nxt_http_source_chunk_error(nxt_task_t *task, void *obj,
34 void *data);
34 void *data);
35static void nxt_http_source_body_filter(nxt_thread_t *thr, void *obj,
35static void nxt_http_source_body_filter(nxt_task_t *task, void *obj,
36 void *data);
37
36 void *data);
37
38static void nxt_http_source_sync_buffer(nxt_thread_t *thr,
39 nxt_http_source_t *hs, nxt_buf_t *b);
40static void nxt_http_source_error(nxt_stream_source_t *stream);
41static void nxt_http_source_fail(nxt_http_source_t *hs);
38static void nxt_http_source_sync_buffer(nxt_task_t *task, nxt_http_source_t *hs,
39 nxt_buf_t *b);
40static void nxt_http_source_error(nxt_task_t *task,
41 nxt_stream_source_t *stream);
42static void nxt_http_source_fail(nxt_task_t *task, nxt_http_source_t *hs);
42static void nxt_http_source_message(const char *msg, size_t len, u_char *p);
43
44
45void
43static void nxt_http_source_message(const char *msg, size_t len, u_char *p);
44
45
46void
46nxt_http_source_handler(nxt_upstream_source_t *us,
47nxt_http_source_handler(nxt_task_t *task, nxt_upstream_source_t *us,
47 nxt_http_source_request_create_t request_create)
48{
49 nxt_http_source_t *hs;
50 nxt_stream_source_t *stream;
51
52 hs = nxt_mem_zalloc(us->buffers.mem_pool, sizeof(nxt_http_source_t));
53 if (nxt_slow_path(hs == NULL)) {
54 goto fail;

--- 39 unchanged lines hidden (view full) ---

94
95 hs->header_in.content_length = -1;
96
97 stream->out = nxt_http_source_request_create(hs);
98
99 if (nxt_fast_path(stream->out != NULL)) {
100 nxt_memzero(&hs->u.status_parse, sizeof(nxt_http_status_parse_t));
101
48 nxt_http_source_request_create_t request_create)
49{
50 nxt_http_source_t *hs;
51 nxt_stream_source_t *stream;
52
53 hs = nxt_mem_zalloc(us->buffers.mem_pool, sizeof(nxt_http_source_t));
54 if (nxt_slow_path(hs == NULL)) {
55 goto fail;

--- 39 unchanged lines hidden (view full) ---

95
96 hs->header_in.content_length = -1;
97
98 stream->out = nxt_http_source_request_create(hs);
99
100 if (nxt_fast_path(stream->out != NULL)) {
101 nxt_memzero(&hs->u.status_parse, sizeof(nxt_http_status_parse_t));
102
102 nxt_stream_source_connect(stream);
103 nxt_stream_source_connect(task, stream);
103 return;
104 }
105
106fail:
107
104 return;
105 }
106
107fail:
108
108 nxt_http_source_fail(hs);
109 nxt_http_source_fail(task, hs);
109}
110
111
112nxt_inline u_char *
113nxt_http_source_copy(u_char *p, nxt_str_t *src, size_t len)
114{
115 u_char *s;
116

--- 62 unchanged lines hidden (view full) ---

179
180 nxt_thread_log_debug("\"%*s\"", b->mem.free - b->mem.pos, b->mem.pos);
181
182 return req;
183}
184
185
186static void
110}
111
112
113nxt_inline u_char *
114nxt_http_source_copy(u_char *p, nxt_str_t *src, size_t len)
115{
116 u_char *s;
117

--- 62 unchanged lines hidden (view full) ---

180
181 nxt_thread_log_debug("\"%*s\"", b->mem.free - b->mem.pos, b->mem.pos);
182
183 return req;
184}
185
186
187static void
187nxt_http_source_status_filter(nxt_thread_t *thr, void *obj, void *data)
188nxt_http_source_status_filter(nxt_task_t *task, void *obj, void *data)
188{
189 nxt_int_t ret;
190 nxt_buf_t *b;
191 nxt_http_source_t *hs;
192
193 hs = obj;
194 b = data;
195
196 /*
197 * No cycle over buffer chain is required since at
198 * start the stream source passes buffers one at a time.
199 */
200
189{
190 nxt_int_t ret;
191 nxt_buf_t *b;
192 nxt_http_source_t *hs;
193
194 hs = obj;
195 b = data;
196
197 /*
198 * No cycle over buffer chain is required since at
199 * start the stream source passes buffers one at a time.
200 */
201
201 nxt_log_debug(thr->log, "http source status filter");
202 nxt_debug(task, "http source status filter");
202
203 if (nxt_slow_path(nxt_buf_is_sync(b))) {
203
204 if (nxt_slow_path(nxt_buf_is_sync(b))) {
204 nxt_http_source_sync_buffer(thr, hs, b);
205 nxt_http_source_sync_buffer(task, hs, b);
205 return;
206 }
207
208 ret = nxt_http_status_parse(&hs->u.status_parse, &b->mem);
209
210 if (nxt_fast_path(ret == NXT_OK)) {
211 /*
212 * Change the HTTP source filter chain:
213 * stream source | HTTP header filter
214 */
215 hs->query.filter = nxt_http_source_header_filter;
216
206 return;
207 }
208
209 ret = nxt_http_status_parse(&hs->u.status_parse, &b->mem);
210
211 if (nxt_fast_path(ret == NXT_OK)) {
212 /*
213 * Change the HTTP source filter chain:
214 * stream source | HTTP header filter
215 */
216 hs->query.filter = nxt_http_source_header_filter;
217
217 nxt_log_debug(thr->log, "upstream status: \"%*s\"",
218 hs->u.status_parse.end - b->mem.start, b->mem.start);
218 nxt_debug(task, "upstream status: \"%*s\"",
219 hs->u.status_parse.end - b->mem.start, b->mem.start);
219
220 hs->header_in.status = hs->u.status_parse.code;
221
220
221 hs->header_in.status = hs->u.status_parse.code;
222
222 nxt_log_debug(thr->log, "upstream version:%d status:%uD \"%*s\"",
223 hs->u.status_parse.http_version,
224 hs->u.status_parse.code,
225 hs->u.status_parse.end - hs->u.status_parse.start,
226 hs->u.status_parse.start);
223 nxt_debug(task, "upstream version:%d status:%uD \"%*s\"",
224 hs->u.status_parse.http_version,
225 hs->u.status_parse.code,
226 hs->u.status_parse.end - hs->u.status_parse.start,
227 hs->u.status_parse.start);
227
228 nxt_memzero(&hs->u.header, sizeof(nxt_http_split_header_parse_t));
229 hs->u.header.mem_pool = hs->upstream->buffers.mem_pool;
230
228
229 nxt_memzero(&hs->u.header, sizeof(nxt_http_split_header_parse_t));
230 hs->u.header.mem_pool = hs->upstream->buffers.mem_pool;
231
231 nxt_http_source_header_filter(thr, hs, b);
232 nxt_http_source_header_filter(task, hs, b);
232 return;
233 }
234
235 if (nxt_slow_path(ret == NXT_ERROR)) {
236 /* HTTP/0.9 response. */
237 hs->header_in.status = 200;
233 return;
234 }
235
236 if (nxt_slow_path(ret == NXT_ERROR)) {
237 /* HTTP/0.9 response. */
238 hs->header_in.status = 200;
238 nxt_http_source_header_ready(hs, b);
239 nxt_http_source_header_ready(task, hs, b);
239 return;
240 }
241
242 /* ret == NXT_AGAIN */
243
244 /*
245 * b->mem.pos is always equal to b->mem.end because b is a buffer
246 * which points to a response part read by the stream source.
247 * However, since the stream source is an immediate source of the
248 * status filter, b->parent is a buffer the stream source reads in.
249 */
250 if (b->parent->mem.pos == b->parent->mem.end) {
251 nxt_http_source_message("upstream sent too long status line: \"%*s\"",
252 b->mem.pos - b->mem.start, b->mem.start);
253
240 return;
241 }
242
243 /* ret == NXT_AGAIN */
244
245 /*
246 * b->mem.pos is always equal to b->mem.end because b is a buffer
247 * which points to a response part read by the stream source.
248 * However, since the stream source is an immediate source of the
249 * status filter, b->parent is a buffer the stream source reads in.
250 */
251 if (b->parent->mem.pos == b->parent->mem.end) {
252 nxt_http_source_message("upstream sent too long status line: \"%*s\"",
253 b->mem.pos - b->mem.start, b->mem.start);
254
254 nxt_http_source_fail(hs);
255 nxt_http_source_fail(task, hs);
255 }
256}
257
258
259static void
256 }
257}
258
259
260static void
260nxt_http_source_header_filter(nxt_thread_t *thr, void *obj, void *data)
261nxt_http_source_header_filter(nxt_task_t *task, void *obj, void *data)
261{
262 nxt_int_t ret;
263 nxt_buf_t *b;
264 nxt_http_source_t *hs;
265
266 hs = obj;
267 b = data;
268
269 /*
270 * No cycle over buffer chain is required since at
271 * start the stream source passes buffers one at a time.
272 */
273
262{
263 nxt_int_t ret;
264 nxt_buf_t *b;
265 nxt_http_source_t *hs;
266
267 hs = obj;
268 b = data;
269
270 /*
271 * No cycle over buffer chain is required since at
272 * start the stream source passes buffers one at a time.
273 */
274
274 nxt_log_debug(thr->log, "http source header filter");
275 nxt_debug(task, "http source header filter");
275
276 if (nxt_slow_path(nxt_buf_is_sync(b))) {
276
277 if (nxt_slow_path(nxt_buf_is_sync(b))) {
277 nxt_http_source_sync_buffer(thr, hs, b);
278 nxt_http_source_sync_buffer(task, hs, b);
278 return;
279 }
280
281 for ( ;; ) {
282 ret = nxt_http_split_header_parse(&hs->u.header, &b->mem);
283
284 if (nxt_slow_path(ret != NXT_OK)) {
285 break;
286 }
287
288 ret = nxt_http_source_header_line_process(hs);
289
290 if (nxt_slow_path(ret != NXT_OK)) {
291 break;
292 }
293 }
294
295 if (nxt_fast_path(ret == NXT_DONE)) {
279 return;
280 }
281
282 for ( ;; ) {
283 ret = nxt_http_split_header_parse(&hs->u.header, &b->mem);
284
285 if (nxt_slow_path(ret != NXT_OK)) {
286 break;
287 }
288
289 ret = nxt_http_source_header_line_process(hs);
290
291 if (nxt_slow_path(ret != NXT_OK)) {
292 break;
293 }
294 }
295
296 if (nxt_fast_path(ret == NXT_DONE)) {
296 nxt_log_debug(thr->log, "http source header done");
297 nxt_http_source_header_ready(hs, b);
297 nxt_debug(task, "http source header done");
298 nxt_http_source_header_ready(task, hs, b);
298 return;
299 }
300
301 if (nxt_fast_path(ret == NXT_AGAIN)) {
302 return;
303 }
304
305 if (ret != NXT_ERROR) {
306 /* ret == NXT_DECLINED: "\r" is not followed by "\n" */
299 return;
300 }
301
302 if (nxt_fast_path(ret == NXT_AGAIN)) {
303 return;
304 }
305
306 if (ret != NXT_ERROR) {
307 /* ret == NXT_DECLINED: "\r" is not followed by "\n" */
307 nxt_log_error(NXT_LOG_ERR, thr->log,
308 "upstream sent invalid header line: \"%*s\\r...\"",
309 hs->u.header.parse.header_end
310 - hs->u.header.parse.header_name_start,
311 hs->u.header.parse.header_name_start);
308 nxt_log(task, NXT_LOG_ERR,
309 "upstream sent invalid header line: \"%*s\\r...\"",
310 hs->u.header.parse.header_end
311 - hs->u.header.parse.header_name_start,
312 hs->u.header.parse.header_name_start);
312 }
313
314 /* ret == NXT_ERROR */
315
313 }
314
315 /* ret == NXT_ERROR */
316
316 nxt_http_source_fail(hs);
317 nxt_http_source_fail(task, hs);
317}
318
319
320static nxt_int_t
321nxt_http_source_header_line_process(nxt_http_source_t *hs)
322{
323 size_t name_len;
324 nxt_name_value_t *nv;

--- 95 unchanged lines hidden (view full) ---

420 hs->chunked = 1;
421 }
422
423 return NXT_OK;
424}
425
426
427static void
318}
319
320
321static nxt_int_t
322nxt_http_source_header_line_process(nxt_http_source_t *hs)
323{
324 size_t name_len;
325 nxt_name_value_t *nv;

--- 95 unchanged lines hidden (view full) ---

421 hs->chunked = 1;
422 }
423
424 return NXT_OK;
425}
426
427
428static void
428nxt_http_source_header_ready(nxt_http_source_t *hs, nxt_buf_t *rest)
429nxt_http_source_header_ready(nxt_task_t *task, nxt_http_source_t *hs,
430 nxt_buf_t *rest)
429{
430 nxt_buf_t *b;
431 nxt_upstream_source_t *us;
432 nxt_http_source_chunk_t *hsc;
433
434 us = hs->upstream;
435
436 /* Free buffers used for request header. */

--- 19 unchanged lines hidden (view full) ---

456 hs->query.filter = nxt_http_source_chunk_filter;
457
458 hsc->next.context = hs;
459 hsc->next.filter = nxt_http_source_body_filter;
460
461 hsc->parse.mem_pool = hs->upstream->buffers.mem_pool;
462
463 if (nxt_buf_mem_used_size(&rest->mem) != 0) {
431{
432 nxt_buf_t *b;
433 nxt_upstream_source_t *us;
434 nxt_http_source_chunk_t *hsc;
435
436 us = hs->upstream;
437
438 /* Free buffers used for request header. */

--- 19 unchanged lines hidden (view full) ---

458 hs->query.filter = nxt_http_source_chunk_filter;
459
460 hsc->next.context = hs;
461 hsc->next.filter = nxt_http_source_body_filter;
462
463 hsc->parse.mem_pool = hs->upstream->buffers.mem_pool;
464
465 if (nxt_buf_mem_used_size(&rest->mem) != 0) {
464 hs->rest = nxt_http_chunk_parse(&hsc->parse, rest);
466 hs->rest = nxt_http_chunk_parse(task, &hsc->parse, rest);
465
466 if (nxt_slow_path(hs->rest == NULL)) {
467 goto fail;
468 }
469 }
470
471 } else {
472 /*

--- 11 unchanged lines hidden (view full) ---

484 return;
485 }
486
487 nxt_thread_log_error(NXT_LOG_ERR, "%d buffers %uDK each "
488 "are not enough to read upstream response",
489 us->buffers.max, us->buffers.size / 1024);
490fail:
491
467
468 if (nxt_slow_path(hs->rest == NULL)) {
469 goto fail;
470 }
471 }
472
473 } else {
474 /*

--- 11 unchanged lines hidden (view full) ---

486 return;
487 }
488
489 nxt_thread_log_error(NXT_LOG_ERR, "%d buffers %uDK each "
490 "are not enough to read upstream response",
491 us->buffers.max, us->buffers.size / 1024);
492fail:
493
492 nxt_http_source_fail(hs);
494 nxt_http_source_fail(task, hs);
493}
494
495
496static void
495}
496
497
498static void
497nxt_http_source_chunk_filter(nxt_thread_t *thr, void *obj, void *data)
499nxt_http_source_chunk_filter(nxt_task_t *task, void *obj, void *data)
498{
499 nxt_buf_t *b;
500 nxt_http_source_t *hs;
501 nxt_http_source_chunk_t *hsc;
502
503 hsc = obj;
504 b = data;
505
500{
501 nxt_buf_t *b;
502 nxt_http_source_t *hs;
503 nxt_http_source_chunk_t *hsc;
504
505 hsc = obj;
506 b = data;
507
506 nxt_log_debug(thr->log, "http source chunk filter");
508 nxt_debug(task, "http source chunk filter");
507
509
508 b = nxt_http_chunk_parse(&hsc->parse, b);
510 b = nxt_http_chunk_parse(task, &hsc->parse, b);
509
510 hs = hsc->next.context;
511
512 if (hsc->parse.error) {
511
512 hs = hsc->next.context;
513
514 if (hsc->parse.error) {
513 nxt_http_source_fail(hs);
515 nxt_http_source_fail(task, hs);
514 return;
515 }
516
517 if (hsc->parse.chunk_error) {
518 /* Output all parsed before a chunk error and close upstream. */
516 return;
517 }
518
519 if (hsc->parse.chunk_error) {
520 /* Output all parsed before a chunk error and close upstream. */
519 nxt_thread_current_work_queue_add(thr, nxt_http_source_chunk_error,
520 hs, NULL, thr->log);
521 nxt_thread_current_work_queue_add(task->thread,
522 nxt_http_source_chunk_error,
523 task, hs, NULL);
521 }
522
523 if (b != NULL) {
524 }
525
526 if (b != NULL) {
524 nxt_source_filter(thr, hs->upstream->work_queue, &hsc->next, b);
527 nxt_source_filter(task->thread, hs->upstream->work_queue, task,
528 &hsc->next, b);
525 }
526}
527
528
529static void
529 }
530}
531
532
533static void
530nxt_http_source_chunk_error(nxt_thread_t *thr, void *obj, void *data)
534nxt_http_source_chunk_error(nxt_task_t *task, void *obj, void *data)
531{
532 nxt_http_source_t *hs;
533
534 hs = obj;
535
535{
536 nxt_http_source_t *hs;
537
538 hs = obj;
539
536 nxt_http_source_fail(hs);
540 nxt_http_source_fail(task, hs);
537}
538
539
540/*
541 * The HTTP source body filter accumulates first body buffers before the next
542 * filter will be established and sets completion handler for the last buffer.
543 */
544
545static void
541}
542
543
544/*
545 * The HTTP source body filter accumulates first body buffers before the next
546 * filter will be established and sets completion handler for the last buffer.
547 */
548
549static void
546nxt_http_source_body_filter(nxt_thread_t *thr, void *obj, void *data)
550nxt_http_source_body_filter(nxt_task_t *task, void *obj, void *data)
547{
548 nxt_buf_t *b, *in;
549 nxt_http_source_t *hs;
550
551 hs = obj;
552 in = data;
553
551{
552 nxt_buf_t *b, *in;
553 nxt_http_source_t *hs;
554
555 hs = obj;
556 in = data;
557
554 nxt_log_debug(thr->log, "http source body filter");
558 nxt_debug(task, "http source body filter");
555
556 for (b = in; b != NULL; b = b->next) {
557
558 if (nxt_buf_is_last(b)) {
559 b->data = hs->upstream->data;
560 b->completion_handler = hs->upstream->state->completion_handler;
561 }
562 }
563
564 if (hs->next != NULL) {
559
560 for (b = in; b != NULL; b = b->next) {
561
562 if (nxt_buf_is_last(b)) {
563 b->data = hs->upstream->data;
564 b->completion_handler = hs->upstream->state->completion_handler;
565 }
566 }
567
568 if (hs->next != NULL) {
565 nxt_source_filter(thr, hs->upstream->work_queue, hs->next, in);
569 nxt_source_filter(task->thread, hs->upstream->work_queue, task,
570 hs->next, in);
566 return;
567 }
568
569 nxt_buf_chain_add(&hs->rest, in);
570}
571
572
573static void
571 return;
572 }
573
574 nxt_buf_chain_add(&hs->rest, in);
575}
576
577
578static void
574nxt_http_source_sync_buffer(nxt_thread_t *thr, nxt_http_source_t *hs,
579nxt_http_source_sync_buffer(nxt_task_t *task, nxt_http_source_t *hs,
575 nxt_buf_t *b)
576{
577 if (nxt_buf_is_last(b)) {
580 nxt_buf_t *b)
581{
582 if (nxt_buf_is_last(b)) {
578 nxt_log_error(NXT_LOG_ERR, thr->log,
579 "upstream closed prematurely connection");
583 nxt_log(task, NXT_LOG_ERR,
584 "upstream closed prematurely connection");
580
581 } else {
585
586 } else {
582 nxt_log_error(NXT_LOG_ERR, thr->log, "%ui buffers %uz each are not "
583 "enough to process upstream response header",
584 hs->upstream->buffers.max,
585 hs->upstream->buffers.size);
587 nxt_log(task, NXT_LOG_ERR,"%ui buffers %uz each are not "
588 "enough to process upstream response header",
589 hs->upstream->buffers.max, hs->upstream->buffers.size);
586 }
587
588 /* The stream source sends only the last and the nobuf sync buffer. */
589
590 }
591
592 /* The stream source sends only the last and the nobuf sync buffer. */
593
590 nxt_http_source_fail(hs);
594 nxt_http_source_fail(task, hs);
591}
592
593
594static void
595}
596
597
598static void
595nxt_http_source_error(nxt_stream_source_t *stream)
599nxt_http_source_error(nxt_task_t *task, nxt_stream_source_t *stream)
596{
597 nxt_http_source_t *hs;
598
599 nxt_thread_log_debug("http source error");
600
601 hs = stream->next->context;
600{
601 nxt_http_source_t *hs;
602
603 nxt_thread_log_debug("http source error");
604
605 hs = stream->next->context;
602 nxt_http_source_fail(hs);
606 nxt_http_source_fail(task, hs);
603}
604
605
606static void
607}
608
609
610static void
607nxt_http_source_fail(nxt_http_source_t *hs)
611nxt_http_source_fail(nxt_task_t *task, nxt_http_source_t *hs)
608{
612{
609 nxt_thread_t *thr;
613 nxt_debug(task, "http source fail");
610
614
611 thr = nxt_thread();
612
613 nxt_log_debug(thr->log, "http source fail");
614
615 /* TODO: fail, next upstream, or bad gateway */
616
615 /* TODO: fail, next upstream, or bad gateway */
616
617 hs->upstream->state->error_handler(thr, hs, NULL);
617 hs->upstream->state->error_handler(task, hs, NULL);
618}
619
620
621static void
622nxt_http_source_message(const char *msg, size_t len, u_char *p)
623{
624 if (len > NXT_MAX_ERROR_STR - 300) {
625 len = NXT_MAX_ERROR_STR - 300;
626 p[len++] = '.'; p[len++] = '.'; p[len++] = '.';
627 }
628
629 nxt_thread_log_error(NXT_LOG_ERR, msg, len, p);
630}
618}
619
620
621static void
622nxt_http_source_message(const char *msg, size_t len, u_char *p)
623{
624 if (len > NXT_MAX_ERROR_STR - 300) {
625 len = NXT_MAX_ERROR_STR - 300;
626 p[len++] = '.'; p[len++] = '.'; p[len++] = '.';
627 }
628
629 nxt_thread_log_error(NXT_LOG_ERR, msg, len, p);
630}