00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "ngx_http_xxslt_selector.h"
00023
00024 static ngx_int_t
00025 ngx_http_xxslt_selector_unknown_match(ngx_http_xxslt_selector_data_t *ctx,
00026 ngx_chain_t *ch_beg, ngx_chain_t *ch_end,
00027 u_char *beg, u_char *end, ngx_int_t last_in_chain);
00028 static ngx_int_t
00029 ngx_http_xxslt_selector_parse_match(ngx_http_xxslt_selector_data_t *ctx,
00030 ngx_chain_t *ch_beg, ngx_chain_t *ch_end,
00031 u_char *beg, u_char *end, ngx_int_t last_in_chain);
00032 static ngx_int_t
00033 ngx_http_xxslt_selector_add_unknown(ngx_http_request_t *r, ngx_chain_t *in, ngx_http_xxslt_out_data_t *out);
00034 static ngx_int_t
00035 ngx_http_xxslt_selector_add_parse(ngx_http_request_t *r, ngx_chain_t *in, ngx_http_xxslt_out_data_t *out,
00036 ngx_http_xxslt_selector_data_t *sel_ctx);
00037 static ngx_chain_t*
00038 ngx_http_xxslt_selector_prepare_in(ngx_http_request_t *r, ngx_chain_t *ch_beg, ngx_chain_t *ch_end,
00039 u_char *buf_beg, u_char *buf_end, ngx_int_t last_in_chain);
00040 static void
00041 ngx_http_xxslt_selector_set_pos(ngx_http_request_t *r, ngx_chain_t *in);
00042
00043
00044
00052 ngx_http_xxslt_selector_data_t *
00053 ngx_http_xxslt_selector_init(ngx_http_request_t *r)
00054 {
00055 ngx_http_xxslt_selector_data_t *ctx;
00056
00057
00058 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
00059 "[selector_init]");
00060
00061
00062 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_xxslt_selector_data_t));
00063 if( ctx == NULL ) {
00064 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
00065 "[selector_init] alloc fail.");
00066 return NULL;
00067 }
00068
00069 ctx->id_data = 1;
00070 ctx->act_out_data_unknown = NULL;
00071 ctx->act_out_data_parse = NULL;
00072 ctx->r = r;
00073
00074
00075 ctx->match_data = ngx_pcalloc(r->pool, sizeof(ngx_http_xxslt_selector_match_t));
00076 if( ctx->match_data == NULL ) {
00077 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
00078 "[selector_init] alloc fail");
00079 return NULL;
00080 }
00081
00082 ctx->match_data->state = NGX_HTTP_XXSLT_MATCH_OPEN;
00083 ctx->select_mode = NGX_HTTP_XXSLT_SELECTOR_UNKNOWN;
00084 ctx->match_data->open = (u_char*)"<xxslt>";
00085 ctx->match_data->o_len = strlen((char*)ctx->match_data->open);
00086 ctx->match_data->close = (u_char*)"</xxslt>";
00087 ctx->match_data->c_len = strlen((char*)ctx->match_data->close);
00088
00089 ctx->backup_in = NULL;
00090
00091 ctx->includes = xmlNewDoc((xmlChar *)"1.0");
00092 ctx->includes->children = xmlNewDocNode(ctx->includes, NULL, (xmlChar *)"inc", NULL);
00093
00094 return ctx;
00095 }
00096
00106 ngx_int_t
00107 ngx_http_xxslt_selector_add_data_chunk(ngx_http_xxslt_selector_data_t *ctx, ngx_chain_t *in)
00108 {
00109 ngx_http_xxslt_selector_match_t *match;
00110 ngx_http_request_t *r;
00111 ngx_int_t rc;
00112 ngx_chain_t *ch, *cl_end;
00113 ngx_buf_t *b;
00114 u_char *c;
00115
00116 u_char *buf_last;
00117 ngx_chain_t *ch_last;
00118
00119 ngx_int_t is_last_buf;
00120
00121
00122 r = ctx->r;
00123 match = ctx->match_data;
00124
00125 if( in == NULL ) {
00126 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
00127 "[selector_add_data_chunk] in is null.");
00128 return NGX_ERROR;
00129 }
00130
00131
00132 if( ctx->backup_in ) {
00133 ctx->backup_in->next = in;
00134 in = ctx->backup_in;
00135 ctx->backup_in = NULL;
00136 }
00137
00138 ch = ch_last = in;
00139 if( ch->buf && ch->buf->last - ch->buf->pos > 0 ) {
00140 buf_last = ch->buf->pos;
00141 }
00142 else {
00143 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
00144 "[selector_add_data_chunk] null or empty buf");
00145 return NGX_ERROR;
00146 }
00147
00148 is_last_buf = 0;
00149 while( ch ) {
00150 cl_end = ch;
00151 b = ch->buf;
00152 if( b == NULL || b->last - b->pos == 0 ) {
00153 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
00154 "[selector_add_data_chunk] null or empty buf");
00155 return NGX_ERROR;
00156 }
00157
00158 is_last_buf = is_last_buf || b->last_buf;
00159
00160
00161 for(c=b->pos; c<b->last; c++) {
00162 if( match->state == NGX_HTTP_XXSLT_MATCH_OPEN && ctx->select_mode == NGX_HTTP_XXSLT_SELECTOR_UNKNOWN ) {
00163 if( match->open[match->o_pos] == *c ) {
00164 match->o_pos++;
00165 }
00166 else {
00167 if( match->open[0] == *c ) {
00168 match->o_pos = 1;
00169 }
00170 else {
00171 match->o_pos = 0;
00172 }
00173 }
00174 if( match->o_pos == 0 ) {
00175 match->cl_before = ch;
00176 match->buf_before = c;
00177 }
00178
00179 if( match->o_pos == match->o_len ) {
00180 match->o_pos = 0;
00181 match->state = NGX_HTTP_XXSLT_MATCH_CLOSE;
00182 ctx->select_mode = NGX_HTTP_XXSLT_SELECTOR_PARSE;
00183
00184 if( match->cl_before && match->buf_before ) {
00185 rc = ngx_http_xxslt_selector_unknown_match(ctx, ch_last, match->cl_before, buf_last, match->buf_before, 1);
00186 if(rc == NGX_ERROR)
00187 {
00188 return NGX_ERROR;
00189 }
00190 match->cl_before = NULL;
00191 match->buf_before = NULL;
00192 }
00193 ch_last = ch;
00194 buf_last = c+1;
00195 if( ch_last->buf->last <= buf_last ) {
00196 ch_last = ch_last->next;
00197 if( ch_last ) {
00198 buf_last = ch_last->buf->pos;
00199 }
00200 }
00201 }
00202 }
00203 else if( match->state == NGX_HTTP_XXSLT_MATCH_CLOSE && ctx->select_mode == NGX_HTTP_XXSLT_SELECTOR_PARSE ) {
00204 if( match->close[match->c_pos] == *c ) {
00205 match->c_pos++;
00206 }
00207 else {
00208 if( match->close[0] == *c ) {
00209 match->c_pos = 1;
00210 }
00211 else {
00212 match->c_pos = 0;
00213 }
00214 }
00215 if( match->c_pos == 0 ) {
00216 match->cl_before = ch;
00217 match->buf_before = c;
00218 }
00219
00220 if( match->c_pos == match->c_len ) {
00221 match->c_pos = 0;
00222 match->state = NGX_HTTP_XXSLT_MATCH_OPEN;
00223 ctx->select_mode = NGX_HTTP_XXSLT_SELECTOR_UNKNOWN;
00224
00225 if( match->cl_before && match->buf_before ) {
00226 rc = ngx_http_xxslt_selector_parse_match(ctx, ch_last, match->cl_before, buf_last, match->buf_before, 1);
00227 if(rc == NGX_ERROR)
00228 {
00229 return NGX_ERROR;
00230 }
00231 match->cl_before = NULL;
00232 match->buf_before = NULL;
00233 }
00234 ch_last = ch;
00235 buf_last = c+1;
00236 if( ch_last->buf->last <= buf_last ) {
00237 ch_last = ch_last->next;
00238 if( ch_last ) {
00239 buf_last = ch_last->buf->pos;
00240 }
00241 }
00242 }
00243
00244 }
00245 else {
00246 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
00247 "[selector_add_data_chunk] bad matcher state or mode :: %d %d ", match->state, ctx->select_mode );
00248 return NGX_ERROR;
00249 }
00250 }
00251
00252 ch = ch->next;
00253 }
00254
00255
00256 if( ch_last == NULL ) {
00257 if( is_last_buf ) {
00258 if( ctx->act_out_data_parse ) {
00259 ctx->act_out_data_parse->last = 1;
00260 }
00261 if( ctx->act_out_data_unknown ) {
00262 ctx->act_out_data_unknown->last = 1;
00263 }
00264 }
00265
00266 if( is_last_buf ) {
00267 ngx_http_xxslt_process_data(r);
00268 }
00269
00270 ngx_http_xxslt_selector_set_pos(r, in);
00271 return NGX_OK;
00272 }
00273
00274 if( match->state == NGX_HTTP_XXSLT_MATCH_OPEN && ctx->select_mode == NGX_HTTP_XXSLT_SELECTOR_UNKNOWN ) {
00275
00276
00277 c = cl_end->buf->last - 1;
00278 if( match->o_pos > 0 && !is_last_buf ) {
00279 c = c - match->o_pos;
00280 ctx->backup_in = ngx_http_xxslt_selector_prepare_in(r, cl_end, cl_end, c+1, cl_end->buf->last-1, 0);
00281 if( ctx->backup_in == NULL ) {
00282 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
00283 "[selector_add_data_chunk] ngx_http_xxslt_selector_prepare_in error.");
00284 return NGX_ERROR;
00285 }
00286 }
00287 match->o_pos = 0;
00288
00289 match->cl_before = NULL;
00290 match->buf_before = NULL;
00291 rc = ngx_http_xxslt_selector_unknown_match(ctx, ch_last, cl_end, buf_last, c, is_last_buf);
00292
00293 if( ctx->act_out_data_unknown ) {
00294 ctx->act_out_data_unknown->last = is_last_buf;
00295 }
00296 }
00297 else if( match->state == NGX_HTTP_XXSLT_MATCH_CLOSE && ctx->select_mode == NGX_HTTP_XXSLT_SELECTOR_PARSE ) {
00298
00299
00300 c = cl_end->buf->last - 1;
00301 if( match->c_pos > 0 && !is_last_buf ) {
00302 c = c - match->c_pos;
00303 ctx->backup_in = ngx_http_xxslt_selector_prepare_in(r, cl_end, cl_end, c+1, cl_end->buf->last-1, 0);
00304 if( ctx->backup_in == NULL ) {
00305 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
00306 "[selector_add_data_chunk] ngx_http_xxslt_selector_prepare_in error.");
00307 return NGX_ERROR;
00308 }
00309 }
00310 match->c_pos = 0;
00311
00312 match->cl_before = NULL;
00313 match->buf_before = NULL;
00314 rc = ngx_http_xxslt_selector_parse_match(ctx, ch_last, cl_end, buf_last, c, is_last_buf);
00315
00316 if( ctx->act_out_data_parse ) {
00317 ctx->act_out_data_parse->last = is_last_buf;
00318 }
00319 }
00320 else {
00321 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
00322 "[selector_add_data_chunk] bad matcher state or mode.");
00323
00324 rc = NGX_ERROR;
00325 }
00326
00327 if( is_last_buf ) {
00328 ngx_http_xxslt_process_data(r);
00329 }
00330
00331 ngx_http_xxslt_selector_set_pos(r, in);
00332 return rc;
00333 }
00334
00342 void
00343 ngx_http_xxslt_selector_log_chain(ngx_http_request_t *r, ngx_chain_t *cl, u_char *label)
00344 {
00345 u_char *c;
00346 ngx_int_t len;
00347
00348 while( cl ) {
00349 len = cl->buf->last - cl->buf->pos;
00350 c = ngx_pcalloc(r->pool, len+1);
00351
00352 ngx_cpystrn(c, cl->buf->pos, len+1);
00353
00354 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
00355 "%s: %s", label, c);
00356
00357 cl = cl->next;
00358 }
00359 }
00360
00372 static ngx_int_t
00373 ngx_http_xxslt_selector_unknown_match(ngx_http_xxslt_selector_data_t *ctx,
00374 ngx_chain_t *ch_beg, ngx_chain_t *ch_end,
00375 u_char *beg, u_char *end, ngx_int_t last_in_chain)
00376 {
00377 ngx_chain_t *cl;
00378 ngx_http_xxslt_out_data_t *out;
00379 ngx_int_t rc;
00380 ngx_http_request_t *r;
00381
00382 r = ctx->r;
00383
00384
00385 cl = ngx_http_xxslt_selector_prepare_in(r, ch_beg, ch_end, beg, end, last_in_chain);
00386 if( cl == NULL ) {
00387 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
00388 "[selector_unknown_match] ngx_http_xxslt_selector_prepare_in error.");
00389 return NGX_ERROR;
00390 }
00391
00392
00393 ctx->act_out_data_parse = NULL;
00394 out = ctx->act_out_data_unknown;
00395 if( out == NULL ) {
00396 out = ngx_pcalloc(r->pool, sizeof(ngx_http_xxslt_out_data_t));
00397 if( out == NULL ) {
00398 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
00399 "[selector_unknown_match] ngx_http_xxslt_out_data_t allocation fail.");
00400 return NGX_ERROR;
00401 }
00402
00403 out->id = ctx->id_data++;
00404 out->r = ctx->r;
00405 out->data_type = NGX_HTTP_XXSLT_SELECTOR_UNKNOWN;
00406
00407 ngx_http_xxslt_enqueue_data(out);
00408 }
00409 ctx->act_out_data_unknown = out;
00410
00411
00412 rc = ngx_http_xxslt_selector_add_unknown(r, cl, out);
00413
00414 if( rc == NGX_ERROR ) {
00415 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
00416 "[selector_unknown_match] ngx_http_xxslt_selector_add_unknown error.");
00417 return NGX_ERROR;
00418 }
00419
00420 return NGX_OK;
00421 }
00422
00434 static ngx_int_t
00435 ngx_http_xxslt_selector_parse_match(ngx_http_xxslt_selector_data_t *ctx,
00436 ngx_chain_t *ch_beg, ngx_chain_t *ch_end,
00437 u_char *beg, u_char *end, ngx_int_t last_in_chain)
00438 {
00439 ngx_chain_t *cl;
00440 ngx_http_xxslt_out_data_t *out;
00441 ngx_int_t rc;
00442 ngx_http_request_t *r;
00443
00444 r = ctx->r;
00445
00446
00447 cl = ngx_http_xxslt_selector_prepare_in(r, ch_beg, ch_end, beg, end, last_in_chain);
00448 if( cl == NULL ) {
00449 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
00450 "[selector_parse_match] ngx_http_xxslt_selector_prepare_in error.");
00451 return NGX_ERROR;
00452 }
00453
00454
00455 ctx->act_out_data_unknown = NULL;
00456 out = ctx->act_out_data_parse;
00457 if( out == NULL ) {
00458 out = ngx_pcalloc(r->pool, sizeof(ngx_http_xxslt_out_data_t));
00459 if( out == NULL ) {
00460 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
00461 "[selector_parse_match] alloc fail.");
00462 return NGX_ERROR;
00463 }
00464
00465 out->id = ctx->id_data++;
00466 out->r = ctx->r;
00467 out->data_type = NGX_HTTP_XXSLT_SELECTOR_PARSE;
00468
00469 ngx_http_xxslt_enqueue_data(out);
00470 }
00471 ctx->act_out_data_parse = out;
00472
00473
00474 rc = ngx_http_xxslt_selector_add_parse(r, cl, out, ctx);
00475 if( rc == NGX_ERROR ) {
00476
00477 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
00478 "[selector_parse_match] ngx_http_xxslt_selector_add_parse error.");
00479 return NGX_ERROR;
00480 }
00481
00482 if( rc == NGX_DONE ) {
00483 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
00484 "selector async mode on");
00485 ctx->async = 1;
00486 }
00487
00488 return NGX_OK;
00489 }
00490
00504 static ngx_chain_t*
00505 ngx_http_xxslt_selector_prepare_in(ngx_http_request_t *r, ngx_chain_t *ch_beg, ngx_chain_t *ch_end,
00506 u_char *buf_beg, u_char *buf_end, ngx_int_t last_in_chain)
00507 {
00508 if( !ch_beg || !ch_end || !buf_beg || !buf_end ) {
00509 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
00510 "[selector_prepare_in] null pointer.");
00511 return NULL;
00512 }
00513
00514 if( ch_beg == ch_end && buf_beg > buf_end ) {
00515 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
00516 "[selector_prepare_in] no data.");
00517 return NULL;
00518 }
00519
00520 ngx_chain_t *cl, *cl_aloc, *res, *res_tail;
00521 ngx_int_t len;
00522 u_char *beg;
00523
00524 res = res_tail = NULL;
00525 cl = ch_beg;
00526 while( 1 ) {
00527 cl_aloc = ngx_pcalloc(r->pool, sizeof(ngx_chain_t));
00528 if( cl_aloc == NULL ) {
00529 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
00530 "[selector_prepare_in] chain allocation fail.");
00531 return NULL;
00532 }
00533 cl_aloc->next = NULL;
00534
00535 if( ch_beg == ch_end ) {
00536 len = buf_end - buf_beg + 1;
00537 beg = buf_beg;
00538 }
00539 else if( cl == ch_beg ) {
00540 len = cl->buf->last - buf_beg + 1;
00541 beg = buf_beg;
00542 }
00543 else if( cl == ch_end ) {
00544 len = buf_end - cl->buf->pos + 1;
00545 beg = cl->buf->pos;
00546 }
00547 else {
00548 len = cl->buf->last - cl->buf->pos + 1;
00549 beg = cl->buf->pos;
00550 }
00551
00552 cl_aloc->buf = ngx_create_temp_buf(r->pool, len);
00553 if( cl_aloc->buf == NULL ) {
00554 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
00555 "[selector_prepare_in] buffer allocation fail.");
00556 return NULL;
00557 }
00558 ngx_memcpy(cl_aloc->buf->start, beg, len);
00559 cl_aloc->buf->last = cl_aloc->buf->pos + len;
00560
00561 if( res == NULL ) {
00562 res = res_tail = cl_aloc;
00563 }
00564 else {
00565 res_tail->next = cl_aloc;
00566 res_tail = cl_aloc;
00567 }
00568
00569 if( cl == ch_end )
00570 break;
00571 cl = cl->next;
00572 }
00573
00574 res_tail->buf->last_in_chain = last_in_chain;
00575
00576 return res;
00577 }
00578
00587 static ngx_int_t
00588 ngx_http_xxslt_selector_add_unknown(ngx_http_request_t *r, ngx_chain_t *in,
00589 ngx_http_xxslt_out_data_t *out)
00590 {
00591 if( out->unknown == NULL ) {
00592 out->unknown = ngx_http_xxslt_unknown_create_new(r);
00593 out->unknown->id = out->id;
00594 out->unknown->r = r;
00595 }
00596
00597 if( out->unknown == NULL ) {
00598 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
00599 "[selector_add_unknown] ngx_http_xxslt_unknown_create_new fail.");
00600 return NGX_ERROR;
00601 }
00602
00603 return ngx_http_xxslt_unknown_add_data_chunk(out->unknown, in);
00604 }
00605
00615 static ngx_int_t
00616 ngx_http_xxslt_selector_add_parse(ngx_http_request_t *r, ngx_chain_t *in,
00617 ngx_http_xxslt_out_data_t *out, ngx_http_xxslt_selector_data_t *sel_ctx)
00618 {
00619 if( out->parse == NULL ) {
00620 out->parse = ngx_http_xxslt_parse_create_new(r);
00621 out->parse->id = out->id;
00622 out->parse->r = r;
00623
00624 out->parse->includes = sel_ctx->includes;
00625 }
00626
00627 if( out->parse == NULL ) {
00628 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
00629 "[selector_add_parse] ngx_http_xxslt_parse_create_new fail.");
00630 return NGX_ERROR;
00631 }
00632
00633
00634 return ngx_http_xxslt_parse_add_data_chunk(out->parse, in);
00635 }
00636
00641 static void
00642 ngx_http_xxslt_selector_set_pos(ngx_http_request_t *r, ngx_chain_t *in)
00643 {
00644 while(in)
00645 {
00646 in->buf->pos = in->buf->last;
00647 in = in->next;
00648 }
00649 }
00650
00656 void
00657 ngx_http_xxslt_selector_cleanup(ngx_http_xxslt_selector_data_t *sel_ctx)
00658 {
00659 if(sel_ctx->includes != NULL)
00660 {
00661 xmlFreeDoc(sel_ctx->includes);
00662 sel_ctx->includes = NULL;
00663 }
00664 }