00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <ngx_config.h>
00023 #include <ngx_core.h>
00024 #include <ngx_http.h>
00025 #include <ngx_md5.h>
00026
00027 #include "ngx_http_mxcache_module.h"
00028 #include "ngx_connection_pool.h"
00029
00030 static void *
00031 ngx_http_mxcache_create_conf(ngx_conf_t *cf);
00032 static char *
00033 ngx_http_mxcache_merge_conf(ngx_conf_t *cf, void *parent, void *child);
00034
00036 static ngx_command_t ngx_http_mxcache_commands[] = {
00037
00038 { ngx_string("mxcache"),
00039 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1|NGX_CONF_FLAG,
00040 ngx_conf_set_flag_slot,
00041 NGX_HTTP_LOC_CONF_OFFSET,
00042 offsetof(ngx_http_mxcache_conf_t, enabled),
00043 NULL },
00044
00045 { ngx_string( "mxcache_server_timeout" ),
00046 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
00047 ngx_conf_set_msec_slot,
00048 NGX_HTTP_LOC_CONF_OFFSET,
00049 offsetof(ngx_http_mxcache_conf_t, server_timeout),
00050 NULL },
00051
00052 { ngx_string( "mxcache_server_ip" ),
00053 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
00054 ngx_conf_set_str_slot,
00055 NGX_HTTP_LOC_CONF_OFFSET,
00056 offsetof(ngx_http_mxcache_conf_t, server_ip ),
00057 NULL },
00058
00059 { ngx_string( "mxcache_server_port" ),
00060 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
00061 ngx_conf_set_num_slot,
00062 NGX_HTTP_LOC_CONF_OFFSET,
00063 offsetof( ngx_http_mxcache_conf_t, server_port ),
00064 NULL },
00065
00066 { ngx_string( "mxcache_expire" ),
00067 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
00068 ngx_conf_set_msec_slot,
00069 NGX_HTTP_LOC_CONF_OFFSET,
00070 offsetof( ngx_http_mxcache_conf_t, expire ),
00071 NULL },
00072
00073 ngx_null_command
00074 };
00075
00077 static ngx_http_module_t ngx_http_mxcache_module_ctx = {
00078 NULL,NULL,NULL,NULL,NULL,NULL,
00079 ngx_http_mxcache_create_conf,
00080 ngx_http_mxcache_merge_conf
00081 };
00082
00084 ngx_module_t ngx_http_mxcache_module = {
00085 NGX_MODULE_V1,
00086 &ngx_http_mxcache_module_ctx,
00087 ngx_http_mxcache_commands,
00088 NGX_HTTP_MODULE,
00089 NULL,
00090 NULL,
00091 NULL,
00092 NULL,
00093 NULL,
00094 NULL,
00095 NULL,
00096 NGX_MODULE_V1_PADDING
00097 };
00098
00099
00100
00101 ngx_http_mxcache_conn_t *
00102 ngx_http_mxcache_create_new(ngx_http_request_t *r);
00103 ngx_int_t
00104 ngx_http_mxcache_get(ngx_http_mxcache_conn_t *conn);
00105 ngx_int_t
00106 ngx_http_mxcache_set(ngx_http_mxcache_conn_t *conn);
00107 ngx_int_t
00108 ngx_http_mxcache_cleanup(ngx_http_mxcache_conn_t *conn);
00109 static ngx_int_t
00110 ngx_http_mxcache_init_conn(ngx_http_mxcache_conn_t *conn);
00111 static ngx_int_t
00112 ngx_http_mxcache_create_get_request(ngx_http_mxcache_conn_t *conn);
00113 static ngx_int_t
00114 ngx_http_mxcache_create_set_request(ngx_http_mxcache_conn_t *conn);
00115 static ngx_int_t
00116 ngx_http_mxcache_flush_buffer(ngx_http_mxcache_conn_t *conn, ssize_t bytes);
00117 static void
00118 ngx_http_mxcache_write_handler(ngx_event_t *wev);
00119 static void
00120 ngx_http_mxcache_dummy_handler(ngx_event_t *ev);
00121 static void
00122 ngx_http_mxcache_read_get_handler(ngx_event_t *rev);
00123 static void
00124 ngx_http_mxcache_read_set_handler(ngx_event_t *rev);
00125 static ngx_int_t
00126 ngx_http_mxcache_read_handler(ngx_event_t *rev);
00127 static void
00128 ngx_http_mxcache_finalize_connection(ngx_http_mxcache_conn_t *conn, ngx_event_t *e, ngx_int_t rc);
00129 static ngx_int_t
00130 ngx_intmin(ngx_int_t a, ngx_int_t b);
00131 static ngx_int_t
00132 ngx_intlen(ngx_int_t n);
00133
00134
00135
00141 ngx_int_t
00142 ngx_http_mxcache_is_enabled(ngx_http_request_t *r)
00143 {
00144 ngx_http_mxcache_conf_t *conf;
00145 conf = ngx_http_get_module_loc_conf(r, ngx_http_mxcache_module);
00146
00147 return conf->enabled;
00148 }
00149
00155 ngx_http_mxcache_conn_t *
00156 ngx_http_mxcache_create_new(ngx_http_request_t *r)
00157 {
00158 ngx_http_mxcache_conn_t *conn;
00159 ngx_http_mxcache_conf_t *conf;
00160 ngx_log_t *log;
00161 ngx_pool_t *pool;
00162
00163 conf = ngx_http_get_module_loc_conf(r, ngx_http_mxcache_module);
00164
00165 pool = ngx_create_pool(NGX_HTTP_MXCACHE_BUFFER_SIZE, r->connection->log);
00166 if( pool == NULL ) {
00167 return NULL;
00168 }
00169
00170 log = ngx_palloc(pool, sizeof(ngx_log_t));
00171 if(log == NULL) {
00172 ngx_destroy_pool(pool);
00173 return NULL;
00174 }
00175 ngx_memcpy(log, r->connection->log, sizeof(ngx_log_t));
00176
00177 pool->log = log;
00178
00179 conn = ngx_pcalloc(pool, sizeof(ngx_http_mxcache_conn_t));
00180 if( conn == NULL ) {
00181 ngx_destroy_pool(pool);
00182 return NULL;
00183 }
00184
00185 conn->pool = pool;
00186 conn->rpool = pool;
00187 conn->log = log;
00188 conn->r = r;
00189 conn->read_timeout = conf->server_timeout;
00190 conn->write_timeout = conf->server_timeout;
00191 conn->exp_time = (conf->expire)/1000;
00192
00193 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00194 "[mxcache_create_new] def timeout: %d, def expire: %d",
00195 conf->server_timeout, conf->expire);
00196
00197 return conn;
00198 }
00199
00225 ngx_int_t
00226 ngx_http_mxcache_get(ngx_http_mxcache_conn_t *conn)
00227 {
00228 ngx_int_t rc;
00229
00230 ngx_http_mxcache_conf_t *conf;
00231 conf = ngx_http_get_module_loc_conf(conn->r, ngx_http_mxcache_module);
00232
00233 if(!conf->enabled)
00234 {
00235 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00236 "[mxcache_get] mxcache disabled");
00237 return NGX_DONE;
00238 }
00239
00240 rc = ngx_http_mxcache_init_conn(conn);
00241 if( rc != NGX_OK ) {
00242 ngx_log_error(NGX_LOG_ERR, conn->log, 0,
00243 "[mxcache_get] ngx_http_mxcache_init_conn fail");
00244 return rc;
00245 }
00246
00247 rc = ngx_http_mxcache_create_get_request(conn);
00248 if( rc != NGX_OK ) {
00249 ngx_log_error(NGX_LOG_ERR, conn->log, 0,
00250 "[mxcache_get] create get request failed");
00251 return rc;
00252 }
00253
00254 conn->out_bufs = NULL;
00255 conn->out_bufs_tail = NULL;
00256
00257 conn->connection->connection->read->handler = ngx_http_mxcache_read_get_handler;
00258 conn->connection->connection->write->handler = ngx_http_mxcache_write_handler;
00259
00260 ngx_add_timer(conn->connection->connection->read, conn->read_timeout);
00261 ngx_add_timer(conn->connection->connection->write, conn->write_timeout);
00262
00263
00264
00265 return NGX_OK;
00266 }
00267
00302 ngx_int_t
00303 ngx_http_mxcache_set(ngx_http_mxcache_conn_t *conn)
00304 {
00305 ngx_int_t rc;
00306
00307 ngx_http_mxcache_conf_t *conf;
00308 conf = ngx_http_get_module_loc_conf(conn->r, ngx_http_mxcache_module);
00309
00310 if(!conf->enabled)
00311 {
00312 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00313 "[mxcache_set] mxcache disabled");
00314 return NGX_DONE;
00315 }
00316
00317 rc = ngx_http_mxcache_init_conn(conn);
00318 if( rc != NGX_OK ) {
00319 ngx_log_error(NGX_LOG_ERR, conn->log, 0,
00320 "[mxcache_set] ngx_http_mxcache_init_conn fail");
00321 return rc;
00322 }
00323
00324 rc = ngx_http_mxcache_create_set_request(conn);
00325 if( rc != NGX_OK ) {
00326 ngx_log_error(NGX_LOG_ERR, conn->log, 0,
00327 "[mxcache_set] create set request failed");
00328 return rc;
00329 }
00330
00331 conn->connection->connection->read->handler = ngx_http_mxcache_read_set_handler;
00332 conn->connection->connection->write->handler = ngx_http_mxcache_write_handler;
00333
00334 conn->out_bufs = NULL;
00335 conn->out_bufs_tail = NULL;
00336
00337 ngx_add_timer(conn->connection->connection->read, conn->read_timeout);
00338 ngx_add_timer(conn->connection->connection->write, conn->write_timeout);
00339
00340
00341
00342 return NGX_OK;
00343 }
00344
00351 ngx_int_t
00352 ngx_http_mxcache_cleanup(ngx_http_mxcache_conn_t *conn)
00353 {
00354 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00355 "[mxcache_cleanup]");
00356
00357 if( conn->done || conn->connection==NULL )
00358 {
00359 if(conn->pool != NULL) {
00360 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00361 "[mxcache_cleanup] destroying pool");
00362 ngx_destroy_pool(conn->pool);
00363 }
00364 }
00365 else
00366 {
00367 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00368 "[mxcache_cleanup] terminating download");
00369 conn->terminated = 1;
00370 conn->done_handler = NULL;
00371 }
00372
00373 return NGX_OK;
00374 }
00375
00384 static ngx_int_t
00385 ngx_http_mxcache_init_conn(ngx_http_mxcache_conn_t *conn)
00386 {
00387 ngx_int_t rc;
00388 ngx_http_request_t *r;
00389 ngx_http_mxcache_conf_t *conf;
00390 ngx_pooled_connection_t *new_connection;
00391 ngx_md5_t md5;
00392 u_char *hash;
00393 u_char prehash[16];
00394 ngx_int_t i;
00395
00396
00397 r = conn->r;
00398 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00399 "[mxcache_init_conn]");
00400
00401 conf = ngx_http_get_module_loc_conf(r, ngx_http_mxcache_module);
00402
00403 conn->done = 0;
00404 conn->terminated = 0;
00405 conn->error = 0;
00406 conn->response_length = 0;
00407 conn->state = 0;
00408
00409
00410 if(ngx_strlen(conn->key) > 100 ) {
00411 hash = ngx_palloc(conn->pool, 33);
00412 if( hash == NULL ) {
00413 return NGX_ERROR;
00414 }
00415
00416 ngx_md5_init(&md5);
00417 ngx_md5_update(&md5, conn->key, ngx_strlen(conn->key) );
00418 ngx_md5_final(prehash, &md5);
00419 for(i=0; i<16; ++i) {
00420 hash[2*i] = (prehash[i] & 0x0F);
00421 hash[2*i] = hash[2*i] + (hash[2*i] < 10 ? '0' : 'a'-10);
00422 hash[2*i+1] = ((prehash[i] & 0xF0) >> 4);
00423 hash[2*i+1] = hash[2*i+1] + (hash[2*i+1] < 10 ? '0' : 'a'-10);
00424 }
00425 hash[32] = '\0';
00426
00427 conn->key = hash;
00428 }
00429
00430
00431
00432 conn->buffer = ngx_create_temp_buf(conn->rpool, NGX_HTTP_MXCACHE_BUFFER_SIZE);
00433 if( conn->buffer == NULL ) {
00434 return NGX_ERROR;
00435 }
00436
00437
00438 rc = ngx_connection_pool_get(conf->connection_pool, &new_connection, 0);
00439 if(rc != NGX_OK) {
00440
00441 ngx_log_error(NGX_LOG_ERR, conn->log, 0,
00442 "[mxcache_init_conn] ngx_connection_pool_get fail");
00443 return NGX_ERROR;
00444 }
00445
00446 conn->connection = new_connection;
00447
00448 ((ngx_pooled_connection_t*)new_connection->connection->data)->data = conn;
00449
00450 ngx_add_timer(new_connection->connection->read, conn->read_timeout);
00451 ngx_add_timer(new_connection->connection->write, conn->write_timeout);
00452
00453 return rc;
00454 }
00455
00462 static ngx_int_t
00463 ngx_http_mxcache_create_get_request(ngx_http_mxcache_conn_t *conn)
00464 {
00465 ngx_buf_t *req;
00466 size_t size;
00467 u_char *line1;
00468
00469 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00470 "[mxcache_create_get_request]");
00471
00472 size = ngx_strlen("get") + 1 \
00473 + ngx_strlen(conn->key) + 2;
00474
00475 req = ngx_create_temp_buf(conn->pool, size + 1);
00476 if( req == NULL ) {
00477 return NGX_ERROR;
00478 }
00479
00480 req->last = req->pos + size;
00481 ngx_sprintf((u_char*)req->pos, "get %s\r\n", conn->key);
00482 line1 = req->pos;
00483 line1[size] = '\0';
00484
00485 conn->request = ngx_alloc_chain_link(conn->pool);
00486 if( conn->request == NULL ) {
00487 return NGX_ERROR;
00488 }
00489 conn->request->buf = req;
00490 conn->request->next = NULL;
00491
00492 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00493 "[mxcache_create_get_request] done (%d): \n%s", size, line1);
00494
00495 return NGX_OK;
00496 }
00497
00504 static ngx_int_t
00505 ngx_http_mxcache_create_set_request(ngx_http_mxcache_conn_t *conn)
00506 {
00507 ngx_buf_t *req;
00508 size_t size;
00509 u_char *line1;
00510
00511 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00512 "[mxcache_create_request]");
00513
00514 size = ngx_strlen("set") + 1 \
00515 + ngx_strlen(conn->key) + 1 \
00516 + ngx_intlen(conn->flag) + 1 \
00517 + ngx_intlen(conn->exp_time) + 1 \
00518 + ngx_intlen(conn->bytes) + 2;
00519
00520 req = ngx_create_temp_buf(conn->pool, size + 1);
00521 if( req == NULL ) {
00522 return NGX_ERROR;
00523 }
00524
00525 req->last = req->pos + size;
00526 ngx_sprintf((u_char*)req->pos, "set %s %d %d %d\r\n", conn->key, conn->flag, conn->exp_time, conn->bytes);
00527 line1 = req->pos;
00528 line1[size] = '\0';
00529
00530 conn->request = ngx_alloc_chain_link(conn->pool);
00531 if( conn->request == NULL ) {
00532 return NGX_ERROR;
00533 }
00534 conn->request->buf = req;
00535 conn->request->next = conn->out_bufs;
00536
00537 conn->out_bufs_tail->next = ngx_alloc_chain_link(conn->pool);
00538 if( conn->out_bufs_tail->next == NULL ) {
00539 return NGX_ERROR;
00540 }
00541 conn->out_bufs_tail = conn->out_bufs_tail->next;
00542
00543 req = conn->out_bufs_tail->buf = ngx_create_temp_buf(conn->pool, 3);
00544 if( conn->out_bufs_tail->buf == NULL ) {
00545 return NGX_ERROR;
00546 }
00547 conn->out_bufs_tail->next = NULL;
00548 req->last = req->pos + 2;
00549 ngx_sprintf((u_char*)req->pos, "\r\n");
00550
00551 conn->out_bufs = NULL;
00552 conn->out_bufs_tail = NULL;
00553
00554 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00555 "[mxcache_create_request] done (%d): \n%s", size, line1);
00556
00557 return NGX_OK;
00558 }
00559
00567 static ngx_int_t
00568 ngx_http_mxcache_flush_buffer(ngx_http_mxcache_conn_t *conn, ssize_t bytes)
00569 {
00570 ngx_chain_t *cl;
00571 ngx_http_request_t *r;
00572
00573
00574 cl = NULL;
00575 r = conn->r;
00576 if( conn->out_bufs == NULL ) {
00577 cl = conn->out_bufs = conn->out_bufs_tail = ngx_alloc_chain_link(conn->rpool);
00578 if( cl == NULL ) {
00579 return NGX_ERROR;
00580 }
00581 }
00582
00583 if (cl == NULL) {
00584 cl = conn->out_bufs_tail->next = ngx_alloc_chain_link(conn->rpool);
00585 if( cl == NULL ) {
00586 return NGX_ERROR;
00587 }
00588 conn->out_bufs_tail = cl;
00589 }
00590
00591 cl->next = NULL;
00592 cl->buf = conn->buffer;
00593 conn->buffer = NULL;
00594
00595 cl->buf->flush = 1;
00596 cl->buf->memory = 1;
00597
00598 return NGX_OK;
00599 }
00600
00606 static void
00607 ngx_http_mxcache_write_handler(ngx_event_t *wev)
00608 {
00609 ngx_connection_t *c;
00610 ssize_t n, size;
00611 ngx_http_request_t *r;
00612 ngx_http_mxcache_conn_t *conn;
00613 ngx_buf_t *b;
00614
00615 c = wev->data;
00616 conn = ((ngx_pooled_connection_t*)c->data)->data;
00617 r = conn->r;
00618
00619 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00620 "[mxcache_write_handler]");
00621
00622 do {
00623 if( conn->terminated ) {
00624 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00625 "[mxcache_write_handler] terminated");
00626
00627 ngx_http_mxcache_finalize_connection(conn, wev, NGX_ERROR);
00628 return ;
00629 }
00630
00631 if( wev->timedout ) {
00632 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00633 "[mxcache_write_handler] timeout");
00634
00635 ngx_http_mxcache_finalize_connection(conn, wev, NGX_ETIMEDOUT);
00636 return ;
00637 }
00638
00639 if( conn->request == NULL || conn->request->buf == NULL ) {
00640 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00641 "[mxcache_write_handler] conn->request is null!");
00642
00643 ngx_http_mxcache_finalize_connection(conn, wev, NGX_ERROR);
00644 return ;
00645 }
00646
00647 b = conn->request->buf;
00648 size = b->last - b->pos;
00649
00650 if( size == 0 ) {
00651 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00652 "[mxcache_write_handler] empty buffer");
00653
00654 ngx_http_mxcache_finalize_connection(conn, wev, NGX_ERROR);
00655 return ;
00656 }
00657
00658 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00659 "[mxcache_write_handler] sending: %d", size);
00660
00661
00662 n = ngx_send(c, (u_char*)b->pos, size );
00663
00664 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00665 "[mxcache_write_handler] sent: %d", n);
00666
00667 if (n == NGX_ERROR) {
00668 ngx_http_mxcache_finalize_connection(conn, wev, NGX_ERROR);
00669 return;
00670 }
00671
00672 if (n > 0) {
00673 b->pos += n;
00674 if( n == size ) {
00675 conn->request = conn->request->next;
00676 if( conn->request == NULL ) {
00677 c->write->handler = ngx_http_mxcache_dummy_handler;
00678
00679 if (wev->timer_set) {
00680 ngx_del_timer(wev);
00681 }
00682
00683 if( ngx_handle_write_event(wev, 0) == NGX_ERROR ) {
00684 ngx_http_mxcache_finalize_connection(conn, wev, NGX_ERROR);
00685 }
00686
00687 return ;
00688 }
00689 }
00690 }
00691 } while( n > 0 );
00692
00693 if( !wev->timer_set ) {
00694 ngx_add_timer(wev, conn->write_timeout);
00695 }
00696 }
00697
00703 static void
00704 ngx_http_mxcache_dummy_handler(ngx_event_t *ev)
00705 {
00706 ngx_connection_t *c;
00707 ngx_http_mxcache_conn_t *conn;
00708
00709 c = ev->data;
00710 conn = ((ngx_pooled_connection_t*)c->data)->data;
00711
00712 if( conn->log ) {
00713 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
00714 "[mxcache_dummy_handler]");
00715 }
00716 }
00717
00724 static void
00725 ngx_http_mxcache_read_get_handler(ngx_event_t *rev)
00726 {
00727 ngx_int_t rc;
00728 ngx_connection_t *c;
00729 ngx_http_mxcache_conn_t *conn;
00730 ngx_chain_t *cl;
00731 u_char *s, *s2, *line_end, *line_beg;
00732 ngx_int_t len;
00733
00734 c = rev->data;
00735 conn = ((ngx_pooled_connection_t*)c->data)->data;
00736
00737
00738
00739 do {
00740 rc = ngx_http_mxcache_read_handler(rev);
00741 if( rc != NGX_OK && rc != NGX_AGAIN ) {
00742 return ;
00743 }
00744
00745 switch( conn->state ) {
00746 case 0:
00747
00748 if( conn->out_bufs ) {
00749 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00750 "[mxcache_read_get_handler] header too long");
00751 ngx_http_mxcache_finalize_connection(conn, rev, NGX_ERROR);
00752 return ;
00753 }
00754
00755 s = conn->buffer->pos + 1;
00756 while( s < conn->buffer->last ) {
00757 if( *(s-1) == '\r' && *s == '\n' ) {
00758 break;
00759 }
00760 s++;
00761 }
00762 if( s == conn->buffer->last ) {
00763 continue;
00764 }
00765 *(s-1) = '\0';
00766
00767
00768 line_beg = conn->buffer->pos;
00769 line_end = s+1;
00770 conn->header_len = line_end-line_beg;
00771 conn->data_begin = NULL;
00772
00773
00774 if( conn->header_len == 5 && \
00775 line_beg[0] == 'E' && \
00776 line_beg[1] == 'N' && \
00777 line_beg[2] == 'D' ) {
00778
00779 ngx_http_mxcache_finalize_connection(conn, rev, NGX_OK);
00780 return ;
00781 }
00782
00783 len = ngx_strlen(conn->key);
00784
00785
00786 if( conn->header_len > 6 + len && \
00787 line_beg[0] == 'V' && \
00788 line_beg[1] == 'A' && \
00789 line_beg[2] == 'L' && \
00790 line_beg[3] == 'U' && \
00791 line_beg[4] == 'E' && \
00792 line_beg[5] == ' ') {
00793
00794 conn->data_begin = s+1;
00795 }
00796 else {
00797 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00798 "[mxcache_read_get_handler] unknown response");
00799 ngx_http_mxcache_finalize_connection(conn, rev, NGX_ERROR);
00800 return ;
00801 }
00802
00803 s = line_beg+6;
00804 if( s[len] != ' ' ) {
00805 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00806 "[mxcache_read_get_handler] key parse fail");
00807 ngx_http_mxcache_finalize_connection(conn, rev, NGX_ERROR);
00808 return ;
00809 }
00810 s[len] = '\0';
00811 if( strcmp((char*)conn->key, (char*)s) != 0 ) {
00812 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00813 "[mxcache_read_get_handler] key doesn't match");
00814 ngx_http_mxcache_finalize_connection(conn, rev, NGX_ERROR);
00815 return ;
00816 }
00817
00818 s = &s[len+1];
00819 if( sscanf((char*)s, "%d %d", (int *) &conn->flag,(int *) &conn->bytes) != 2 ) {
00820 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00821 "[mxcache_read_get_handler] can't read flag and data len");
00822 ngx_http_mxcache_finalize_connection(conn, rev, NGX_ERROR);
00823 return ;
00824 }
00825
00826 conn->state = 1;
00827 case 1:
00828 len = conn->response_length - conn->header_len - (conn->bytes + 2);
00829 if( len <= 0 ) {
00830 continue;
00831 }
00832 else {
00833 conn->state = 2;
00834 }
00835 case 2:
00836 len = conn->response_length - conn->header_len - (conn->bytes + 2);
00837 if( len < 5 ) {
00838 continue;
00839 }
00840 else if( len > 5 ) {
00841 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00842 "[mxcache_read_get_handler] footer too long");
00843 ngx_http_mxcache_finalize_connection(conn, rev, NGX_ERROR);
00844 return ;
00845 }
00846
00847
00848 cl = conn->out_bufs_tail;
00849 if( ngx_http_mxcache_flush_buffer(conn, conn->buffer->last - conn->buffer->pos) == NGX_ERROR ) {
00850 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00851 "[mxcache_read_get_handler] ngx_http_mxcache_flush_buffer fail");
00852 ngx_http_mxcache_finalize_connection(conn, rev, NGX_ERROR);
00853 return ;
00854 }
00855
00856 len = ngx_buf_size(conn->out_bufs_tail->buf);
00857 len = 5-len;
00858
00859
00860 if( len > 0 ) {
00861 s = cl->buf->last - len;
00862 s2 = cl->next->buf->pos;
00863 if( ngx_strncmp(s, "END\r\n", len) != 0 || ngx_strncmp(s2, &"END\r\n"[len], 5-len) != 0 ) {
00864 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00865 "[mxcache_read_get_handler] unknown footer");
00866 ngx_http_mxcache_finalize_connection(conn, rev, NGX_ERROR);
00867 return ;
00868 }
00869
00870 conn->out_bufs->buf->pos = conn->data_begin;
00871 cl->buf->last = cl->buf->last - len;
00872 conn->out_bufs_tail = cl;
00873 conn->out_bufs_tail->next = NULL;
00874 }
00875 else {
00876 s = conn->out_bufs_tail->buf->last - 5;
00877 if( ngx_strncmp(s, "END\r\n", 5) != 0 ) {
00878 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00879 "[mxcache_read_get_handler] unknown footer");
00880 ngx_http_mxcache_finalize_connection(conn, rev, NGX_ERROR);
00881 return ;
00882 }
00883
00884 conn->out_bufs->buf->pos = conn->data_begin;
00885
00886 conn->out_bufs_tail->buf->last = conn->out_bufs_tail->buf->last - 5;
00887 if ( conn->out_bufs_tail->buf->pos == conn->out_bufs_tail->buf->last ) {
00888 conn->out_bufs_tail = cl;
00889 }
00890 conn->out_bufs_tail->next = NULL;
00891 }
00892
00893
00894 ngx_http_mxcache_finalize_connection(conn, rev, NGX_OK);
00895 return ;
00896
00897 break;
00898 default:
00899 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00900 "[mxcache_read_get_handler] unknown parser states");
00901
00902 ngx_http_mxcache_finalize_connection(conn, rev, NGX_ERROR);
00903 return ;
00904 }
00905
00906 } while( rc == NGX_AGAIN );
00907
00908 return ;
00909 }
00910
00917 static void
00918 ngx_http_mxcache_read_set_handler(ngx_event_t *rev)
00919 {
00920 ngx_int_t rc;
00921 ngx_connection_t *c;
00922 ngx_http_mxcache_conn_t *conn;
00923 u_char *s;
00924 ngx_int_t len;
00925
00926 c = rev->data;
00927 conn = ((ngx_pooled_connection_t*)c->data)->data;
00928
00929 do {
00930 rc = ngx_http_mxcache_read_handler(rev);
00931 if( rc != NGX_OK && rc != NGX_AGAIN ) {
00932 return ;
00933 }
00934
00935 if( conn->out_bufs ) {
00936 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00937 "[mxcache_read_set_handler] response too long");
00938 ngx_http_mxcache_finalize_connection(conn, rev, NGX_ERROR);
00939 return ;
00940 }
00941
00942 s = conn->buffer->pos;
00943
00944 len = ngx_intmin(conn->response_length, ngx_strlen("STORED\r\n"));
00945 if( ngx_strncmp(s, "STORED\r\n", len) != 0 || conn->response_length > ngx_strlen("STORED\r\n") ) {
00946 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00947 "[mxcache_read_set_handler] unknown response");
00948 ngx_http_mxcache_finalize_connection(conn, rev, NGX_ERROR);
00949 return ;
00950 }
00951
00952 if( conn->response_length == ngx_strlen("STORED\r\n") ) {
00953
00954 ngx_http_mxcache_finalize_connection(conn, rev, NGX_OK);
00955 return ;
00956 }
00957
00958
00959 } while( rc == NGX_AGAIN );
00960
00961 }
00962
00968 static ngx_int_t
00969 ngx_http_mxcache_read_handler(ngx_event_t *rev)
00970 {
00971 size_t size;
00972 ngx_int_t n;
00973 ngx_buf_t *b;
00974 ngx_connection_t *c;
00975 ngx_http_request_t *r;
00976 ngx_http_mxcache_conn_t *conn;
00977
00978 c = rev->data;
00979 conn = ((ngx_pooled_connection_t*)c->data)->data;
00980 r = conn->r;
00981
00982 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00983 "[mxcache_read_handler]");
00984
00985 if( conn->terminated ) {
00986 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
00987 "[mxcache_read_handler] terminated");
00988 ngx_http_mxcache_finalize_connection(conn, rev, NGX_ERROR);
00989 return NGX_DONE;
00990 }
00991
00992 if (rev->timedout) {
00993 ngx_connection_error(c, NGX_ETIMEDOUT, "mxcache connection timed out");
00994 ngx_http_mxcache_finalize_connection(conn, rev, NGX_ETIMEDOUT);
00995 return NGX_ETIMEDOUT;
00996 }
00997
00998 b = conn->buffer;
00999 size = b->end - b->last;
01000 if( size == 0 ) {
01001 if( ngx_http_mxcache_flush_buffer(conn, b->end - b->start) == NGX_ERROR ) {
01002 ngx_http_mxcache_finalize_connection(conn, rev, NGX_ERROR);
01003 return NGX_ERROR;
01004 }
01005 b = conn->buffer = ngx_create_temp_buf(conn->rpool, NGX_HTTP_MXCACHE_BUFFER_SIZE);
01006 if(b == NULL)
01007 {
01008 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
01009 "[mxcache_read_handler] create temp buf failed");
01010
01011 ngx_http_mxcache_finalize_connection(conn, rev, NGX_ERROR);
01012 return NGX_ERROR;
01013 }
01014 size = b->end - b->last;
01015 }
01016
01017
01018 n = c->recv(c, b->last, size);
01019
01020 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, conn->log, 0,
01021 "[mxcache_read_handler] recv %d", n);
01022
01023 if (n == 0 || n == NGX_ERROR) {
01024 ngx_http_mxcache_finalize_connection(conn, rev, NGX_ERROR);
01025
01026 return NGX_ERROR;
01027 }
01028
01029 if( n>0 ) {
01030 conn->response_length += n;
01031 b->last += n;
01032
01033 if( rev->ready ) {
01034 return NGX_AGAIN;
01035 }
01036 }
01037
01038
01039
01040 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
01041 ngx_http_mxcache_finalize_connection(conn, rev, NGX_ERROR);
01042 return NGX_ERROR;
01043 }
01044
01045 if (rev->active) {
01046 ngx_add_timer(rev, conn->read_timeout);
01047 } else if (rev->timer_set) {
01048 ngx_del_timer(rev);
01049 }
01050
01051 return NGX_OK;
01052 }
01053
01061 static void
01062 ngx_http_mxcache_finalize_connection(ngx_http_mxcache_conn_t *conn, ngx_event_t *e, ngx_int_t rc)
01063 {
01064 ngx_http_request_t *r;
01065
01066 r = conn->r;
01067
01068 if ( !conn->done ) {
01069
01070 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, conn->log, 0,
01071 "[mxcache_finalize_connection] rc: %d", rc);
01072
01073 if( conn->out_bufs_tail && conn->out_bufs_tail->buf ) {
01074 conn->out_bufs_tail->buf->last_buf = 1;
01075 conn->out_bufs_tail->buf->last_in_chain = 1;
01076 }
01077
01078 if( rc == NGX_OK ) {
01079 ngx_connection_pool_return(conn->connection);
01080 }
01081 else {
01082 ngx_connection_pool_release(conn->connection);
01083 }
01084
01085 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, conn->log, 0,
01086 "[mxcache_finalize_connection] close mxcache request");
01087
01088 conn->done = 1;
01089 conn->error = rc;
01090
01091
01092 if( conn->done_handler != NULL ) {
01093 conn->done_handler(conn);
01094 }
01095 else {
01096 ngx_http_mxcache_cleanup(conn);
01097 }
01098 }
01099 }
01100
01101
01102
01108 static void *
01109 ngx_http_mxcache_create_conf(ngx_conf_t *cf)
01110 {
01111 ngx_http_mxcache_conf_t *conf;
01112
01113 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0,
01114 "ngx_http_mxcache_create_conf");
01115
01116 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_mxcache_conf_t));
01117 if (conf == NULL) {
01118 return NGX_CONF_ERROR;
01119 }
01120
01121 conf->enabled = NGX_CONF_UNSET;
01122
01123 conf->server_timeout = NGX_CONF_UNSET_MSEC;
01124 conf->server_ip.data = NULL;
01125 conf->server_port = NGX_CONF_UNSET_UINT;
01126 conf->expire = NGX_CONF_UNSET_MSEC;
01127
01128 conf->sockaddr = NGX_CONF_UNSET_PTR;
01129 conf->pool = ngx_create_pool(NGX_HTTP_MXCACHE_BUFFER_SIZE, cf->log);
01130
01131 conf->log = ngx_palloc(cf->pool, sizeof(ngx_log_t));
01132 ngx_memcpy(conf->log, cf->log, sizeof(ngx_log_t));
01133
01134 conf->connection_pool = NGX_CONF_UNSET_PTR;
01135
01136 return conf;
01137 }
01138
01147 static char *
01148 ngx_http_mxcache_merge_conf(ngx_conf_t *cf, void *parent, void *child)
01149 {
01150 ngx_http_mxcache_conf_t *prev = parent;
01151 ngx_http_mxcache_conf_t *conf = child;
01152 struct sockaddr_in *sin;
01153 struct hostent *hp;
01154
01155 ngx_conf_merge_msec_value(conf->server_timeout, prev->server_timeout, 1000);
01156 ngx_conf_merge_str_value(conf->server_ip, prev->server_ip, "127.0.0.1");
01157 ngx_conf_merge_uint_value(conf->server_port, prev->server_port, 11211);
01158 ngx_conf_merge_msec_value(conf->expire, prev->expire, 300*1000);
01159 ngx_conf_merge_value(conf->enabled, prev->enabled, 0);
01160
01161 if (conf->server_port > 65535) {
01162 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
01163 "server_port value is invalid: should be between 0 and 65535");
01164 return NGX_CONF_ERROR;
01165 }
01166 if (conf->server_timeout <= 0) {
01167 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
01168 "check_server_timeout must be greater then zero");
01169 return NGX_CONF_ERROR;
01170 }
01171 if (conf->expire <= 0) {
01172 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
01173 "expire must be greater then zero");
01174 return NGX_CONF_ERROR;
01175 }
01176
01177
01178
01179
01180
01181 if(conf->sockaddr == NGX_CONF_UNSET_PTR) {
01182 conf->sockaddr = ngx_pcalloc(conf->pool, sizeof(struct sockaddr_in));
01183 sin = (struct sockaddr_in *)conf->sockaddr;
01184
01185 u_char * ip = ngx_pcalloc(cf->pool, conf->server_ip.len+1);
01186 ngx_cpystrn(ip, conf->server_ip.data, conf->server_ip.len+1);
01187 hp = gethostbyname((const char*)ip);
01188 if( hp == NULL || hp->h_addr_list[0] == NULL ) {
01189 return NGX_CONF_ERROR;
01190 }
01191 bcopy(hp->h_addr, &(sin->sin_addr.s_addr), hp->h_length);
01192
01193 sin->sin_family = AF_INET;
01194 sin->sin_port = htons(conf->server_port);
01195 }
01196
01197 if (conf->connection_pool == NGX_CONF_UNSET_PTR) {
01198 conf->connection_pool = ngx_connection_pool_create(cf->log, conf->sockaddr, sizeof(struct sockaddr_in), 100);
01199 }
01200
01201 return NGX_CONF_OK;
01202 }
01203
01210 static ngx_int_t
01211 ngx_intlen(ngx_int_t n)
01212 {
01213 ngx_int_t len;
01214
01215 len = 0;
01216 do {
01217 n/=10;
01218 len++;
01219 } while( n );
01220
01221 return len;
01222 }
01223
01231 static ngx_int_t
01232 ngx_intmin(ngx_int_t a, ngx_int_t b)
01233 {
01234 return (a<b) ? a : b;
01235 }