Mercurial > hg > nginx
comparison src/http/modules/perl/nginx.xs @ 599:869b6444d234 release-0.3.21
nginx-0.3.21-RELEASE import
*) Feature: the ngx_http_perl_module.
*) Change: the "valid_referers" directive allows the referreres without
URI part.
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Mon, 16 Jan 2006 14:56:53 +0000 |
parents | |
children | 77f77f53214a |
comparison
equal
deleted
inserted
replaced
598:bfa12c280dec | 599:869b6444d234 |
---|---|
1 | |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #define PERL_NO_GET_CONTEXT | |
8 | |
9 #include "EXTERN.h" | |
10 #include "perl.h" | |
11 #include "XSUB.h" | |
12 | |
13 #include <ngx_config.h> | |
14 #include <ngx_core.h> | |
15 #include <ngx_http.h> | |
16 #include <ngx_http_perl_module.h> | |
17 | |
18 | |
19 static ngx_int_t | |
20 ngx_http_perl_sv2str(pTHX_ ngx_http_request_t *r, ngx_str_t *s, SV *sv) | |
21 { | |
22 u_char *p; | |
23 STRLEN len; | |
24 | |
25 if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PV) { | |
26 sv = SvRV(sv); | |
27 } | |
28 | |
29 p = (u_char *) SvPV(sv, len); | |
30 | |
31 s->len = len; | |
32 | |
33 if (SvREADONLY(sv)) { | |
34 s->data = p; | |
35 return NGX_OK; | |
36 } | |
37 | |
38 s->data = ngx_palloc(r->pool, len); | |
39 if (s->data == NULL) { | |
40 return NGX_ERROR; | |
41 } | |
42 | |
43 ngx_memcpy(s->data, p, len); | |
44 | |
45 return NGX_OK; | |
46 } | |
47 | |
48 | |
49 static ngx_int_t | |
50 ngx_http_perl_output(ngx_http_request_t *r, ngx_buf_t *b) | |
51 { | |
52 ngx_chain_t *cl, out; | |
53 ngx_http_perl_ctx_t *ctx; | |
54 | |
55 ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); | |
56 | |
57 if (ctx->ssi) { | |
58 cl = ngx_alloc_chain_link(r->pool); | |
59 if (cl == NULL) { | |
60 return NGX_ERROR; | |
61 } | |
62 | |
63 cl->buf = b; | |
64 cl->next = NULL; | |
65 *ctx->ssi->last_out = cl; | |
66 ctx->ssi->last_out = &cl->next; | |
67 | |
68 return NGX_OK; | |
69 } | |
70 | |
71 out.buf = b; | |
72 out.next = NULL; | |
73 | |
74 return ngx_http_output_filter(r, &out); | |
75 } | |
76 | |
77 | |
78 MODULE = nginx PACKAGE = nginx | |
79 | |
80 | |
81 int | |
82 send_http_header(r, ...) | |
83 nginx r | |
84 | |
85 PREINIT: | |
86 | |
87 SV *sv; | |
88 | |
89 CODE: | |
90 | |
91 if (r->headers_out.status == 0) { | |
92 r->headers_out.status = NGX_HTTP_OK; | |
93 } | |
94 | |
95 if (items != 1) { | |
96 sv = ST(1); | |
97 | |
98 if (ngx_http_perl_sv2str(aTHX_ r, &r->headers_out.content_type, sv) | |
99 != NGX_OK) | |
100 { | |
101 RETVAL = NGX_ERROR; | |
102 goto done; | |
103 } | |
104 | |
105 } else { | |
106 if (r->headers_out.content_type.len == 0) { | |
107 if (ngx_http_set_content_type(r) != NGX_OK) { | |
108 RETVAL = NGX_ERROR; | |
109 goto done; | |
110 } | |
111 } | |
112 } | |
113 | |
114 RETVAL = ngx_http_send_header(r); | |
115 | |
116 done: | |
117 | |
118 OUTPUT: | |
119 RETVAL | |
120 | |
121 | |
122 int | |
123 header_only(r) | |
124 nginx r | |
125 | |
126 CODE: | |
127 RETVAL = r->header_only; | |
128 | |
129 OUTPUT: | |
130 RETVAL | |
131 | |
132 | |
133 # The returning "char *" is more quickly than creating SV, because SV returned | |
134 # from XS is never used as permanent storage. Even in simple case: | |
135 # "$uri = $r->uri" the SV returned by $r->uri is copied to $uri's SV. | |
136 | |
137 char * | |
138 uri(r, ...) | |
139 nginx r | |
140 | |
141 CODE: | |
142 | |
143 if (items != 1) { | |
144 croak("$r->uri(text) is not implemented"); | |
145 } | |
146 | |
147 RETVAL = ngx_palloc(r->pool, r->uri.len + 1); | |
148 if (RETVAL == NULL) { | |
149 XSRETURN_UNDEF; | |
150 } | |
151 | |
152 ngx_cpystrn((u_char *) RETVAL, r->uri.data, r->uri.len + 1); | |
153 | |
154 OUTPUT: | |
155 RETVAL | |
156 | |
157 | |
158 char * | |
159 query_string(r, ...) | |
160 nginx r | |
161 | |
162 CODE: | |
163 | |
164 if (items != 1) { | |
165 croak("$r->query_string(text) is not implemented"); | |
166 } | |
167 | |
168 RETVAL = ngx_palloc(r->pool, r->args.len + 1); | |
169 if (RETVAL == NULL) { | |
170 XSRETURN_UNDEF; | |
171 } | |
172 | |
173 ngx_cpystrn((u_char *) RETVAL, r->args.data, r->args.len + 1); | |
174 | |
175 OUTPUT: | |
176 RETVAL | |
177 | |
178 | |
179 char * | |
180 header_in(r, key) | |
181 nginx r | |
182 SV *key | |
183 | |
184 PREINIT: | |
185 | |
186 u_char *p; | |
187 STRLEN len; | |
188 ngx_uint_t i; | |
189 ngx_list_part_t *part; | |
190 ngx_table_elt_t *header; | |
191 | |
192 CODE: | |
193 | |
194 if (SvROK(key) && SvTYPE(SvRV(key)) == SVt_PV) { | |
195 key = SvRV(key); | |
196 } | |
197 | |
198 p = (u_char *) SvPV(key, len); | |
199 | |
200 part = &r->headers_in.headers.part; | |
201 header = part->elts; | |
202 | |
203 for (i = 0; /* void */ ; i++) { | |
204 | |
205 if (i >= part->nelts) { | |
206 if (part->next == NULL) { | |
207 break; | |
208 } | |
209 | |
210 part = part->next; | |
211 header = part->elts; | |
212 i = 0; | |
213 } | |
214 | |
215 if (len != header[i].key.len | |
216 || ngx_strcasecmp(p, header[i].key.data) != 0) | |
217 { | |
218 continue; | |
219 } | |
220 | |
221 RETVAL = (char *) header[i].value.data; | |
222 | |
223 goto done; | |
224 } | |
225 | |
226 XSRETURN_UNDEF; | |
227 | |
228 done: | |
229 | |
230 OUTPUT: | |
231 RETVAL | |
232 | |
233 | |
234 int | |
235 header_out(r, key, value) | |
236 nginx r | |
237 SV *key | |
238 SV *value | |
239 | |
240 PREINIT: | |
241 | |
242 ngx_table_elt_t *header; | |
243 | |
244 CODE: | |
245 | |
246 header = ngx_list_push(&r->headers_out.headers); | |
247 if (header == NULL) { | |
248 RETVAL = NGX_ERROR; | |
249 goto done; | |
250 } | |
251 | |
252 header->hash = 1; | |
253 | |
254 if (ngx_http_perl_sv2str(aTHX_ r, &header->key, key) != NGX_OK) { | |
255 RETVAL = NGX_ERROR; | |
256 goto done; | |
257 } | |
258 | |
259 if (ngx_http_perl_sv2str(aTHX_ r, &header->value, value) != NGX_OK) { | |
260 RETVAL = NGX_ERROR; | |
261 goto done; | |
262 } | |
263 | |
264 if (header->key.len == sizeof("Content-Length") - 1 | |
265 && ngx_strncasecmp(header->key.data, "Content-Length", | |
266 sizeof("Content-Length") - 1) == 0 | |
267 && SvIOK(value)) | |
268 { | |
269 r->headers_out.content_length_n = (ssize_t) SvIV(value);; | |
270 r->headers_out.content_length = header; | |
271 } | |
272 | |
273 RETVAL = NGX_OK; | |
274 | |
275 done: | |
276 | |
277 OUTPUT: | |
278 RETVAL | |
279 | |
280 | |
281 char * | |
282 filename(r) | |
283 nginx r | |
284 | |
285 PREINIT: | |
286 | |
287 ngx_str_t path; | |
288 ngx_http_perl_ctx_t *ctx; | |
289 | |
290 CODE: | |
291 | |
292 ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); | |
293 if (ctx->filename) { | |
294 goto done; | |
295 } | |
296 | |
297 if (ngx_http_map_uri_to_path(r, &path, 0) == NULL) { | |
298 XSRETURN_UNDEF; | |
299 } | |
300 | |
301 ctx->filename = (char *) path.data; | |
302 | |
303 sv_setpv(PL_statname, ctx->filename); | |
304 | |
305 done: | |
306 | |
307 RETVAL = ctx->filename; | |
308 | |
309 OUTPUT: | |
310 RETVAL | |
311 | |
312 | |
313 int | |
314 print(r, ...) | |
315 nginx r | |
316 | |
317 PREINIT: | |
318 | |
319 SV *sv; | |
320 int i; | |
321 u_char *p; | |
322 size_t size; | |
323 STRLEN len; | |
324 ngx_buf_t *b; | |
325 | |
326 CODE: | |
327 | |
328 RETVAL = NGX_OK; | |
329 | |
330 if (items == 2) { | |
331 | |
332 /* | |
333 * do zero copy for prolate single read-only SV: | |
334 * $r->print("some text\n"); | |
335 */ | |
336 | |
337 sv = ST(1); | |
338 | |
339 if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PV) { | |
340 sv = SvRV(sv); | |
341 } | |
342 | |
343 if (SvREADONLY(sv)) { | |
344 | |
345 p = (u_char *) SvPV(sv, len); | |
346 | |
347 if (len == 0) { | |
348 goto done; | |
349 } | |
350 | |
351 b = ngx_calloc_buf(r->pool); | |
352 if (b == NULL) { | |
353 RETVAL = NGX_ERROR; | |
354 goto done; | |
355 } | |
356 | |
357 b->memory = 1; | |
358 b->pos = p; | |
359 b->last = p + len; | |
360 b->start = p; | |
361 b->end = b->last; | |
362 | |
363 goto out; | |
364 } | |
365 } | |
366 | |
367 size = 0; | |
368 | |
369 for (i = 1; i < items; i++) { | |
370 | |
371 sv = ST(i); | |
372 | |
373 if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PV) { | |
374 sv = SvRV(sv); | |
375 } | |
376 | |
377 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
378 "SV: %p %d %Xd", | |
379 sv, SvREFCNT(sv), SvREADONLY(sv)); | |
380 | |
381 (void) SvPV(sv, len); | |
382 | |
383 size += len; | |
384 } | |
385 | |
386 if (size == 0) { | |
387 goto done; | |
388 } | |
389 | |
390 b = ngx_create_temp_buf(r->pool, size); | |
391 if (b == NULL) { | |
392 RETVAL = NGX_ERROR; | |
393 goto done; | |
394 } | |
395 | |
396 for (i = 1; i < items; i++) { | |
397 sv = ST(i); | |
398 | |
399 if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PV) { | |
400 sv = SvRV(sv); | |
401 } | |
402 | |
403 p = (u_char *) SvPV(sv, len); | |
404 b->last = ngx_cpymem(b->last, p, len); | |
405 } | |
406 | |
407 out: | |
408 | |
409 RETVAL = ngx_http_perl_output(r, b); | |
410 | |
411 done: | |
412 | |
413 OUTPUT: | |
414 RETVAL | |
415 | |
416 | |
417 int | |
418 sendfile(r, filename) | |
419 nginx r | |
420 char *filename | |
421 | |
422 PREINIT: | |
423 | |
424 ngx_fd_t fd; | |
425 ngx_buf_t *b; | |
426 ngx_file_info_t fi; | |
427 ngx_pool_cleanup_t *cln; | |
428 ngx_pool_cleanup_file_t *clnf; | |
429 | |
430 CODE: | |
431 | |
432 if (filename == NULL) { | |
433 croak("sendfile(): NULL filename"); | |
434 } | |
435 | |
436 b = ngx_calloc_buf(r->pool); | |
437 if (b == NULL) { | |
438 RETVAL = NGX_ERROR; | |
439 goto done; | |
440 } | |
441 | |
442 b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); | |
443 if (b->file == NULL) { | |
444 RETVAL = NGX_ERROR; | |
445 goto done; | |
446 } | |
447 | |
448 cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t)); | |
449 if (cln == NULL) { | |
450 RETVAL = NGX_ERROR; | |
451 goto done; | |
452 } | |
453 | |
454 fd = ngx_open_file((u_char *) filename, NGX_FILE_RDONLY, NGX_FILE_OPEN); | |
455 | |
456 if (fd == NGX_INVALID_FILE) { | |
457 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, | |
458 ngx_open_file_n " \"%s\" failed", filename); | |
459 RETVAL = NGX_ERROR; | |
460 goto done; | |
461 } | |
462 | |
463 if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { | |
464 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, | |
465 ngx_fd_info_n " \"%s\" failed", filename); | |
466 | |
467 if (ngx_close_file(fd) == NGX_FILE_ERROR) { | |
468 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, | |
469 ngx_close_file_n " \"%s\" failed", filename); | |
470 } | |
471 | |
472 RETVAL = NGX_ERROR; | |
473 goto done; | |
474 } | |
475 | |
476 cln->handler = ngx_pool_cleanup_file; | |
477 clnf = cln->data; | |
478 | |
479 clnf->fd = fd; | |
480 clnf->name = (u_char *) ""; | |
481 clnf->log = r->pool->log; | |
482 | |
483 b->in_file = 1; | |
484 b->file_pos = 0; | |
485 b->file_last = ngx_file_size(&fi); | |
486 | |
487 b->file->fd = fd; | |
488 b->file->log = r->connection->log; | |
489 | |
490 RETVAL = ngx_http_perl_output(r, b); | |
491 | |
492 done: | |
493 | |
494 OUTPUT: | |
495 RETVAL | |
496 | |
497 | |
498 int | |
499 rflush(r) | |
500 nginx r | |
501 | |
502 PREINIT: | |
503 | |
504 ngx_buf_t *b; | |
505 | |
506 CODE: | |
507 | |
508 b = ngx_calloc_buf(r->pool); | |
509 if (b == NULL) { | |
510 RETVAL = NGX_ERROR; | |
511 goto done; | |
512 } | |
513 | |
514 b->flush = 1; | |
515 | |
516 RETVAL = ngx_http_perl_output(r, b); | |
517 | |
518 done: | |
519 | |
520 OUTPUT: | |
521 RETVAL | |
522 | |
523 | |
524 void | |
525 internal_redirect(r, uri) | |
526 nginx r | |
527 SV *uri | |
528 | |
529 PREINIT: | |
530 | |
531 ngx_uint_t i; | |
532 ngx_http_perl_ctx_t *ctx; | |
533 | |
534 CODE: | |
535 | |
536 ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); | |
537 | |
538 if (ngx_http_perl_sv2str(aTHX_ r, &ctx->redirect_uri, uri) != NGX_OK) { | |
539 XSRETURN_EMPTY; | |
540 } | |
541 | |
542 for (i = 0; i < ctx->redirect_uri.len; i++) { | |
543 if (ctx->redirect_uri.data[i] == '?') { | |
544 | |
545 ctx->redirect_args.len = ctx->redirect_uri.len - (i + 1); | |
546 ctx->redirect_args.data = &ctx->redirect_uri.data[i + 1]; | |
547 ctx->redirect_uri.len = i; | |
548 | |
549 XSRETURN_EMPTY; | |
550 } | |
551 } |