comparison src/imap/ngx_imap_proxy_module.c @ 521:6f00349b98e5 release-0.1.35

nginx-0.1.35-RELEASE import *) Feature: the "working_directory" directive. *) Feature: the "port_in_redirect" directive. *) Bugfix: the segmentation fault was occurred if the backend response header was in several packets; the bug had appeared in 0.1.29. *) Bugfix: if more than 10 servers were configured or some server did not use the "listen" directive, then the segmentation fault was occurred on the start. *) Bugfix: the segmentation fault might occur if the response was bigger than the temporary file. *) Bugfix: nginx returned the 400 response on requests like "GET http://www.domain.com/uri HTTP/1.0"; the bug had appeared in 0.1.28.
author Igor Sysoev <igor@sysoev.ru>
date Tue, 07 Jun 2005 15:56:31 +0000
parents src/imap/ngx_imap_proxy.c@9b8c906f6e63
children 7fa11e5c6e96
comparison
equal deleted inserted replaced
520:1fecc7e0d717 521:6f00349b98e5
1
2 /*
3 * Copyright (C) Igor Sysoev
4 */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_event.h>
10 #include <ngx_event_connect.h>
11 #include <ngx_imap.h>
12
13
14 typedef struct {
15 ngx_flag_t enable;
16 } ngx_imap_proxy_conf_t;
17
18
19 static void ngx_imap_proxy_block_read(ngx_event_t *rev);
20 static void ngx_imap_proxy_auth_handler(ngx_event_t *rev);
21 static void ngx_imap_proxy_dummy_handler(ngx_event_t *ev);
22 static ngx_int_t ngx_imap_proxy_read_response(ngx_imap_session_t *s);
23 static void ngx_imap_proxy_handler(ngx_event_t *ev);
24 static void ngx_imap_proxy_close_session(ngx_imap_session_t *s);
25 static void *ngx_imap_proxy_create_conf(ngx_conf_t *cf);
26 static char *ngx_imap_proxy_merge_conf(ngx_conf_t *cf, void *parent,
27 void *child);
28
29
30 static ngx_command_t ngx_imap_proxy_commands[] = {
31 { ngx_string("proxy"),
32 NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_FLAG,
33 ngx_conf_set_flag_slot,
34 NGX_IMAP_SRV_CONF_OFFSET,
35 offsetof(ngx_imap_proxy_conf_t, enable),
36 NULL },
37
38 ngx_null_command
39 };
40
41
42 static ngx_imap_module_t ngx_imap_proxy_module_ctx = {
43 NULL, /* create main configuration */
44 NULL, /* init main configuration */
45
46 ngx_imap_proxy_create_conf, /* create server configuration */
47 ngx_imap_proxy_merge_conf /* merge server configuration */
48 };
49
50
51 ngx_module_t ngx_imap_proxy_module = {
52 NGX_MODULE_V1,
53 &ngx_imap_proxy_module_ctx, /* module context */
54 ngx_imap_proxy_commands, /* module directives */
55 NGX_IMAP_MODULE, /* module type */
56 NULL, /* init module */
57 NULL /* init process */
58 };
59
60
61 void
62 ngx_imap_proxy_init(ngx_imap_session_t *s, ngx_peers_t *peers)
63 {
64 ngx_int_t rc;
65 ngx_imap_proxy_ctx_t *p;
66
67 p = ngx_pcalloc(s->connection->pool, sizeof(ngx_imap_proxy_ctx_t));
68 if (p == NULL) {
69 ngx_imap_close_connection(s->connection);
70 return;
71 }
72
73 s->proxy = p;
74
75 p->upstream.peers = peers;
76 p->upstream.log = s->connection->log;
77 p->upstream.log_error = NGX_ERROR_ERR;
78
79 rc = ngx_event_connect_peer(&p->upstream);
80
81 if (rc == NGX_ERROR) {
82 ngx_imap_proxy_close_session(s);
83 return;
84 }
85
86 p->upstream.connection->data = s;
87 p->upstream.connection->pool = s->connection->pool;
88
89 s->connection->read->handler = ngx_imap_proxy_block_read;
90 p->upstream.connection->read->handler = ngx_imap_proxy_auth_handler;
91 p->upstream.connection->write->handler = ngx_imap_proxy_dummy_handler;
92 }
93
94
95 static void
96 ngx_imap_proxy_block_read(ngx_event_t *rev)
97 {
98 ngx_connection_t *c;
99 ngx_imap_session_t *s;
100
101 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy block read");
102
103 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
104 c = rev->data;
105 s = c->data;
106
107 ngx_imap_proxy_close_session(s);
108 }
109 }
110
111
112 static void
113 ngx_imap_proxy_auth_handler(ngx_event_t *rev)
114 {
115 u_char *p;
116 ngx_int_t rc;
117 ngx_str_t line;
118 ngx_connection_t *c;
119 ngx_imap_session_t *s;
120
121 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy auth handler");
122
123 c = rev->data;
124 s = c->data;
125
126 if (rev->timedout) {
127 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
128 ngx_imap_proxy_close_session(s);
129 return;
130 }
131
132 if (s->proxy->buffer == NULL) {
133 s->proxy->buffer = ngx_create_temp_buf(c->pool, /* STUB */ 4096);
134 if (s->proxy->buffer == NULL) {
135 ngx_imap_proxy_close_session(s);
136 return;
137 }
138 }
139
140 rc = ngx_imap_proxy_read_response(s);
141
142 if (rc == NGX_AGAIN) {
143 return;
144 }
145
146 if (rc == NGX_ERROR) {
147 /* TODO: ngx_imap_proxy_finalize_session(s, NGX_IMAP_INTERNAL_ERROR) */
148 ngx_imap_proxy_close_session(s);
149 return;
150 }
151
152 if (s->imap_state == ngx_pop3_start) {
153
154 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy send user");
155
156 line.len = sizeof("USER ") + s->login.len - 1 + 2;
157 line.data = ngx_palloc(c->pool, line.len);
158 if (line.data == NULL) {
159 ngx_imap_proxy_close_session(s);
160 return;
161 }
162
163 p = ngx_cpymem(line.data, "USER ", sizeof("USER ") - 1);
164 p = ngx_cpymem(p, s->login.data, s->login.len);
165 *p++ = CR; *p = LF;
166
167 if (ngx_send(c, line.data, line.len) < (ssize_t) line.len) {
168 /*
169 * we treat the incomplete sending as NGX_ERROR
170 * because it is very strange here
171 */
172 ngx_imap_close_connection(c);
173 return;
174 }
175
176 s->imap_state = ngx_pop3_user;
177
178 s->proxy->buffer->pos = s->proxy->buffer->start;
179 s->proxy->buffer->last = s->proxy->buffer->start;
180
181 return;
182 }
183
184 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy send pass");
185
186 line.len = sizeof("PASS ") + s->passwd.len - 1 + 2;
187 line.data = ngx_palloc(c->pool, line.len);
188 if (line.data == NULL) {
189 ngx_imap_proxy_close_session(s);
190 return;
191 }
192
193 p = ngx_cpymem(line.data, "PASS ", sizeof("PASS ") - 1);
194 p = ngx_cpymem(p, s->passwd.data, s->passwd.len);
195 *p++ = CR; *p = LF;
196
197 if (ngx_send(c, line.data, line.len) < (ssize_t) line.len) {
198 /*
199 * we treat the incomplete sending as NGX_ERROR
200 * because it is very strange here
201 */
202 ngx_imap_close_connection(c);
203 return;
204 }
205
206 s->proxy->buffer->pos = s->proxy->buffer->start;
207 s->proxy->buffer->last = s->proxy->buffer->start;
208
209 s->connection->read->handler = ngx_imap_proxy_handler;
210 s->connection->write->handler = ngx_imap_proxy_handler;
211 rev->handler = ngx_imap_proxy_handler;
212 c->write->handler = ngx_imap_proxy_handler;
213 }
214
215
216 static void
217 ngx_imap_proxy_dummy_handler(ngx_event_t *ev)
218 {
219 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, ev->log, 0, "imap proxy dummy handler");
220 }
221
222
223 static ngx_int_t
224 ngx_imap_proxy_read_response(ngx_imap_session_t *s)
225 {
226 u_char *p;
227 ssize_t n;
228 ngx_buf_t *b;
229
230 b = s->proxy->buffer;
231
232 n = ngx_recv(s->proxy->upstream.connection, b->last, b->end - b->last);
233
234 if (n == NGX_ERROR || n == 0) {
235 return NGX_ERROR;
236 }
237
238 if (n == NGX_AGAIN) {
239 return NGX_AGAIN;
240 }
241
242 b->last += n;
243
244 if (b->last - b->pos < 5) {
245 return NGX_AGAIN;
246 }
247
248 if (*(b->last - 2) != CR || *(b->last - 1) != LF) {
249 if (b->last == b->end) {
250 *(b->last - 1) = '\0';
251 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
252 "upstream sent too long response line: \"%s\"",
253 b->pos);
254 return NGX_IMAP_PROXY_INVALID;
255 }
256
257 return NGX_AGAIN;
258 }
259
260 p = b->pos;
261
262 if (p[0] == '+' && p[1] == 'O' && p[2] == 'K') {
263 return NGX_OK;
264 }
265
266 if (p[0] == '-' && p[1] == 'E' && p[2] == 'R' && p[3] == 'R') {
267 return NGX_IMAP_PROXY_ERROR;
268 }
269
270 *(b->last - 2) = '\0';
271 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
272 "upstream sent invalid greeting line: \"%s\"", p);
273
274 return NGX_IMAP_PROXY_INVALID;
275 }
276
277
278 static void
279 ngx_imap_proxy_handler(ngx_event_t *ev)
280 {
281 size_t size;
282 ssize_t n;
283 ngx_buf_t *b;
284 ngx_uint_t again, do_write;
285 ngx_connection_t *c, *src, *dst;
286 ngx_imap_session_t *s;
287
288 c = ev->data;
289 s = c->data;
290
291 if (ev->timedout) {
292 if (c == s->connection) {
293 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
294 "client timed out");
295 } else {
296 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
297 "upstream timed out");
298 }
299
300 ngx_imap_proxy_close_session(s);
301 return;
302 }
303
304 if (c == s->connection) {
305 if (ev->write) {
306 src = s->proxy->upstream.connection;
307 dst = c;
308 b = s->proxy->buffer;
309
310 } else {
311 src = c;
312 dst = s->proxy->upstream.connection;
313 b = s->buffer;
314 }
315
316 } else {
317 if (ev->write) {
318 src = s->connection;
319 dst = c;
320 b = s->buffer;
321
322 } else {
323 src = c;
324 dst = s->connection;
325 b = s->proxy->buffer;
326 }
327 }
328
329 do_write = ev->write ? 1 : 0;
330
331 ngx_log_debug3(NGX_LOG_DEBUG_IMAP, ev->log, 0,
332 "imap proxy handler: %d, #%d > #%d",
333 do_write, src->fd, dst->fd);
334
335 do {
336 again = 0;
337
338 if (do_write == 1) {
339
340 size = b->last - b->pos;
341
342 if (size && dst->write->ready) {
343 n = ngx_send(dst, b->pos, size);
344
345 if (n == NGX_ERROR) {
346 ngx_imap_proxy_close_session(s);
347 return;
348 }
349
350 if (n > 0) {
351 again = 1;
352 b->pos += n;
353
354 if (b->pos == b->last) {
355 b->pos = b->start;
356 b->last = b->start;
357 }
358 }
359
360 if (n == NGX_AGAIN || n < (ssize_t) size) {
361 if (ngx_handle_write_event(dst->write, /* TODO: LOWAT */ 0)
362 == NGX_ERROR)
363 {
364 ngx_imap_proxy_close_session(s);
365 return;
366 }
367 }
368 }
369 }
370
371 size = b->end - b->last;
372
373 if (size && src->read->ready) {
374 n = ngx_recv(src, b->last, size);
375
376 if (n == NGX_ERROR || n == 0) {
377 ngx_imap_proxy_close_session(s);
378 return;
379 }
380
381 if (n > 0) {
382 again = 1;
383 do_write = 1;
384 b->last += n;
385 }
386
387 if (n == NGX_AGAIN || n < (ssize_t) size) {
388 if (ngx_handle_read_event(src->read, 0) == NGX_ERROR) {
389 ngx_imap_proxy_close_session(s);
390 return;
391 }
392 }
393 }
394
395 } while (again);
396 }
397
398
399 static void
400 ngx_imap_proxy_close_session(ngx_imap_session_t *s)
401 {
402 if (s->proxy->upstream.connection) {
403 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
404 "close imap proxy connection: %d",
405 s->proxy->upstream.connection->fd);
406
407 ngx_close_connection(s->proxy->upstream.connection);
408 }
409
410 ngx_imap_close_connection(s->connection);
411 }
412
413
414 static void *
415 ngx_imap_proxy_create_conf(ngx_conf_t *cf)
416 {
417 ngx_imap_proxy_conf_t *pcf;
418
419 pcf = ngx_pcalloc(cf->pool, sizeof(ngx_imap_proxy_conf_t));
420 if (pcf == NULL) {
421 return NGX_CONF_ERROR;
422 }
423
424 pcf->enable = NGX_CONF_UNSET;
425
426 return pcf;
427 }
428
429
430 static char *
431 ngx_imap_proxy_merge_conf(ngx_conf_t *cf, void *parent, void *child)
432 {
433 ngx_imap_proxy_conf_t *prev = parent;
434 ngx_imap_proxy_conf_t *conf = child;
435
436 ngx_conf_merge_msec_value(conf->enable, prev->enable, 0);
437
438 return NGX_CONF_OK;
439 }