comparison src/imap/ngx_imap_proxy_module.c @ 527:7fa11e5c6e96 release-0.1.38

nginx-0.1.38-RELEASE import *) Feature: the "limit_rate" directive is supported in in proxy and FastCGI mode. *) Feature: the "X-Accel-Limit-Rate" response header line is supported in proxy and FastCGI mode. *) Feature: the "break" directive. *) Feature: the "log_not_found" directive. *) Bugfix: the response status code was not changed when request was redirected by the ""X-Accel-Redirect" header line. *) Bugfix: the variables set by the "set" directive could not be used in SSI. *) Bugfix: the segmentation fault may occurred if the SSI page has more than one remote subrequest. *) Bugfix: nginx treated the backend response as invalid if the status line in the header was transferred in two packets; the bug had appeared in 0.1.29. *) Feature: the "ssi_types" directive. *) Feature: the "autoindex_exact_size" directive. *) Bugfix: the ngx_http_autoindex_module did not support the long file names in UTF-8. *) Feature: the IMAP/POP3 proxy.
author Igor Sysoev <igor@sysoev.ru>
date Fri, 08 Jul 2005 14:34:20 +0000
parents 6f00349b98e5
children e5d7d0334fdb
comparison
equal deleted inserted replaced
526:e31ce4d8b8e6 527:7fa11e5c6e96
15 ngx_flag_t enable; 15 ngx_flag_t enable;
16 } ngx_imap_proxy_conf_t; 16 } ngx_imap_proxy_conf_t;
17 17
18 18
19 static void ngx_imap_proxy_block_read(ngx_event_t *rev); 19 static void ngx_imap_proxy_block_read(ngx_event_t *rev);
20 static void ngx_imap_proxy_auth_handler(ngx_event_t *rev); 20 static void ngx_imap_proxy_imap_handler(ngx_event_t *rev);
21 static void ngx_imap_proxy_pop3_handler(ngx_event_t *rev);
21 static void ngx_imap_proxy_dummy_handler(ngx_event_t *ev); 22 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 ngx_int_t ngx_imap_proxy_read_response(ngx_imap_session_t *s,
24 ngx_uint_t what);
23 static void ngx_imap_proxy_handler(ngx_event_t *ev); 25 static void ngx_imap_proxy_handler(ngx_event_t *ev);
26 static void ngx_imap_proxy_internal_server_error(ngx_imap_session_t *s);
24 static void ngx_imap_proxy_close_session(ngx_imap_session_t *s); 27 static void ngx_imap_proxy_close_session(ngx_imap_session_t *s);
25 static void *ngx_imap_proxy_create_conf(ngx_conf_t *cf); 28 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, 29 static char *ngx_imap_proxy_merge_conf(ngx_conf_t *cf, void *parent,
27 void *child); 30 void *child);
31
32
33 #define NGX_IMAP_WAIT_OK 0
34 #define NGX_IMAP_WAIT_NEXT 1
28 35
29 36
30 static ngx_command_t ngx_imap_proxy_commands[] = { 37 static ngx_command_t ngx_imap_proxy_commands[] = {
31 { ngx_string("proxy"), 38 { ngx_string("proxy"),
32 NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_FLAG, 39 NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_FLAG,
59 66
60 67
61 void 68 void
62 ngx_imap_proxy_init(ngx_imap_session_t *s, ngx_peers_t *peers) 69 ngx_imap_proxy_init(ngx_imap_session_t *s, ngx_peers_t *peers)
63 { 70 {
64 ngx_int_t rc; 71 ngx_int_t rc;
65 ngx_imap_proxy_ctx_t *p; 72 ngx_imap_proxy_ctx_t *p;
73 ngx_imap_core_srv_conf_t *cscf;
66 74
67 p = ngx_pcalloc(s->connection->pool, sizeof(ngx_imap_proxy_ctx_t)); 75 p = ngx_pcalloc(s->connection->pool, sizeof(ngx_imap_proxy_ctx_t));
68 if (p == NULL) { 76 if (p == NULL) {
69 ngx_imap_close_connection(s->connection); 77 ngx_imap_session_internal_server_error(s);
70 return; 78 return;
71 } 79 }
72 80
73 s->proxy = p; 81 s->proxy = p;
74 82
77 p->upstream.log_error = NGX_ERROR_ERR; 85 p->upstream.log_error = NGX_ERROR_ERR;
78 86
79 rc = ngx_event_connect_peer(&p->upstream); 87 rc = ngx_event_connect_peer(&p->upstream);
80 88
81 if (rc == NGX_ERROR) { 89 if (rc == NGX_ERROR) {
82 ngx_imap_proxy_close_session(s); 90 ngx_imap_session_internal_server_error(s);
83 return; 91 return;
84 } 92 }
93
94 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
95 ngx_add_timer(p->upstream.connection->read, cscf->timeout);
85 96
86 p->upstream.connection->data = s; 97 p->upstream.connection->data = s;
87 p->upstream.connection->pool = s->connection->pool; 98 p->upstream.connection->pool = s->connection->pool;
88 99
89 s->connection->read->handler = ngx_imap_proxy_block_read; 100 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; 101 p->upstream.connection->write->handler = ngx_imap_proxy_dummy_handler;
102
103 if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
104 p->upstream.connection->read->handler = ngx_imap_proxy_pop3_handler;
105 s->imap_state = ngx_pop3_start;
106
107 } else {
108 p->upstream.connection->read->handler = ngx_imap_proxy_imap_handler;
109 s->imap_state = ngx_imap_start;
110 }
92 } 111 }
93 112
94 113
95 static void 114 static void
96 ngx_imap_proxy_block_read(ngx_event_t *rev) 115 ngx_imap_proxy_block_read(ngx_event_t *rev)
108 } 127 }
109 } 128 }
110 129
111 130
112 static void 131 static void
113 ngx_imap_proxy_auth_handler(ngx_event_t *rev) 132 ngx_imap_proxy_imap_handler(ngx_event_t *rev)
114 { 133 {
115 u_char *p; 134 u_char *p;
116 ngx_int_t rc; 135 ngx_int_t rc;
117 ngx_str_t line; 136 ngx_str_t line;
118 ngx_connection_t *c; 137 ngx_connection_t *c;
119 ngx_imap_session_t *s; 138 ngx_imap_session_t *s;
120 139 ngx_imap_core_srv_conf_t *cscf;
121 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy auth handler"); 140
141 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0,
142 "imap proxy imap auth handler");
122 143
123 c = rev->data; 144 c = rev->data;
124 s = c->data; 145 s = c->data;
125 146
126 if (rev->timedout) { 147 if (rev->timedout) {
127 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); 148 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
128 ngx_imap_proxy_close_session(s); 149 "upstream timed out");
150 ngx_imap_proxy_internal_server_error(s);
129 return; 151 return;
130 } 152 }
131 153
132 if (s->proxy->buffer == NULL) { 154 if (s->proxy->buffer == NULL) {
133 s->proxy->buffer = ngx_create_temp_buf(c->pool, /* STUB */ 4096); 155 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
156
157 s->proxy->buffer = ngx_create_temp_buf(c->pool,
158 cscf->proxy_buffer_size);
134 if (s->proxy->buffer == NULL) { 159 if (s->proxy->buffer == NULL) {
135 ngx_imap_proxy_close_session(s); 160 ngx_imap_proxy_internal_server_error(s);
136 return; 161 return;
137 } 162 }
138 } 163 }
139 164
140 rc = ngx_imap_proxy_read_response(s); 165 rc = ngx_imap_proxy_read_response(s, s->imap_state == ngx_imap_start ?
166 NGX_IMAP_WAIT_OK : NGX_IMAP_WAIT_NEXT);
141 167
142 if (rc == NGX_AGAIN) { 168 if (rc == NGX_AGAIN) {
143 return; 169 return;
144 } 170 }
145 171
146 if (rc == NGX_ERROR) { 172 if (rc == NGX_ERROR) {
147 /* TODO: ngx_imap_proxy_finalize_session(s, NGX_IMAP_INTERNAL_ERROR) */ 173 ngx_imap_proxy_internal_server_error(s);
148 ngx_imap_proxy_close_session(s); 174 return;
149 return; 175 }
150 } 176
151 177 switch (s->imap_state) {
152 if (s->imap_state == ngx_pop3_start) { 178
153 179 case ngx_imap_start:
154 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy send user"); 180 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0,
155 181 "imap proxy send login");
156 line.len = sizeof("USER ") + s->login.len - 1 + 2; 182
183 line.len = s->tag.len + sizeof("LOGIN ") - 1
184 + 1 + NGX_SIZE_T_LEN + 1 + 2;
157 line.data = ngx_palloc(c->pool, line.len); 185 line.data = ngx_palloc(c->pool, line.len);
158 if (line.data == NULL) { 186 if (line.data == NULL) {
159 ngx_imap_proxy_close_session(s); 187 ngx_imap_proxy_internal_server_error(s);
160 return; 188 return;
161 } 189 }
162 190
163 p = ngx_cpymem(line.data, "USER ", sizeof("USER ") - 1); 191 line.len = ngx_sprintf(line.data, "%VLOGIN {%uz}" CRLF,
164 p = ngx_cpymem(p, s->login.data, s->login.len); 192 &s->tag, s->login.len)
193 - line.data;
194
195 s->imap_state = ngx_imap_login;
196 break;
197
198 case ngx_imap_login:
199 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy send user");
200
201 line.len = s->login.len + 1 + NGX_SIZE_T_LEN + 1 + 2;
202 line.data = ngx_palloc(c->pool, line.len);
203 if (line.data == NULL) {
204 ngx_imap_proxy_internal_server_error(s);
205 return;
206 }
207
208 line.len = ngx_sprintf(line.data, "%V{%uz}" CRLF,
209 &s->login, s->passwd.len)
210 - line.data;
211
212 s->imap_state = ngx_imap_user;
213 break;
214
215 case ngx_imap_user:
216 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0,
217 "imap proxy send passwd");
218
219 line.len = s->passwd.len + 2;
220 line.data = ngx_palloc(c->pool, line.len);
221 if (line.data == NULL) {
222 ngx_imap_proxy_internal_server_error(s);
223 return;
224 }
225
226 p = ngx_cpymem(line.data, s->passwd.data, s->passwd.len);
165 *p++ = CR; *p = LF; 227 *p++ = CR; *p = LF;
166 228
167 if (ngx_send(c, line.data, line.len) < (ssize_t) line.len) { 229 s->imap_state = ngx_imap_passwd;
168 /* 230 break;
169 * we treat the incomplete sending as NGX_ERROR 231
170 * because it is very strange here 232 default:
171 */ 233 #if (NGX_SUPPRESS_WARN)
172 ngx_imap_close_connection(c); 234 line.len = 0;
173 return; 235 line.data = NULL;
174 } 236 #endif
175 237 break;
176 s->imap_state = ngx_pop3_user; 238 }
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 239
197 if (ngx_send(c, line.data, line.len) < (ssize_t) line.len) { 240 if (ngx_send(c, line.data, line.len) < (ssize_t) line.len) {
198 /* 241 /*
199 * we treat the incomplete sending as NGX_ERROR 242 * we treat the incomplete sending as NGX_ERROR
200 * because it is very strange here 243 * because it is very strange here
201 */ 244 */
202 ngx_imap_close_connection(c); 245 ngx_imap_proxy_internal_server_error(s);
203 return; 246 return;
204 } 247 }
205 248
206 s->proxy->buffer->pos = s->proxy->buffer->start; 249 s->proxy->buffer->pos = s->proxy->buffer->start;
207 s->proxy->buffer->last = s->proxy->buffer->start; 250 s->proxy->buffer->last = s->proxy->buffer->start;
208 251
209 s->connection->read->handler = ngx_imap_proxy_handler; 252 if (s->imap_state == ngx_imap_passwd) {
210 s->connection->write->handler = ngx_imap_proxy_handler; 253 s->connection->read->handler = ngx_imap_proxy_handler;
211 rev->handler = ngx_imap_proxy_handler; 254 s->connection->write->handler = ngx_imap_proxy_handler;
212 c->write->handler = ngx_imap_proxy_handler; 255 rev->handler = ngx_imap_proxy_handler;
256 c->write->handler = ngx_imap_proxy_handler;
257 }
258 }
259
260
261 static void
262 ngx_imap_proxy_pop3_handler(ngx_event_t *rev)
263 {
264 u_char *p;
265 ngx_int_t rc;
266 ngx_str_t line;
267 ngx_connection_t *c;
268 ngx_imap_session_t *s;
269 ngx_imap_core_srv_conf_t *cscf;
270
271 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0,
272 "imap proxy pop3 auth handler");
273
274 c = rev->data;
275 s = c->data;
276
277 if (rev->timedout) {
278 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
279 "upstream timed out");
280 ngx_imap_proxy_internal_server_error(s);
281 return;
282 }
283
284 if (s->proxy->buffer == NULL) {
285 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
286
287 s->proxy->buffer = ngx_create_temp_buf(c->pool,
288 cscf->proxy_buffer_size);
289 if (s->proxy->buffer == NULL) {
290 ngx_imap_proxy_internal_server_error(s);
291 return;
292 }
293 }
294
295 rc = ngx_imap_proxy_read_response(s, NGX_IMAP_WAIT_OK);
296
297 if (rc == NGX_AGAIN) {
298 return;
299 }
300
301 if (rc == NGX_ERROR) {
302 ngx_imap_proxy_internal_server_error(s);
303 return;
304 }
305
306 switch (s->imap_state) {
307
308 case ngx_pop3_start:
309 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy send user");
310
311 line.len = sizeof("USER ") - 1 + s->login.len + 2;
312 line.data = ngx_palloc(c->pool, line.len);
313 if (line.data == NULL) {
314 ngx_imap_proxy_internal_server_error(s);
315 return;
316 }
317
318 p = ngx_cpymem(line.data, "USER ", sizeof("USER ") - 1);
319 p = ngx_cpymem(p, s->login.data, s->login.len);
320 *p++ = CR; *p = LF;
321
322 s->imap_state = ngx_pop3_user;
323 break;
324
325 case ngx_pop3_user:
326 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy send pass");
327
328 line.len = sizeof("PASS ") - 1 + s->passwd.len + 2;
329 line.data = ngx_palloc(c->pool, line.len);
330 if (line.data == NULL) {
331 ngx_imap_proxy_internal_server_error(s);
332 return;
333 }
334
335 p = ngx_cpymem(line.data, "PASS ", sizeof("PASS ") - 1);
336 p = ngx_cpymem(p, s->passwd.data, s->passwd.len);
337 *p++ = CR; *p = LF;
338
339 s->imap_state = ngx_pop3_passwd;
340 break;
341
342 default:
343 #if (NGX_SUPPRESS_WARN)
344 line.len = 0;
345 line.data = NULL;
346 #endif
347 break;
348 }
349
350 if (ngx_send(c, line.data, line.len) < (ssize_t) line.len) {
351 /*
352 * we treat the incomplete sending as NGX_ERROR
353 * because it is very strange here
354 */
355 ngx_imap_proxy_internal_server_error(s);
356 return;
357 }
358
359 s->proxy->buffer->pos = s->proxy->buffer->start;
360 s->proxy->buffer->last = s->proxy->buffer->start;
361
362 if (s->imap_state == ngx_pop3_passwd) {
363 s->connection->read->handler = ngx_imap_proxy_handler;
364 s->connection->write->handler = ngx_imap_proxy_handler;
365 rev->handler = ngx_imap_proxy_handler;
366 c->write->handler = ngx_imap_proxy_handler;
367 }
213 } 368 }
214 369
215 370
216 static void 371 static void
217 ngx_imap_proxy_dummy_handler(ngx_event_t *ev) 372 ngx_imap_proxy_dummy_handler(ngx_event_t *ev)
219 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, ev->log, 0, "imap proxy dummy handler"); 374 ngx_log_debug0(NGX_LOG_DEBUG_IMAP, ev->log, 0, "imap proxy dummy handler");
220 } 375 }
221 376
222 377
223 static ngx_int_t 378 static ngx_int_t
224 ngx_imap_proxy_read_response(ngx_imap_session_t *s) 379 ngx_imap_proxy_read_response(ngx_imap_session_t *s, ngx_uint_t what)
225 { 380 {
226 u_char *p; 381 u_char *p;
227 ssize_t n; 382 ssize_t n;
228 ngx_buf_t *b; 383 ngx_buf_t *b;
229 384
257 return NGX_AGAIN; 412 return NGX_AGAIN;
258 } 413 }
259 414
260 p = b->pos; 415 p = b->pos;
261 416
262 if (p[0] == '+' && p[1] == 'O' && p[2] == 'K') { 417 if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
263 return NGX_OK; 418 if (p[0] == '+' && p[1] == 'O' && p[2] == 'K') {
264 } 419 return NGX_OK;
265 420 }
266 if (p[0] == '-' && p[1] == 'E' && p[2] == 'R' && p[3] == 'R') { 421
267 return NGX_IMAP_PROXY_ERROR; 422 if (p[0] == '-' && p[1] == 'E' && p[2] == 'R' && p[3] == 'R') {
423 return NGX_IMAP_PROXY_ERROR;
424 }
425
426 } else {
427 if (what == NGX_IMAP_WAIT_OK) {
428 if (p[0] == '*' && p[1] == ' ' && p[2] == 'O' && p[3] == 'K') {
429 return NGX_OK;
430 }
431
432 } else {
433 if (p[0] == '+' && p[1] == ' ' && p[2] == 'O' && p[3] == 'K') {
434 return NGX_OK;
435 }
436 }
268 } 437 }
269 438
270 *(b->last - 2) = '\0'; 439 *(b->last - 2) = '\0';
271 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, 440 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
272 "upstream sent invalid greeting line: \"%s\"", p); 441 "upstream sent invalid response: \"%s\"", p);
273 442
274 return NGX_IMAP_PROXY_INVALID; 443 return NGX_IMAP_PROXY_INVALID;
275 } 444 }
276 445
277 446
395 } while (again); 564 } while (again);
396 } 565 }
397 566
398 567
399 static void 568 static void
569 ngx_imap_proxy_internal_server_error(ngx_imap_session_t *s)
570 {
571 if (s->proxy->upstream.connection) {
572 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
573 "close imap proxy connection: %d",
574 s->proxy->upstream.connection->fd);
575
576 ngx_close_connection(s->proxy->upstream.connection);
577 }
578
579 ngx_imap_session_internal_server_error(s);
580 }
581
582
583 static void
400 ngx_imap_proxy_close_session(ngx_imap_session_t *s) 584 ngx_imap_proxy_close_session(ngx_imap_session_t *s)
401 { 585 {
402 if (s->proxy->upstream.connection) { 586 if (s->proxy->upstream.connection) {
403 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, s->connection->log, 0, 587 ngx_log_debug1(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
404 "close imap proxy connection: %d", 588 "close imap proxy connection: %d",