annotate src/stream/ngx_stream_write_filter_module.c @ 7401:a7ff19afbb14

Negative size buffers detection. In the past, there were several security issues which resulted in worker process memory disclosure due to buffers with negative size. It looks reasonable to check for such buffers in various places, much like we already check for zero size buffers. While here, removed "#if 1 / #endif" around zero size buffer checks. It looks highly unlikely that we'll disable these checks anytime soon.
author Maxim Dounin <mdounin@mdounin.ru>
date Mon, 26 Nov 2018 18:29:56 +0300
parents 56fc55e32f23
children d127837c714f
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
6692
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
1
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
2 /*
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
3 * Copyright (C) Igor Sysoev
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
4 * Copyright (C) Nginx, Inc.
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
5 */
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
6
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
7
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
8 #include <ngx_config.h>
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
9 #include <ngx_core.h>
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
10 #include <ngx_stream.h>
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
11
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
12
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
13 typedef struct {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
14 ngx_chain_t *from_upstream;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
15 ngx_chain_t *from_downstream;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
16 } ngx_stream_write_filter_ctx_t;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
17
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
18
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
19 static ngx_int_t ngx_stream_write_filter(ngx_stream_session_t *s,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
20 ngx_chain_t *in, ngx_uint_t from_upstream);
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
21 static ngx_int_t ngx_stream_write_filter_init(ngx_conf_t *cf);
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
22
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
23
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
24 static ngx_stream_module_t ngx_stream_write_filter_module_ctx = {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
25 NULL, /* preconfiguration */
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
26 ngx_stream_write_filter_init, /* postconfiguration */
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
27
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
28 NULL, /* create main configuration */
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
29 NULL, /* init main configuration */
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
30
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
31 NULL, /* create server configuration */
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
32 NULL /* merge server configuration */
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
33 };
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
34
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
35
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
36 ngx_module_t ngx_stream_write_filter_module = {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
37 NGX_MODULE_V1,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
38 &ngx_stream_write_filter_module_ctx, /* module context */
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
39 NULL, /* module directives */
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
40 NGX_STREAM_MODULE, /* module type */
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
41 NULL, /* init master */
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
42 NULL, /* init module */
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
43 NULL, /* init process */
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
44 NULL, /* init thread */
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
45 NULL, /* exit thread */
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
46 NULL, /* exit process */
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
47 NULL, /* exit master */
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
48 NGX_MODULE_V1_PADDING
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
49 };
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
50
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
51
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
52 static ngx_int_t
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
53 ngx_stream_write_filter(ngx_stream_session_t *s, ngx_chain_t *in,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
54 ngx_uint_t from_upstream)
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
55 {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
56 off_t size;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
57 ngx_uint_t last, flush, sync;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
58 ngx_chain_t *cl, *ln, **ll, **out, *chain;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
59 ngx_connection_t *c;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
60 ngx_stream_write_filter_ctx_t *ctx;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
61
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
62 ctx = ngx_stream_get_module_ctx(s, ngx_stream_write_filter_module);
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
63
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
64 if (ctx == NULL) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
65 ctx = ngx_pcalloc(s->connection->pool,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
66 sizeof(ngx_stream_write_filter_ctx_t));
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
67 if (ctx == NULL) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
68 return NGX_ERROR;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
69 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
70
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
71 ngx_stream_set_ctx(s, ctx, ngx_stream_write_filter_module);
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
72 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
73
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
74 if (from_upstream) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
75 c = s->connection;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
76 out = &ctx->from_upstream;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
77
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
78 } else {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
79 c = s->upstream->peer.connection;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
80 out = &ctx->from_downstream;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
81 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
82
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
83 if (c->error) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
84 return NGX_ERROR;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
85 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
86
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
87 size = 0;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
88 flush = 0;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
89 sync = 0;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
90 last = 0;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
91 ll = out;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
92
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
93 /* find the size, the flush point and the last link of the saved chain */
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
94
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
95 for (cl = *out; cl; cl = cl->next) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
96 ll = &cl->next;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
97
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
98 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
99 "write old buf t:%d f:%d %p, pos %p, size: %z "
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
100 "file: %O, size: %O",
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
101 cl->buf->temporary, cl->buf->in_file,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
102 cl->buf->start, cl->buf->pos,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
103 cl->buf->last - cl->buf->pos,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
104 cl->buf->file_pos,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
105 cl->buf->file_last - cl->buf->file_pos);
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
106
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
107 if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
108 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
109 "zero size buf in writer "
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
110 "t:%d r:%d f:%d %p %p-%p %p %O-%O",
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
111 cl->buf->temporary,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
112 cl->buf->recycled,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
113 cl->buf->in_file,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
114 cl->buf->start,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
115 cl->buf->pos,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
116 cl->buf->last,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
117 cl->buf->file,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
118 cl->buf->file_pos,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
119 cl->buf->file_last);
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
120
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
121 ngx_debug_point();
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
122 return NGX_ERROR;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
123 }
7401
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
124
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
125 if (ngx_buf_size(cl->buf) < 0) {
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
126 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
127 "negative size buf in writer "
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
128 "t:%d r:%d f:%d %p %p-%p %p %O-%O",
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
129 cl->buf->temporary,
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
130 cl->buf->recycled,
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
131 cl->buf->in_file,
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
132 cl->buf->start,
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
133 cl->buf->pos,
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
134 cl->buf->last,
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
135 cl->buf->file,
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
136 cl->buf->file_pos,
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
137 cl->buf->file_last);
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
138
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
139 ngx_debug_point();
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
140 return NGX_ERROR;
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
141 }
6692
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
142
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
143 size += ngx_buf_size(cl->buf);
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
144
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
145 if (cl->buf->flush || cl->buf->recycled) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
146 flush = 1;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
147 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
148
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
149 if (cl->buf->sync) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
150 sync = 1;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
151 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
152
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
153 if (cl->buf->last_buf) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
154 last = 1;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
155 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
156 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
157
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
158 /* add the new chain to the existent one */
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
159
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
160 for (ln = in; ln; ln = ln->next) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
161 cl = ngx_alloc_chain_link(c->pool);
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
162 if (cl == NULL) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
163 return NGX_ERROR;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
164 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
165
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
166 cl->buf = ln->buf;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
167 *ll = cl;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
168 ll = &cl->next;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
169
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
170 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
171 "write new buf t:%d f:%d %p, pos %p, size: %z "
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
172 "file: %O, size: %O",
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
173 cl->buf->temporary, cl->buf->in_file,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
174 cl->buf->start, cl->buf->pos,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
175 cl->buf->last - cl->buf->pos,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
176 cl->buf->file_pos,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
177 cl->buf->file_last - cl->buf->file_pos);
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
178
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
179 if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
180 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
181 "zero size buf in writer "
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
182 "t:%d r:%d f:%d %p %p-%p %p %O-%O",
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
183 cl->buf->temporary,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
184 cl->buf->recycled,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
185 cl->buf->in_file,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
186 cl->buf->start,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
187 cl->buf->pos,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
188 cl->buf->last,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
189 cl->buf->file,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
190 cl->buf->file_pos,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
191 cl->buf->file_last);
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
192
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
193 ngx_debug_point();
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
194 return NGX_ERROR;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
195 }
7401
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
196
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
197 if (ngx_buf_size(cl->buf) < 0) {
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
198 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
199 "negative size buf in writer "
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
200 "t:%d r:%d f:%d %p %p-%p %p %O-%O",
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
201 cl->buf->temporary,
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
202 cl->buf->recycled,
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
203 cl->buf->in_file,
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
204 cl->buf->start,
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
205 cl->buf->pos,
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
206 cl->buf->last,
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
207 cl->buf->file,
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
208 cl->buf->file_pos,
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
209 cl->buf->file_last);
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
210
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
211 ngx_debug_point();
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
212 return NGX_ERROR;
a7ff19afbb14 Negative size buffers detection.
Maxim Dounin <mdounin@mdounin.ru>
parents: 6692
diff changeset
213 }
6692
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
214
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
215 size += ngx_buf_size(cl->buf);
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
216
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
217 if (cl->buf->flush || cl->buf->recycled) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
218 flush = 1;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
219 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
220
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
221 if (cl->buf->sync) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
222 sync = 1;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
223 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
224
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
225 if (cl->buf->last_buf) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
226 last = 1;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
227 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
228 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
229
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
230 *ll = NULL;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
231
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
232 ngx_log_debug3(NGX_LOG_DEBUG_STREAM, c->log, 0,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
233 "stream write filter: l:%ui f:%ui s:%O", last, flush, size);
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
234
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
235 if (size == 0
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
236 && !(c->buffered & NGX_LOWLEVEL_BUFFERED)
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
237 && !(last && c->need_last_buf))
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
238 {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
239 if (last || flush || sync) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
240 for (cl = *out; cl; /* void */) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
241 ln = cl;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
242 cl = cl->next;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
243 ngx_free_chain(c->pool, ln);
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
244 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
245
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
246 *out = NULL;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
247 c->buffered &= ~NGX_STREAM_WRITE_BUFFERED;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
248
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
249 return NGX_OK;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
250 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
251
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
252 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
253 "the stream output chain is empty");
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
254
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
255 ngx_debug_point();
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
256
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
257 return NGX_ERROR;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
258 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
259
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
260 chain = c->send_chain(c, *out, 0);
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
261
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
262 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
263 "stream write filter %p", chain);
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
264
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
265 if (chain == NGX_CHAIN_ERROR) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
266 c->error = 1;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
267 return NGX_ERROR;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
268 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
269
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
270 for (cl = *out; cl && cl != chain; /* void */) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
271 ln = cl;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
272 cl = cl->next;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
273 ngx_free_chain(c->pool, ln);
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
274 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
275
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
276 *out = chain;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
277
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
278 if (chain) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
279 if (c->shared) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
280 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
281 "shared connection is busy");
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
282 return NGX_ERROR;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
283 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
284
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
285 c->buffered |= NGX_STREAM_WRITE_BUFFERED;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
286 return NGX_AGAIN;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
287 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
288
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
289 c->buffered &= ~NGX_STREAM_WRITE_BUFFERED;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
290
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
291 if (c->buffered & NGX_LOWLEVEL_BUFFERED) {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
292 return NGX_AGAIN;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
293 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
294
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
295 return NGX_OK;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
296 }
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
297
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
298
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
299 static ngx_int_t
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
300 ngx_stream_write_filter_init(ngx_conf_t *cf)
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
301 {
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
302 ngx_stream_top_filter = ngx_stream_write_filter;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
303
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
304 return NGX_OK;
56fc55e32f23 Stream: filters.
Roman Arutyunyan <arut@nginx.com>
parents:
diff changeset
305 }