comparison src/http/modules/perl/nginx.xs @ 633:f971949ffb58 release-0.3.38

nginx-0.3.38-RELEASE import *) Feature: the ngx_http_dav_module. *) Change: the ngx_http_perl_module optimizations. Thanks to Sergey Skvortsov. *) Feature: the ngx_http_perl_module supports the $r->request_body_file method. *) Feature: the "client_body_in_file_only" directive. *) Workaround: now on disk overflow nginx tries to write access logs once a second only. Thanks to Anton Yuzhaninov and Maxim Dounin. *) Bugfix: now the "limit_rate" directive more precisely limits rate if rate is more than 100 Kbyte/s. Thanks to ForJest. *) Bugfix: now the IMAP/POP3 proxy escapes the "\r" and "\n" symbols in login and password to pass authorization server. Thanks to Maxim Dounin.
author Igor Sysoev <igor@sysoev.ru>
date Fri, 14 Apr 2006 09:53:38 +0000
parents 5d2b8078c1c2
children 63a820b0bc6c
comparison
equal deleted inserted replaced
632:5c60f5f0887d 633:f971949ffb58
10 #include <ngx_core.h> 10 #include <ngx_core.h>
11 #include <ngx_http.h> 11 #include <ngx_http.h>
12 #include <ngx_http_perl_module.h> 12 #include <ngx_http_perl_module.h>
13 13
14 #include "XSUB.h" 14 #include "XSUB.h"
15
16 #define ngx_http_perl_set_request(r) \
17 r = INT2PTR(ngx_http_request_t *, SvIV((SV *) SvRV(ST(0))))
18
19
20 #define ngx_http_perl_set_targ(p, len, z) \
21 \
22 sv_upgrade(TARG, SVt_PV); \
23 SvPOK_on(TARG); \
24 SvPV_set(TARG, (char *) p); \
25 SvLEN_set(TARG, len + z); \
26 SvCUR_set(TARG, len); \
27 SvFAKE_on(TARG); \
28 SvREADONLY_on(TARG); \
15 29
16 30
17 static ngx_int_t 31 static ngx_int_t
18 ngx_http_perl_sv2str(pTHX_ ngx_http_request_t *r, ngx_str_t *s, SV *sv) 32 ngx_http_perl_sv2str(pTHX_ ngx_http_request_t *r, ngx_str_t *s, SV *sv)
19 { 33 {
77 91
78 92
79 MODULE = nginx PACKAGE = nginx 93 MODULE = nginx PACKAGE = nginx
80 94
81 95
82 int 96 void
83 send_http_header(r, ...) 97 send_http_header(r, ...)
84 nginx r 98 CODE:
85 99
86 PREINIT: 100 ngx_http_request_t *r;
87 101 SV *sv;
88 SV *sv; 102
89 103 ngx_http_perl_set_request(r);
90 CODE:
91 104
92 if (r->headers_out.status == 0) { 105 if (r->headers_out.status == 0) {
93 r->headers_out.status = NGX_HTTP_OK; 106 r->headers_out.status = NGX_HTTP_OK;
94 } 107 }
95 108
97 sv = ST(1); 110 sv = ST(1);
98 111
99 if (ngx_http_perl_sv2str(aTHX_ r, &r->headers_out.content_type, sv) 112 if (ngx_http_perl_sv2str(aTHX_ r, &r->headers_out.content_type, sv)
100 != NGX_OK) 113 != NGX_OK)
101 { 114 {
102 RETVAL = NGX_ERROR; 115 XSRETURN_EMPTY;
103 goto done;
104 } 116 }
105 117
106 } else { 118 } else {
107 if (r->headers_out.content_type.len == 0) { 119 if (r->headers_out.content_type.len == 0) {
108 if (ngx_http_set_content_type(r) != NGX_OK) { 120 if (ngx_http_set_content_type(r) != NGX_OK) {
109 RETVAL = NGX_ERROR; 121 XSRETURN_EMPTY;
110 goto done;
111 } 122 }
112 } 123 }
113 } 124 }
114 125
115 RETVAL = ngx_http_send_header(r); 126 (void) ngx_http_send_header(r);
116 127
117 done: 128
118 129 void
119 OUTPUT:
120 RETVAL
121
122
123 int
124 header_only(r) 130 header_only(r)
125 nginx r 131 CODE:
126 132
127 CODE: 133 dXSTARG;
128 RETVAL = r->header_only; 134 ngx_http_request_t *r;
129 135
130 OUTPUT: 136 ngx_http_perl_set_request(r);
131 RETVAL 137
132 138 sv_upgrade(TARG, SVt_IV);
133 139 sv_setiv(TARG, r->header_only);
134 # The returning "char *" is more quickly than creating SV, because SV returned 140
135 # from XS is never used as permanent storage. Even in simple case: 141 ST(0) = TARG;
136 # "$uri = $r->uri" the SV returned by $r->uri is copied to $uri's SV. 142
137 143
138 char * 144 void
139 uri(r, ...) 145 uri(r)
140 nginx r 146 CODE:
141 147
142 CODE: 148 dXSTARG;
143 149 ngx_http_request_t *r;
144 if (items != 1) { 150
145 croak("$r->uri(text) is not implemented"); 151 ngx_http_perl_set_request(r);
146 } 152 ngx_http_perl_set_targ(r->uri.data, r->uri.len, 0);
147 153
148 RETVAL = ngx_palloc(r->pool, r->uri.len + 1); 154 ST(0) = TARG;
149 if (RETVAL == NULL) { 155
150 XSRETURN_UNDEF; 156
151 } 157 void
152 158 args(r)
153 ngx_cpystrn((u_char *) RETVAL, r->uri.data, r->uri.len + 1); 159 CODE:
154 160
155 OUTPUT: 161 dXSTARG;
156 RETVAL 162 ngx_http_request_t *r;
157 163
158 164 ngx_http_perl_set_request(r);
159 char * 165 ngx_http_perl_set_targ(r->args.data, r->args.len, 0);
160 args(r, ...) 166
161 nginx r 167 ST(0) = TARG;
162 168
163 CODE: 169
164 170 void
165 if (items != 1) {
166 croak("$r->args(text) is not implemented");
167 }
168
169 RETVAL = ngx_palloc(r->pool, r->args.len + 1);
170 if (RETVAL == NULL) {
171 XSRETURN_UNDEF;
172 }
173
174 ngx_cpystrn((u_char *) RETVAL, r->args.data, r->args.len + 1);
175
176 OUTPUT:
177 RETVAL
178
179
180 char *
181 request_method(r) 171 request_method(r)
182 nginx r 172 CODE:
183 173
184 CODE: 174 dXSTARG;
185 175 ngx_http_request_t *r;
186 RETVAL = ngx_palloc(r->pool, r->method_name.len + 1); 176
187 if (RETVAL == NULL) { 177 ngx_http_perl_set_request(r);
188 XSRETURN_UNDEF; 178 ngx_http_perl_set_targ(r->method_name.data, r->method_name.len, 0);
189 } 179
190 180 ST(0) = TARG;
191 ngx_cpystrn((u_char *) RETVAL, r->method_name.data, r->method_name.len + 1); 181
192 182
193 OUTPUT: 183 void
194 RETVAL
195
196
197 char *
198 remote_addr(r) 184 remote_addr(r)
199 nginx r 185 CODE:
200 186
201 CODE: 187 dXSTARG;
202 188 ngx_http_request_t *r;
203 RETVAL = (char *) r->connection->addr_text.data; 189
204 190 ngx_http_perl_set_request(r);
205 OUTPUT: 191 ngx_http_perl_set_targ(r->connection->addr_text.data,
206 RETVAL 192 r->connection->addr_text.len, 1);
207 193
208 194 ST(0) = TARG;
209 char * 195
196
197 void
210 header_in(r, key) 198 header_in(r, key)
211 nginx r 199 CODE:
212 SV *key 200
213 201 dXSTARG;
214 PREINIT: 202 ngx_http_request_t *r;
215 203 SV *key;
216 u_char *p; 204 u_char *p;
217 STRLEN len; 205 STRLEN len;
218 ngx_uint_t i; 206 ngx_uint_t i;
219 ngx_list_part_t *part; 207 ngx_list_part_t *part;
220 ngx_table_elt_t *header; 208 ngx_table_elt_t *header;
221 209
222 CODE: 210 ngx_http_perl_set_request(r);
211
212 key = ST(1);
223 213
224 if (SvROK(key) && SvTYPE(SvRV(key)) == SVt_PV) { 214 if (SvROK(key) && SvTYPE(SvRV(key)) == SVt_PV) {
225 key = SvRV(key); 215 key = SvRV(key);
226 } 216 }
227 217
246 || ngx_strcasecmp(p, header[i].key.data) != 0) 236 || ngx_strcasecmp(p, header[i].key.data) != 0)
247 { 237 {
248 continue; 238 continue;
249 } 239 }
250 240
251 RETVAL = (char *) header[i].value.data; 241 ngx_http_perl_set_targ(header[i].value.data, header[i].value.len, 0);
252 242
253 goto done; 243 goto done;
254 } 244 }
255 245
256 XSRETURN_UNDEF; 246 XSRETURN_UNDEF;
257 247
258 done: 248 done:
259 249
260 OUTPUT: 250 ST(0) = TARG;
261 RETVAL 251
262 252
263 253 void
264 SV *
265 request_body(r) 254 request_body(r)
266 nginx r 255 CODE:
267 256
268 PREINIT: 257 dXSTARG;
269 258 ngx_http_request_t *r;
270 STRLEN len; 259 size_t len;
271 ngx_chain_t *cl; 260
272 261 ngx_http_perl_set_request(r);
273 CODE: 262
274 263 if (r->request_body->temp_file || r->request_body->bufs == NULL) {
275 len = 0; 264 XSRETURN_UNDEF;
276 265 }
277 for (cl = r->request_body->bufs; cl; cl = cl->next) { 266
278 if (cl->buf->in_file) { 267 len = r->request_body->bufs->buf->last - r->request_body->bufs->buf->pos;
279 XSRETURN_UNDEF;
280 }
281
282 len += cl->buf->last - cl->buf->pos;
283 }
284 268
285 if (len == 0) { 269 if (len == 0) {
286 XSRETURN_UNDEF; 270 XSRETURN_UNDEF;
287 } 271 }
288 272
289 RETVAL = newSV(len); 273 ngx_http_perl_set_targ(r->request_body->bufs->buf->pos, len, 0);
290 274
291 for (cl = r->request_body->bufs; cl; cl = cl->next) { 275 ST(0) = TARG;
292 sv_catpvn(RETVAL, cl->buf->pos, cl->buf->last - cl->buf->pos); 276
293 } 277
294 278 void
295 OUTPUT: 279 request_body_file(r)
296 RETVAL 280 CODE:
297 281
298 282 dXSTARG;
299 int 283 ngx_http_request_t *r;
284
285 ngx_http_perl_set_request(r);
286
287 if (r->request_body->temp_file == NULL) {
288 XSRETURN_UNDEF;
289 }
290
291 ngx_http_perl_set_targ(r->request_body->temp_file->file.name.data,
292 r->request_body->temp_file->file.name.len, 1);
293
294 ST(0) = TARG;
295
296
297 void
300 header_out(r, key, value) 298 header_out(r, key, value)
301 nginx r 299 CODE:
302 SV *key 300
303 SV *value 301 ngx_http_request_t *r;
304 302 SV *key;
305 PREINIT: 303 SV *value;
306 304 ngx_table_elt_t *header;
307 ngx_table_elt_t *header; 305
308 306 ngx_http_perl_set_request(r);
309 CODE: 307
308 key = ST(1);
309 value = ST(2);
310 310
311 header = ngx_list_push(&r->headers_out.headers); 311 header = ngx_list_push(&r->headers_out.headers);
312 if (header == NULL) { 312 if (header == NULL) {
313 RETVAL = NGX_ERROR; 313 XSRETURN_EMPTY;
314 goto done;
315 } 314 }
316 315
317 header->hash = 1; 316 header->hash = 1;
318 317
319 if (ngx_http_perl_sv2str(aTHX_ r, &header->key, key) != NGX_OK) { 318 if (ngx_http_perl_sv2str(aTHX_ r, &header->key, key) != NGX_OK) {
320 RETVAL = NGX_ERROR; 319 XSRETURN_EMPTY;
321 goto done;
322 } 320 }
323 321
324 if (ngx_http_perl_sv2str(aTHX_ r, &header->value, value) != NGX_OK) { 322 if (ngx_http_perl_sv2str(aTHX_ r, &header->value, value) != NGX_OK) {
325 RETVAL = NGX_ERROR; 323 XSRETURN_EMPTY;
326 goto done;
327 } 324 }
328 325
329 if (header->key.len == sizeof("Content-Length") - 1 326 if (header->key.len == sizeof("Content-Length") - 1
330 && ngx_strncasecmp(header->key.data, "Content-Length", 327 && ngx_strncasecmp(header->key.data, "Content-Length",
331 sizeof("Content-Length") - 1) == 0 328 sizeof("Content-Length") - 1) == 0
333 { 330 {
334 r->headers_out.content_length_n = (ssize_t) SvIV(value);; 331 r->headers_out.content_length_n = (ssize_t) SvIV(value);;
335 r->headers_out.content_length = header; 332 r->headers_out.content_length = header;
336 } 333 }
337 334
338 RETVAL = NGX_OK; 335 XSRETURN_EMPTY;
336
337
338 void
339 filename(r)
340 CODE:
341
342 dXSTARG;
343 ngx_http_request_t *r;
344 ngx_http_perl_ctx_t *ctx;
345
346 ngx_http_perl_set_request(r);
347
348 ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
349 if (ctx->filename.data) {
350 goto done;
351 }
352
353 if (ngx_http_map_uri_to_path(r, &ctx->filename, 0) == NULL) {
354 XSRETURN_UNDEF;
355 }
356
357 ctx->filename.len--;
358 sv_setpv(PL_statname, (char *) ctx->filename.data);
339 359
340 done: 360 done:
341 361
342 OUTPUT: 362 ngx_http_perl_set_targ(ctx->filename.data, ctx->filename.len, 1);
343 RETVAL 363
344 364 ST(0) = TARG;
345 365
346 char * 366
347 filename(r) 367 void
348 nginx r
349
350 PREINIT:
351
352 ngx_str_t path;
353 ngx_http_perl_ctx_t *ctx;
354
355 CODE:
356
357 ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
358 if (ctx->filename) {
359 goto done;
360 }
361
362 if (ngx_http_map_uri_to_path(r, &path, 0) == NULL) {
363 XSRETURN_UNDEF;
364 }
365
366 ctx->filename = (char *) path.data;
367
368 sv_setpv(PL_statname, ctx->filename);
369
370 done:
371
372 RETVAL = ctx->filename;
373
374 OUTPUT:
375 RETVAL
376
377
378 int
379 print(r, ...) 368 print(r, ...)
380 nginx r 369 CODE:
381 370
382 PREINIT: 371 ngx_http_request_t *r;
383 372 SV *sv;
384 SV *sv; 373 int i;
385 int i; 374 u_char *p;
386 u_char *p; 375 size_t size;
387 size_t size; 376 STRLEN len;
388 STRLEN len; 377 ngx_buf_t *b;
389 ngx_buf_t *b; 378
390 379 ngx_http_perl_set_request(r);
391 CODE:
392
393 RETVAL = NGX_OK;
394 380
395 if (items == 2) { 381 if (items == 2) {
396 382
397 /* 383 /*
398 * do zero copy for prolate single read-only SV: 384 * do zero copy for prolate single read-only SV:
408 if (SvREADONLY(sv)) { 394 if (SvREADONLY(sv)) {
409 395
410 p = (u_char *) SvPV(sv, len); 396 p = (u_char *) SvPV(sv, len);
411 397
412 if (len == 0) { 398 if (len == 0) {
413 goto done; 399 XSRETURN_EMPTY;
414 } 400 }
415 401
416 b = ngx_calloc_buf(r->pool); 402 b = ngx_calloc_buf(r->pool);
417 if (b == NULL) { 403 if (b == NULL) {
418 RETVAL = NGX_ERROR; 404 XSRETURN_EMPTY;
419 goto done;
420 } 405 }
421 406
422 b->memory = 1; 407 b->memory = 1;
423 b->pos = p; 408 b->pos = p;
424 b->last = p + len; 409 b->last = p + len;
449 434
450 size += len; 435 size += len;
451 } 436 }
452 437
453 if (size == 0) { 438 if (size == 0) {
454 goto done; 439 XSRETURN_EMPTY;
455 } 440 }
456 441
457 b = ngx_create_temp_buf(r->pool, size); 442 b = ngx_create_temp_buf(r->pool, size);
458 if (b == NULL) { 443 if (b == NULL) {
459 RETVAL = NGX_ERROR; 444 XSRETURN_EMPTY;
460 goto done;
461 } 445 }
462 446
463 for (i = 1; i < items; i++) { 447 for (i = 1; i < items; i++) {
464 sv = ST(i); 448 sv = ST(i);
465 449
471 b->last = ngx_cpymem(b->last, p, len); 455 b->last = ngx_cpymem(b->last, p, len);
472 } 456 }
473 457
474 out: 458 out:
475 459
476 RETVAL = ngx_http_perl_output(r, b); 460 (void) ngx_http_perl_output(r, b);
477 461
478 done: 462 XSRETURN_EMPTY;
479 463
480 OUTPUT: 464
481 RETVAL 465 void
482
483
484 int
485 sendfile(r, filename, offset = -1, bytes = 0) 466 sendfile(r, filename, offset = -1, bytes = 0)
486 nginx r 467 CODE:
487 char *filename 468
469 ngx_http_request_t *r;
470 char *filename;
488 int offset; 471 int offset;
489 size_t bytes; 472 size_t bytes;
490
491 PREINIT:
492
493 ngx_fd_t fd; 473 ngx_fd_t fd;
494 ngx_buf_t *b; 474 ngx_buf_t *b;
495 ngx_file_info_t fi; 475 ngx_file_info_t fi;
496 ngx_pool_cleanup_t *cln; 476 ngx_pool_cleanup_t *cln;
497 ngx_pool_cleanup_file_t *clnf; 477 ngx_pool_cleanup_file_t *clnf;
498 478
499 CODE: 479 ngx_http_perl_set_request(r);
480
481 filename = SvPV_nolen(ST(1));
500 482
501 if (filename == NULL) { 483 if (filename == NULL) {
502 croak("sendfile(): NULL filename"); 484 croak("sendfile(): NULL filename");
503 } 485 }
504 486
487 offset = items < 3 ? -1 : SvIV(ST(2));
488 bytes = items < 4 ? 0 : SvIV(ST(3));
489
505 b = ngx_calloc_buf(r->pool); 490 b = ngx_calloc_buf(r->pool);
506 if (b == NULL) { 491 if (b == NULL) {
507 RETVAL = NGX_ERROR; 492 XSRETURN_EMPTY;
508 goto done;
509 } 493 }
510 494
511 b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); 495 b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
512 if (b->file == NULL) { 496 if (b->file == NULL) {
513 RETVAL = NGX_ERROR; 497 XSRETURN_EMPTY;
514 goto done;
515 } 498 }
516 499
517 cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t)); 500 cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t));
518 if (cln == NULL) { 501 if (cln == NULL) {
519 RETVAL = NGX_ERROR; 502 XSRETURN_EMPTY;
520 goto done;
521 } 503 }
522 504
523 fd = ngx_open_file((u_char *) filename, NGX_FILE_RDONLY, NGX_FILE_OPEN); 505 fd = ngx_open_file((u_char *) filename, NGX_FILE_RDONLY, NGX_FILE_OPEN);
524 506
525 if (fd == NGX_INVALID_FILE) { 507 if (fd == NGX_INVALID_FILE) {
526 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, 508 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
527 ngx_open_file_n " \"%s\" failed", filename); 509 ngx_open_file_n " \"%s\" failed", filename);
528 RETVAL = NGX_ERROR; 510 XSRETURN_EMPTY;
529 goto done;
530 } 511 }
531 512
532 if (offset == -1) { 513 if (offset == -1) {
533 offset = 0; 514 offset = 0;
534 } 515 }
541 if (ngx_close_file(fd) == NGX_FILE_ERROR) { 522 if (ngx_close_file(fd) == NGX_FILE_ERROR) {
542 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, 523 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
543 ngx_close_file_n " \"%s\" failed", filename); 524 ngx_close_file_n " \"%s\" failed", filename);
544 } 525 }
545 526
546 RETVAL = NGX_ERROR; 527 XSRETURN_EMPTY;
547 goto done;
548
549 } 528 }
550 529
551 bytes = ngx_file_size(&fi) - offset; 530 bytes = ngx_file_size(&fi) - offset;
552 } 531 }
553 532
564 b->file_last = offset + bytes; 543 b->file_last = offset + bytes;
565 544
566 b->file->fd = fd; 545 b->file->fd = fd;
567 b->file->log = r->connection->log; 546 b->file->log = r->connection->log;
568 547
569 RETVAL = ngx_http_perl_output(r, b); 548 (void) ngx_http_perl_output(r, b);
570 549
571 done: 550 XSRETURN_EMPTY;
572 551
573 OUTPUT: 552
574 RETVAL 553 void
575
576
577 int
578 rflush(r) 554 rflush(r)
579 nginx r 555 CODE:
580 556
581 PREINIT: 557 ngx_http_request_t *r;
582 558 ngx_buf_t *b;
583 ngx_buf_t *b; 559
584 560 ngx_http_perl_set_request(r);
585 CODE:
586 561
587 b = ngx_calloc_buf(r->pool); 562 b = ngx_calloc_buf(r->pool);
588 if (b == NULL) { 563 if (b == NULL) {
589 RETVAL = NGX_ERROR; 564 XSRETURN_EMPTY;
590 goto done;
591 } 565 }
592 566
593 b->flush = 1; 567 b->flush = 1;
594 568
595 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "$r->rflush"); 569 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "$r->rflush");
596 570
597 RETVAL = ngx_http_perl_output(r, b); 571 (void) ngx_http_perl_output(r, b);
598 572
599 done: 573 XSRETURN_EMPTY;
600
601 OUTPUT:
602 RETVAL
603 574
604 575
605 void 576 void
606 internal_redirect(r, uri) 577 internal_redirect(r, uri)
607 nginx r 578 CODE:
608 SV *uri 579
609 580 ngx_http_request_t *r;
610 PREINIT: 581 SV *uri;
611
612 ngx_uint_t i; 582 ngx_uint_t i;
613 ngx_http_perl_ctx_t *ctx; 583 ngx_http_perl_ctx_t *ctx;
614 584
615 CODE: 585 ngx_http_perl_set_request(r);
586
587 uri = ST(1);
616 588
617 ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); 589 ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
618 590
619 if (ngx_http_perl_sv2str(aTHX_ r, &ctx->redirect_uri, uri) != NGX_OK) { 591 if (ngx_http_perl_sv2str(aTHX_ r, &ctx->redirect_uri, uri) != NGX_OK) {
620 XSRETURN_EMPTY; 592 XSRETURN_EMPTY;
630 XSRETURN_EMPTY; 602 XSRETURN_EMPTY;
631 } 603 }
632 } 604 }
633 605
634 606
635 char * 607 void
636 unescape(r, text, type = 0) 608 unescape(r, text, type = 0)
637 nginx r 609 CODE:
638 SV *text 610
639 int type 611 dXSTARG;
640 612 ngx_http_request_t *r;
641 PREINIT: 613 SV *text;
642 614 int type;
643 u_char *p, *dst, *src; 615 u_char *p, *dst, *src;
644 STRLEN n; 616 STRLEN len;
645 617
646 CODE: 618 ngx_http_perl_set_request(r);
647 619
648 src = (u_char *) SvPV(text, n); 620 text = ST(1);
649 621
650 p = ngx_palloc(r->pool, n + 1); 622 src = (u_char *) SvPV(text, len);
623
624 p = ngx_palloc(r->pool, len + 1);
651 if (p == NULL) { 625 if (p == NULL) {
652 XSRETURN_UNDEF; 626 XSRETURN_UNDEF;
653 } 627 }
654 628
655 dst = p; 629 dst = p;
656 630
657 ngx_unescape_uri(&dst, &src, n, (ngx_uint_t) type); 631 type = items < 3 ? 0 : SvIV(ST(2));
632
633 ngx_unescape_uri(&dst, &src, len, (ngx_uint_t) type);
658 *dst = '\0'; 634 *dst = '\0';
659 635
660 RETVAL = (char *) p; 636 ngx_http_perl_set_targ(p, dst - p, 1);
661 637
662 OUTPUT: 638 ST(0) = TARG;
663 RETVAL