Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_http_fastcgi_module.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11 
12 
13 typedef struct {
15 
17 
23 
26 
29 
31 
32 #if (NGX_HTTP_CACHE)
33  ngx_http_complex_value_t cache_key;
34 #endif
35 
36 #if (NGX_PCRE)
37  ngx_regex_t *split_regex;
38  ngx_str_t split_name;
39 #endif
41 
42 
43 typedef enum {
55 
56 
57 typedef struct {
58  u_char *start;
59  u_char *end;
61 
62 
63 typedef struct {
65  u_char *pos;
66  u_char *last;
68  size_t length;
69  size_t padding;
70 
71  unsigned fastcgi_stdout:1;
72  unsigned large_stderr:1;
73 
75 
79 
80 
81 #define NGX_HTTP_FASTCGI_RESPONDER 1
82 
83 #define NGX_HTTP_FASTCGI_KEEP_CONN 1
84 
85 #define NGX_HTTP_FASTCGI_BEGIN_REQUEST 1
86 #define NGX_HTTP_FASTCGI_ABORT_REQUEST 2
87 #define NGX_HTTP_FASTCGI_END_REQUEST 3
88 #define NGX_HTTP_FASTCGI_PARAMS 4
89 #define NGX_HTTP_FASTCGI_STDIN 5
90 #define NGX_HTTP_FASTCGI_STDOUT 6
91 #define NGX_HTTP_FASTCGI_STDERR 7
92 #define NGX_HTTP_FASTCGI_DATA 8
93 
94 
95 typedef struct {
96  u_char version;
97  u_char type;
98  u_char request_id_hi;
99  u_char request_id_lo;
103  u_char reserved;
105 
106 
107 typedef struct {
108  u_char role_hi;
109  u_char role_lo;
110  u_char flags;
111  u_char reserved[5];
113 
114 
115 typedef struct {
116  u_char version;
117  u_char type;
121 
122 
123 typedef struct {
128 
129 
130 static ngx_int_t ngx_http_fastcgi_eval(ngx_http_request_t *r,
132 #if (NGX_HTTP_CACHE)
133 static ngx_int_t ngx_http_fastcgi_create_key(ngx_http_request_t *r);
134 #endif
135 static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r);
136 static ngx_int_t ngx_http_fastcgi_reinit_request(ngx_http_request_t *r);
137 static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r);
138 static ngx_int_t ngx_http_fastcgi_input_filter_init(void *data);
139 static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p,
140  ngx_buf_t *buf);
141 static ngx_int_t ngx_http_fastcgi_process_record(ngx_http_request_t *r,
143 static void ngx_http_fastcgi_abort_request(ngx_http_request_t *r);
144 static void ngx_http_fastcgi_finalize_request(ngx_http_request_t *r,
145  ngx_int_t rc);
146 
147 static ngx_int_t ngx_http_fastcgi_add_variables(ngx_conf_t *cf);
148 static void *ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf);
149 static char *ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf,
150  void *parent, void *child);
151 static ngx_int_t ngx_http_fastcgi_merge_params(ngx_conf_t *cf,
153 
154 static ngx_int_t ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r,
155  ngx_http_variable_value_t *v, uintptr_t data);
156 static ngx_int_t ngx_http_fastcgi_path_info_variable(ngx_http_request_t *r,
157  ngx_http_variable_value_t *v, uintptr_t data);
158 static ngx_http_fastcgi_ctx_t *ngx_http_fastcgi_split(ngx_http_request_t *r,
160 
161 static char *ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd,
162  void *conf);
163 static char *ngx_http_fastcgi_split_path_info(ngx_conf_t *cf,
164  ngx_command_t *cmd, void *conf);
165 static char *ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd,
166  void *conf);
167 #if (NGX_HTTP_CACHE)
168 static char *ngx_http_fastcgi_cache(ngx_conf_t *cf, ngx_command_t *cmd,
169  void *conf);
170 static char *ngx_http_fastcgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
171  void *conf);
172 #endif
173 
174 static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post,
175  void *data);
176 
177 
178 static ngx_conf_post_t ngx_http_fastcgi_lowat_post =
179  { ngx_http_fastcgi_lowat_check };
180 
181 
182 static ngx_conf_bitmask_t ngx_http_fastcgi_next_upstream_masks[] = {
185  { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
186  { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
187  { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
188  { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
189  { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
191  { ngx_null_string, 0 }
192 };
193 
194 
196 
197 
198 static ngx_command_t ngx_http_fastcgi_commands[] = {
199 
200  { ngx_string("fastcgi_pass"),
202  ngx_http_fastcgi_pass,
204  0,
205  NULL },
206 
207  { ngx_string("fastcgi_index"),
212  NULL },
213 
214  { ngx_string("fastcgi_split_path_info"),
216  ngx_http_fastcgi_split_path_info,
218  0,
219  NULL },
220 
221  { ngx_string("fastcgi_store"),
223  ngx_http_fastcgi_store,
225  0,
226  NULL },
227 
228  { ngx_string("fastcgi_store_access"),
232  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.store_access),
233  NULL },
234 
235  { ngx_string("fastcgi_ignore_client_abort"),
239  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.ignore_client_abort),
240  NULL },
241 
242  { ngx_string("fastcgi_bind"),
246  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.local),
247  NULL },
248 
249  { ngx_string("fastcgi_connect_timeout"),
253  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.connect_timeout),
254  NULL },
255 
256  { ngx_string("fastcgi_send_timeout"),
260  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.send_timeout),
261  NULL },
262 
263  { ngx_string("fastcgi_send_lowat"),
267  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.send_lowat),
268  &ngx_http_fastcgi_lowat_post },
269 
270  { ngx_string("fastcgi_buffer_size"),
274  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.buffer_size),
275  NULL },
276 
277  { ngx_string("fastcgi_pass_request_headers"),
281  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_request_headers),
282  NULL },
283 
284  { ngx_string("fastcgi_pass_request_body"),
288  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_request_body),
289  NULL },
290 
291  { ngx_string("fastcgi_intercept_errors"),
295  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.intercept_errors),
296  NULL },
297 
298  { ngx_string("fastcgi_read_timeout"),
302  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.read_timeout),
303  NULL },
304 
305  { ngx_string("fastcgi_buffers"),
309  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.bufs),
310  NULL },
311 
312  { ngx_string("fastcgi_busy_buffers_size"),
316  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.busy_buffers_size_conf),
317  NULL },
318 
319 #if (NGX_HTTP_CACHE)
320 
321  { ngx_string("fastcgi_cache"),
323  ngx_http_fastcgi_cache,
325  0,
326  NULL },
327 
328  { ngx_string("fastcgi_cache_key"),
330  ngx_http_fastcgi_cache_key,
332  0,
333  NULL },
334 
335  { ngx_string("fastcgi_cache_path"),
338  0,
339  0,
340  &ngx_http_fastcgi_module },
341 
342  { ngx_string("fastcgi_cache_bypass"),
346  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_bypass),
347  NULL },
348 
349  { ngx_string("fastcgi_no_cache"),
353  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.no_cache),
354  NULL },
355 
356  { ngx_string("fastcgi_cache_valid"),
360  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_valid),
361  NULL },
362 
363  { ngx_string("fastcgi_cache_min_uses"),
367  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_min_uses),
368  NULL },
369 
370  { ngx_string("fastcgi_cache_use_stale"),
374  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_use_stale),
375  &ngx_http_fastcgi_next_upstream_masks },
376 
377  { ngx_string("fastcgi_cache_methods"),
381  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_methods),
383 
384  { ngx_string("fastcgi_cache_lock"),
388  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock),
389  NULL },
390 
391  { ngx_string("fastcgi_cache_lock_timeout"),
395  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock_timeout),
396  NULL },
397 
398 #endif
399 
400  { ngx_string("fastcgi_temp_path"),
404  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.temp_path),
405  NULL },
406 
407  { ngx_string("fastcgi_max_temp_file_size"),
411  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.max_temp_file_size_conf),
412  NULL },
413 
414  { ngx_string("fastcgi_temp_file_write_size"),
418  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.temp_file_write_size_conf),
419  NULL },
420 
421  { ngx_string("fastcgi_next_upstream"),
425  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream),
426  &ngx_http_fastcgi_next_upstream_masks },
427 
428  { ngx_string("fastcgi_param"),
432  offsetof(ngx_http_fastcgi_loc_conf_t, params_source),
433  NULL },
434 
435  { ngx_string("fastcgi_pass_header"),
439  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_headers),
440  NULL },
441 
442  { ngx_string("fastcgi_hide_header"),
446  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.hide_headers),
447  NULL },
448 
449  { ngx_string("fastcgi_ignore_headers"),
453  offsetof(ngx_http_fastcgi_loc_conf_t, upstream.ignore_headers),
455 
456  { ngx_string("fastcgi_catch_stderr"),
460  offsetof(ngx_http_fastcgi_loc_conf_t, catch_stderr),
461  NULL },
462 
463  { ngx_string("fastcgi_keep_conn"),
467  offsetof(ngx_http_fastcgi_loc_conf_t, keep_conn),
468  NULL },
469 
471 };
472 
473 
474 static ngx_http_module_t ngx_http_fastcgi_module_ctx = {
475  ngx_http_fastcgi_add_variables, /* preconfiguration */
476  NULL, /* postconfiguration */
477 
478  NULL, /* create main configuration */
479  NULL, /* init main configuration */
480 
481  NULL, /* create server configuration */
482  NULL, /* merge server configuration */
483 
484  ngx_http_fastcgi_create_loc_conf, /* create location configuration */
485  ngx_http_fastcgi_merge_loc_conf /* merge location configuration */
486 };
487 
488 
489 ngx_module_t ngx_http_fastcgi_module = {
491  &ngx_http_fastcgi_module_ctx, /* module context */
492  ngx_http_fastcgi_commands, /* module directives */
493  NGX_HTTP_MODULE, /* module type */
494  NULL, /* init master */
495  NULL, /* init module */
496  NULL, /* init process */
497  NULL, /* init thread */
498  NULL, /* exit thread */
499  NULL, /* exit process */
500  NULL, /* exit master */
502 };
503 
504 
505 static ngx_http_fastcgi_request_start_t ngx_http_fastcgi_request_start = {
506  { 1, /* version */
508  0, /* request_id_hi */
509  1, /* request_id_lo */
510  0, /* content_length_hi */
511  sizeof(ngx_http_fastcgi_begin_request_t), /* content_length_lo */
512  0, /* padding_length */
513  0 }, /* reserved */
514 
515  { 0, /* role_hi */
516  NGX_HTTP_FASTCGI_RESPONDER, /* role_lo */
517  0, /* NGX_HTTP_FASTCGI_KEEP_CONN */ /* flags */
518  { 0, 0, 0, 0, 0 } }, /* reserved[5] */
519 
520  { 1, /* version */
521  NGX_HTTP_FASTCGI_PARAMS, /* type */
522  0, /* request_id_hi */
523  1 }, /* request_id_lo */
524 
525 };
526 
527 
528 static ngx_http_variable_t ngx_http_fastcgi_vars[] = {
529 
530  { ngx_string("fastcgi_script_name"), NULL,
531  ngx_http_fastcgi_script_name_variable, 0,
533 
534  { ngx_string("fastcgi_path_info"), NULL,
535  ngx_http_fastcgi_path_info_variable, 0,
537 
538  { ngx_null_string, NULL, NULL, 0, 0, 0 }
539 };
540 
541 
542 static ngx_str_t ngx_http_fastcgi_hide_headers[] = {
543  ngx_string("Status"),
544  ngx_string("X-Accel-Expires"),
545  ngx_string("X-Accel-Redirect"),
546  ngx_string("X-Accel-Limit-Rate"),
547  ngx_string("X-Accel-Buffering"),
548  ngx_string("X-Accel-Charset"),
550 };
551 
552 
553 #if (NGX_HTTP_CACHE)
554 
555 static ngx_keyval_t ngx_http_fastcgi_cache_headers[] = {
556  { ngx_string("HTTP_IF_MODIFIED_SINCE"), ngx_string("") },
557  { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
558  { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("") },
559  { ngx_string("HTTP_IF_MATCH"), ngx_string("") },
560  { ngx_string("HTTP_RANGE"), ngx_string("") },
561  { ngx_string("HTTP_IF_RANGE"), ngx_string("") },
563 };
564 
565 #endif
566 
567 
568 static ngx_path_init_t ngx_http_fastcgi_temp_path = {
570 };
571 
572 
573 static ngx_int_t
574 ngx_http_fastcgi_handler(ngx_http_request_t *r)
575 {
576  ngx_int_t rc;
580 
581  if (r->subrequest_in_memory) {
583  "ngx_http_fastcgi_module does not support "
584  "subrequest in memory");
586  }
587 
588  if (ngx_http_upstream_create(r) != NGX_OK) {
590  }
591 
592  f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
593  if (f == NULL) {
595  }
596 
597  ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
598 
599  flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
600 
601  if (flcf->fastcgi_lengths) {
602  if (ngx_http_fastcgi_eval(r, flcf) != NGX_OK) {
604  }
605  }
606 
607  u = r->upstream;
608 
609  ngx_str_set(&u->schema, "fastcgi://");
610  u->output.tag = (ngx_buf_tag_t) &ngx_http_fastcgi_module;
611 
612  u->conf = &flcf->upstream;
613 
614 #if (NGX_HTTP_CACHE)
615  u->create_key = ngx_http_fastcgi_create_key;
616 #endif
617  u->create_request = ngx_http_fastcgi_create_request;
618  u->reinit_request = ngx_http_fastcgi_reinit_request;
619  u->process_header = ngx_http_fastcgi_process_header;
620  u->abort_request = ngx_http_fastcgi_abort_request;
621  u->finalize_request = ngx_http_fastcgi_finalize_request;
622  r->state = 0;
623 
624  u->buffering = 1;
625 
626  u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
627  if (u->pipe == NULL) {
629  }
630 
631  u->pipe->input_filter = ngx_http_fastcgi_input_filter;
632  u->pipe->input_ctx = r;
633 
634  u->input_filter_init = ngx_http_fastcgi_input_filter_init;
635 
637 
638  if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
639  return rc;
640  }
641 
642  return NGX_DONE;
643 }
644 
645 
646 static ngx_int_t
647 ngx_http_fastcgi_eval(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
648 {
649  ngx_url_t url;
651 
652  ngx_memzero(&url, sizeof(ngx_url_t));
653 
654  if (ngx_http_script_run(r, &url.url, flcf->fastcgi_lengths->elts, 0,
655  flcf->fastcgi_values->elts)
656  == NULL)
657  {
658  return NGX_ERROR;
659  }
660 
661  url.no_resolve = 1;
662 
663  if (ngx_parse_url(r->pool, &url) != NGX_OK) {
664  if (url.err) {
666  "%s in upstream \"%V\"", url.err, &url.url);
667  }
668 
669  return NGX_ERROR;
670  }
671 
672  u = r->upstream;
673 
675  if (u->resolved == NULL) {
676  return NGX_ERROR;
677  }
678 
679  if (url.addrs && url.addrs[0].sockaddr) {
680  u->resolved->sockaddr = url.addrs[0].sockaddr;
681  u->resolved->socklen = url.addrs[0].socklen;
682  u->resolved->naddrs = 1;
683  u->resolved->host = url.addrs[0].name;
684 
685  } else {
686  u->resolved->host = url.host;
687  u->resolved->port = url.port;
688  u->resolved->no_port = url.no_port;
689  }
690 
691  return NGX_OK;
692 }
693 
694 
695 #if (NGX_HTTP_CACHE)
696 
697 static ngx_int_t
698 ngx_http_fastcgi_create_key(ngx_http_request_t *r)
699 {
700  ngx_str_t *key;
702 
703  key = ngx_array_push(&r->cache->keys);
704  if (key == NULL) {
705  return NGX_ERROR;
706  }
707 
708  flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
709 
710  if (ngx_http_complex_value(r, &flcf->cache_key, key) != NGX_OK) {
711  return NGX_ERROR;
712  }
713 
714  return NGX_OK;
715 }
716 
717 #endif
718 
719 
720 static ngx_int_t
721 ngx_http_fastcgi_create_request(ngx_http_request_t *r)
722 {
723  off_t file_pos;
724  u_char ch, *pos, *lowcase_key;
725  size_t size, len, key_len, val_len, padding,
726  allocated;
727  ngx_uint_t i, n, next, hash, skip_empty, header_params;
728  ngx_buf_t *b;
729  ngx_chain_t *cl, *body;
730  ngx_list_part_t *part;
731  ngx_table_elt_t *header, **ignored;
737 
738  len = 0;
739  header_params = 0;
740  ignored = NULL;
741 
742  flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
743 
744  if (flcf->params_len) {
746 
748  le.flushed = 1;
749 
750  le.ip = flcf->params_len->elts;
751  le.request = r;
752 
753  while (*(uintptr_t *) le.ip) {
754 
755  lcode = *(ngx_http_script_len_code_pt *) le.ip;
756  key_len = lcode(&le);
757 
758  lcode = *(ngx_http_script_len_code_pt *) le.ip;
759  skip_empty = lcode(&le);
760 
761  for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
762  lcode = *(ngx_http_script_len_code_pt *) le.ip;
763  }
764  le.ip += sizeof(uintptr_t);
765 
766  if (skip_empty && val_len == 0) {
767  continue;
768  }
769 
770  len += 1 + key_len + ((val_len > 127) ? 4 : 1) + val_len;
771  }
772  }
773 
774  if (flcf->upstream.pass_request_headers) {
775 
776  allocated = 0;
777  lowcase_key = NULL;
778 
779  if (flcf->header_params) {
780  n = 0;
781  part = &r->headers_in.headers.part;
782 
783  while (part) {
784  n += part->nelts;
785  part = part->next;
786  }
787 
788  ignored = ngx_palloc(r->pool, n * sizeof(void *));
789  if (ignored == NULL) {
790  return NGX_ERROR;
791  }
792  }
793 
794  part = &r->headers_in.headers.part;
795  header = part->elts;
796 
797  for (i = 0; /* void */; i++) {
798 
799  if (i >= part->nelts) {
800  if (part->next == NULL) {
801  break;
802  }
803 
804  part = part->next;
805  header = part->elts;
806  i = 0;
807  }
808 
809  if (flcf->header_params) {
810  if (allocated < header[i].key.len) {
811  allocated = header[i].key.len + 16;
812  lowcase_key = ngx_pnalloc(r->pool, allocated);
813  if (lowcase_key == NULL) {
814  return NGX_ERROR;
815  }
816  }
817 
818  hash = 0;
819 
820  for (n = 0; n < header[i].key.len; n++) {
821  ch = header[i].key.data[n];
822 
823  if (ch >= 'A' && ch <= 'Z') {
824  ch |= 0x20;
825 
826  } else if (ch == '-') {
827  ch = '_';
828  }
829 
830  hash = ngx_hash(hash, ch);
831  lowcase_key[n] = ch;
832  }
833 
834  if (ngx_hash_find(&flcf->headers_hash, hash, lowcase_key, n)) {
835  ignored[header_params++] = &header[i];
836  continue;
837  }
838 
839  n += sizeof("HTTP_") - 1;
840 
841  } else {
842  n = sizeof("HTTP_") - 1 + header[i].key.len;
843  }
844 
845  len += ((n > 127) ? 4 : 1) + ((header[i].value.len > 127) ? 4 : 1)
846  + n + header[i].value.len;
847  }
848  }
849 
850 
851  if (len > 65535) {
853  "fastcgi request record is too big: %uz", len);
854  return NGX_ERROR;
855  }
856 
857 
858  padding = 8 - len % 8;
859  padding = (padding == 8) ? 0 : padding;
860 
861 
862  size = sizeof(ngx_http_fastcgi_header_t)
864 
865  + sizeof(ngx_http_fastcgi_header_t) /* NGX_HTTP_FASTCGI_PARAMS */
866  + len + padding
867  + sizeof(ngx_http_fastcgi_header_t) /* NGX_HTTP_FASTCGI_PARAMS */
868 
869  + sizeof(ngx_http_fastcgi_header_t); /* NGX_HTTP_FASTCGI_STDIN */
870 
871 
872  b = ngx_create_temp_buf(r->pool, size);
873  if (b == NULL) {
874  return NGX_ERROR;
875  }
876 
877  cl = ngx_alloc_chain_link(r->pool);
878  if (cl == NULL) {
879  return NGX_ERROR;
880  }
881 
882  cl->buf = b;
883 
884  ngx_http_fastcgi_request_start.br.flags =
886 
887  ngx_memcpy(b->pos, &ngx_http_fastcgi_request_start,
889 
891  (b->pos + sizeof(ngx_http_fastcgi_header_t)
893 
894  h->content_length_hi = (u_char) ((len >> 8) & 0xff);
895  h->content_length_lo = (u_char) (len & 0xff);
896  h->padding_length = (u_char) padding;
897  h->reserved = 0;
898 
899  b->last = b->pos + sizeof(ngx_http_fastcgi_header_t)
901  + sizeof(ngx_http_fastcgi_header_t);
902 
903 
904  if (flcf->params_len) {
906 
907  e.ip = flcf->params->elts;
908  e.pos = b->last;
909  e.request = r;
910  e.flushed = 1;
911 
912  le.ip = flcf->params_len->elts;
913 
914  while (*(uintptr_t *) le.ip) {
915 
916  lcode = *(ngx_http_script_len_code_pt *) le.ip;
917  key_len = (u_char) lcode(&le);
918 
919  lcode = *(ngx_http_script_len_code_pt *) le.ip;
920  skip_empty = lcode(&le);
921 
922  for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
923  lcode = *(ngx_http_script_len_code_pt *) le.ip;
924  }
925  le.ip += sizeof(uintptr_t);
926 
927  if (skip_empty && val_len == 0) {
928  e.skip = 1;
929 
930  while (*(uintptr_t *) e.ip) {
931  code = *(ngx_http_script_code_pt *) e.ip;
932  code((ngx_http_script_engine_t *) &e);
933  }
934  e.ip += sizeof(uintptr_t);
935 
936  e.skip = 0;
937 
938  continue;
939  }
940 
941  *e.pos++ = (u_char) key_len;
942 
943  if (val_len > 127) {
944  *e.pos++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
945  *e.pos++ = (u_char) ((val_len >> 16) & 0xff);
946  *e.pos++ = (u_char) ((val_len >> 8) & 0xff);
947  *e.pos++ = (u_char) (val_len & 0xff);
948 
949  } else {
950  *e.pos++ = (u_char) val_len;
951  }
952 
953  while (*(uintptr_t *) e.ip) {
954  code = *(ngx_http_script_code_pt *) e.ip;
955  code((ngx_http_script_engine_t *) &e);
956  }
957  e.ip += sizeof(uintptr_t);
958 
960  "fastcgi param: \"%*s: %*s\"",
961  key_len, e.pos - (key_len + val_len),
962  val_len, e.pos - val_len);
963  }
964 
965  b->last = e.pos;
966  }
967 
968 
969  if (flcf->upstream.pass_request_headers) {
970 
971  part = &r->headers_in.headers.part;
972  header = part->elts;
973 
974  for (i = 0; /* void */; i++) {
975 
976  if (i >= part->nelts) {
977  if (part->next == NULL) {
978  break;
979  }
980 
981  part = part->next;
982  header = part->elts;
983  i = 0;
984  }
985 
986  for (n = 0; n < header_params; n++) {
987  if (&header[i] == ignored[n]) {
988  goto next;
989  }
990  }
991 
992  key_len = sizeof("HTTP_") - 1 + header[i].key.len;
993  if (key_len > 127) {
994  *b->last++ = (u_char) (((key_len >> 24) & 0x7f) | 0x80);
995  *b->last++ = (u_char) ((key_len >> 16) & 0xff);
996  *b->last++ = (u_char) ((key_len >> 8) & 0xff);
997  *b->last++ = (u_char) (key_len & 0xff);
998 
999  } else {
1000  *b->last++ = (u_char) key_len;
1001  }
1002 
1003  val_len = header[i].value.len;
1004  if (val_len > 127) {
1005  *b->last++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
1006  *b->last++ = (u_char) ((val_len >> 16) & 0xff);
1007  *b->last++ = (u_char) ((val_len >> 8) & 0xff);
1008  *b->last++ = (u_char) (val_len & 0xff);
1009 
1010  } else {
1011  *b->last++ = (u_char) val_len;
1012  }
1013 
1014  b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1);
1015 
1016  for (n = 0; n < header[i].key.len; n++) {
1017  ch = header[i].key.data[n];
1018 
1019  if (ch >= 'a' && ch <= 'z') {
1020  ch &= ~0x20;
1021 
1022  } else if (ch == '-') {
1023  ch = '_';
1024  }
1025 
1026  *b->last++ = ch;
1027  }
1028 
1029  b->last = ngx_copy(b->last, header[i].value.data, val_len);
1030 
1032  "fastcgi param: \"%*s: %*s\"",
1033  key_len, b->last - (key_len + val_len),
1034  val_len, b->last - val_len);
1035  next:
1036 
1037  continue;
1038  }
1039  }
1040 
1041 
1042  if (padding) {
1043  ngx_memzero(b->last, padding);
1044  b->last += padding;
1045  }
1046 
1047 
1048  h = (ngx_http_fastcgi_header_t *) b->last;
1049  b->last += sizeof(ngx_http_fastcgi_header_t);
1050 
1051  h->version = 1;
1053  h->request_id_hi = 0;
1054  h->request_id_lo = 1;
1055  h->content_length_hi = 0;
1056  h->content_length_lo = 0;
1057  h->padding_length = 0;
1058  h->reserved = 0;
1059 
1060  h = (ngx_http_fastcgi_header_t *) b->last;
1061  b->last += sizeof(ngx_http_fastcgi_header_t);
1062 
1063  if (flcf->upstream.pass_request_body) {
1064  body = r->upstream->request_bufs;
1065  r->upstream->request_bufs = cl;
1066 
1067 #if (NGX_SUPPRESS_WARN)
1068  file_pos = 0;
1069  pos = NULL;
1070 #endif
1071 
1072  while (body) {
1073 
1074  if (body->buf->in_file) {
1075  file_pos = body->buf->file_pos;
1076 
1077  } else {
1078  pos = body->buf->pos;
1079  }
1080 
1081  next = 0;
1082 
1083  do {
1084  b = ngx_alloc_buf(r->pool);
1085  if (b == NULL) {
1086  return NGX_ERROR;
1087  }
1088 
1089  ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
1090 
1091  if (body->buf->in_file) {
1092  b->file_pos = file_pos;
1093  file_pos += 32 * 1024;
1094 
1095  if (file_pos >= body->buf->file_last) {
1096  file_pos = body->buf->file_last;
1097  next = 1;
1098  }
1099 
1100  b->file_last = file_pos;
1101  len = (ngx_uint_t) (file_pos - b->file_pos);
1102 
1103  } else {
1104  b->pos = pos;
1105  pos += 32 * 1024;
1106 
1107  if (pos >= body->buf->last) {
1108  pos = body->buf->last;
1109  next = 1;
1110  }
1111 
1112  b->last = pos;
1113  len = (ngx_uint_t) (pos - b->pos);
1114  }
1115 
1116  padding = 8 - len % 8;
1117  padding = (padding == 8) ? 0 : padding;
1118 
1119  h->version = 1;
1121  h->request_id_hi = 0;
1122  h->request_id_lo = 1;
1123  h->content_length_hi = (u_char) ((len >> 8) & 0xff);
1124  h->content_length_lo = (u_char) (len & 0xff);
1125  h->padding_length = (u_char) padding;
1126  h->reserved = 0;
1127 
1128  cl->next = ngx_alloc_chain_link(r->pool);
1129  if (cl->next == NULL) {
1130  return NGX_ERROR;
1131  }
1132 
1133  cl = cl->next;
1134  cl->buf = b;
1135 
1136  b = ngx_create_temp_buf(r->pool,
1138  + padding);
1139  if (b == NULL) {
1140  return NGX_ERROR;
1141  }
1142 
1143  if (padding) {
1144  ngx_memzero(b->last, padding);
1145  b->last += padding;
1146  }
1147 
1148  h = (ngx_http_fastcgi_header_t *) b->last;
1149  b->last += sizeof(ngx_http_fastcgi_header_t);
1150 
1151  cl->next = ngx_alloc_chain_link(r->pool);
1152  if (cl->next == NULL) {
1153  return NGX_ERROR;
1154  }
1155 
1156  cl = cl->next;
1157  cl->buf = b;
1158 
1159  } while (!next);
1160 
1161  body = body->next;
1162  }
1163 
1164  } else {
1165  r->upstream->request_bufs = cl;
1166  }
1167 
1168  h->version = 1;
1170  h->request_id_hi = 0;
1171  h->request_id_lo = 1;
1172  h->content_length_hi = 0;
1173  h->content_length_lo = 0;
1174  h->padding_length = 0;
1175  h->reserved = 0;
1176 
1177  cl->next = NULL;
1178 
1179  return NGX_OK;
1180 }
1181 
1182 
1183 static ngx_int_t
1184 ngx_http_fastcgi_reinit_request(ngx_http_request_t *r)
1185 {
1187 
1188  f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
1189 
1190  if (f == NULL) {
1191  return NGX_OK;
1192  }
1193 
1195  f->fastcgi_stdout = 0;
1196  f->large_stderr = 0;
1197 
1198  r->state = 0;
1199 
1200  return NGX_OK;
1201 }
1202 
1203 
1204 static ngx_int_t
1205 ngx_http_fastcgi_process_header(ngx_http_request_t *r)
1206 {
1207  u_char *p, *msg, *start, *last,
1208  *part_start, *part_end;
1209  size_t size;
1210  ngx_str_t *status_line, *pattern;
1211  ngx_int_t rc, status;
1212  ngx_buf_t buf;
1213  ngx_uint_t i;
1214  ngx_table_elt_t *h;
1221 
1222  f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
1223 
1225 
1226  u = r->upstream;
1227 
1228  for ( ;; ) {
1229 
1230  if (f->state < ngx_http_fastcgi_st_data) {
1231 
1232  f->pos = u->buffer.pos;
1233  f->last = u->buffer.last;
1234 
1235  rc = ngx_http_fastcgi_process_record(r, f);
1236 
1237  u->buffer.pos = f->pos;
1238  u->buffer.last = f->last;
1239 
1240  if (rc == NGX_AGAIN) {
1241  return NGX_AGAIN;
1242  }
1243 
1244  if (rc == NGX_ERROR) {
1246  }
1247 
1248  if (f->type != NGX_HTTP_FASTCGI_STDOUT
1249  && f->type != NGX_HTTP_FASTCGI_STDERR)
1250  {
1252  "upstream sent unexpected FastCGI record: %d",
1253  f->type);
1254 
1256  }
1257 
1258  if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
1260  "upstream prematurely closed FastCGI stdout");
1261 
1263  }
1264  }
1265 
1266  if (f->state == ngx_http_fastcgi_st_padding) {
1267 
1268  if (u->buffer.pos + f->padding < u->buffer.last) {
1270  u->buffer.pos += f->padding;
1271 
1272  continue;
1273  }
1274 
1275  if (u->buffer.pos + f->padding == u->buffer.last) {
1277  u->buffer.pos = u->buffer.last;
1278 
1279  return NGX_AGAIN;
1280  }
1281 
1282  f->padding -= u->buffer.last - u->buffer.pos;
1283  u->buffer.pos = u->buffer.last;
1284 
1285  return NGX_AGAIN;
1286  }
1287 
1288 
1289  /* f->state == ngx_http_fastcgi_st_data */
1290 
1291  if (f->type == NGX_HTTP_FASTCGI_STDERR) {
1292 
1293  if (f->length) {
1294  msg = u->buffer.pos;
1295 
1296  if (u->buffer.pos + f->length <= u->buffer.last) {
1297  u->buffer.pos += f->length;
1298  f->length = 0;
1300 
1301  } else {
1302  f->length -= u->buffer.last - u->buffer.pos;
1303  u->buffer.pos = u->buffer.last;
1304  }
1305 
1306  for (p = u->buffer.pos - 1; msg < p; p--) {
1307  if (*p != LF && *p != CR && *p != '.' && *p != ' ') {
1308  break;
1309  }
1310  }
1311 
1312  p++;
1313 
1315  "FastCGI sent in stderr: \"%*s\"", p - msg, msg);
1316 
1317  flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
1318 
1319  if (flcf->catch_stderr) {
1320  pattern = flcf->catch_stderr->elts;
1321 
1322  for (i = 0; i < flcf->catch_stderr->nelts; i++) {
1323  if (ngx_strnstr(msg, (char *) pattern[i].data,
1324  p - msg)
1325  != NULL)
1326  {
1328  }
1329  }
1330  }
1331 
1332  if (u->buffer.pos == u->buffer.last) {
1333 
1334  if (!f->fastcgi_stdout) {
1335 
1336  /*
1337  * the special handling the large number
1338  * of the PHP warnings to not allocate memory
1339  */
1340 
1341 #if (NGX_HTTP_CACHE)
1342  if (r->cache) {
1343  u->buffer.pos = u->buffer.start
1344  + r->cache->header_start;
1345  } else {
1346  u->buffer.pos = u->buffer.start;
1347  }
1348 #else
1349  u->buffer.pos = u->buffer.start;
1350 #endif
1351  u->buffer.last = u->buffer.pos;
1352  f->large_stderr = 1;
1353  }
1354 
1355  return NGX_AGAIN;
1356  }
1357 
1358  } else {
1360  }
1361 
1362  continue;
1363  }
1364 
1365 
1366  /* f->type == NGX_HTTP_FASTCGI_STDOUT */
1367 
1368 #if (NGX_HTTP_CACHE)
1369 
1370  if (f->large_stderr && r->cache) {
1371  u_char *start;
1372  ssize_t len;
1374 
1375  start = u->buffer.start + r->cache->header_start;
1376 
1377  len = u->buffer.pos - start - 2 * sizeof(ngx_http_fastcgi_header_t);
1378 
1379  /*
1380  * A tail of large stderr output before HTTP header is placed
1381  * in a cache file without a FastCGI record header.
1382  * To workaround it we put a dummy FastCGI record header at the
1383  * start of the stderr output or update r->cache_header_start,
1384  * if there is no enough place for the record header.
1385  */
1386 
1387  if (len >= 0) {
1388  fh = (ngx_http_fastcgi_header_t *) start;
1389  fh->version = 1;
1391  fh->request_id_hi = 0;
1392  fh->request_id_lo = 1;
1393  fh->content_length_hi = (u_char) ((len >> 8) & 0xff);
1394  fh->content_length_lo = (u_char) (len & 0xff);
1395  fh->padding_length = 0;
1396  fh->reserved = 0;
1397 
1398  } else {
1399  r->cache->header_start += u->buffer.pos - start
1400  - sizeof(ngx_http_fastcgi_header_t);
1401  }
1402 
1403  f->large_stderr = 0;
1404  }
1405 
1406 #endif
1407 
1408  f->fastcgi_stdout = 1;
1409 
1410  start = u->buffer.pos;
1411 
1412  if (u->buffer.pos + f->length < u->buffer.last) {
1413 
1414  /*
1415  * set u->buffer.last to the end of the FastCGI record data
1416  * for ngx_http_parse_header_line()
1417  */
1418 
1419  last = u->buffer.last;
1420  u->buffer.last = u->buffer.pos + f->length;
1421 
1422  } else {
1423  last = NULL;
1424  }
1425 
1426  for ( ;; ) {
1427 
1428  part_start = u->buffer.pos;
1429  part_end = u->buffer.last;
1430 
1431  rc = ngx_http_parse_header_line(r, &u->buffer, 1);
1432 
1434  "http fastcgi parser: %d", rc);
1435 
1436  if (rc == NGX_AGAIN) {
1437  break;
1438  }
1439 
1440  if (rc == NGX_OK) {
1441 
1442  /* a header line has been parsed successfully */
1443 
1444  h = ngx_list_push(&u->headers_in.headers);
1445  if (h == NULL) {
1446  return NGX_ERROR;
1447  }
1448 
1449  if (f->split_parts && f->split_parts->nelts) {
1450 
1451  part = f->split_parts->elts;
1452  size = u->buffer.pos - part_start;
1453 
1454  for (i = 0; i < f->split_parts->nelts; i++) {
1455  size += part[i].end - part[i].start;
1456  }
1457 
1458  p = ngx_pnalloc(r->pool, size);
1459  if (p == NULL) {
1460  return NGX_ERROR;
1461  }
1462 
1463  buf.pos = p;
1464 
1465  for (i = 0; i < f->split_parts->nelts; i++) {
1466  p = ngx_cpymem(p, part[i].start,
1467  part[i].end - part[i].start);
1468  }
1469 
1470  p = ngx_cpymem(p, part_start, u->buffer.pos - part_start);
1471 
1472  buf.last = p;
1473 
1474  f->split_parts->nelts = 0;
1475 
1476  rc = ngx_http_parse_header_line(r, &buf, 1);
1477 
1479  h->key.data = r->header_name_start;
1480  h->key.data[h->key.len] = '\0';
1481 
1482  h->value.len = r->header_end - r->header_start;
1483  h->value.data = r->header_start;
1484  h->value.data[h->value.len] = '\0';
1485 
1486  h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
1487  if (h->lowcase_key == NULL) {
1488  return NGX_ERROR;
1489  }
1490 
1491  } else {
1492 
1494  h->value.len = r->header_end - r->header_start;
1495 
1496  h->key.data = ngx_pnalloc(r->pool,
1497  h->key.len + 1 + h->value.len + 1
1498  + h->key.len);
1499  if (h->key.data == NULL) {
1500  return NGX_ERROR;
1501  }
1502 
1503  h->value.data = h->key.data + h->key.len + 1;
1504  h->lowcase_key = h->key.data + h->key.len + 1
1505  + h->value.len + 1;
1506 
1508  h->key.data[h->key.len] = '\0';
1509  ngx_memcpy(h->value.data, r->header_start, h->value.len);
1510  h->value.data[h->value.len] = '\0';
1511  }
1512 
1513  h->hash = r->header_hash;
1514 
1515  if (h->key.len == r->lowcase_index) {
1517 
1518  } else {
1519  ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
1520  }
1521 
1522  hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1523  h->lowcase_key, h->key.len);
1524 
1525  if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1526  return NGX_ERROR;
1527  }
1528 
1530  "http fastcgi header: \"%V: %V\"",
1531  &h->key, &h->value);
1532 
1533  if (u->buffer.pos < u->buffer.last) {
1534  continue;
1535  }
1536 
1537  /* the end of the FastCGI record */
1538 
1539  break;
1540  }
1541 
1542  if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1543 
1544  /* a whole header has been parsed successfully */
1545 
1547  "http fastcgi header done");
1548 
1549  if (u->headers_in.status) {
1550  status_line = &u->headers_in.status->value;
1551 
1552  status = ngx_atoi(status_line->data, 3);
1553 
1554  if (status == NGX_ERROR) {
1556  "upstream sent invalid status \"%V\"",
1557  status_line);
1559  }
1560 
1561  u->headers_in.status_n = status;
1562  u->headers_in.status_line = *status_line;
1563 
1564  } else if (u->headers_in.location) {
1565  u->headers_in.status_n = 302;
1567  "302 Moved Temporarily");
1568 
1569  } else {
1570  u->headers_in.status_n = 200;
1571  ngx_str_set(&u->headers_in.status_line, "200 OK");
1572  }
1573 
1574  if (u->state) {
1575  u->state->status = u->headers_in.status_n;
1576  }
1577 
1578  break;
1579  }
1580 
1581  /* there was error while a header line parsing */
1582 
1584  "upstream sent invalid header");
1585 
1587  }
1588 
1589  if (last) {
1590  u->buffer.last = last;
1591  }
1592 
1593  f->length -= u->buffer.pos - start;
1594 
1595  if (f->length == 0) {
1597  }
1598 
1599  if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1600  return NGX_OK;
1601  }
1602 
1603  if (rc == NGX_OK) {
1604  continue;
1605  }
1606 
1607  /* rc == NGX_AGAIN */
1608 
1610  "upstream split a header line in FastCGI records");
1611 
1612  if (f->split_parts == NULL) {
1613  f->split_parts = ngx_array_create(r->pool, 1,
1615  if (f->split_parts == NULL) {
1616  return NGX_ERROR;
1617  }
1618  }
1619 
1620  part = ngx_array_push(f->split_parts);
1621  if (part == NULL) {
1622  return NGX_ERROR;
1623  }
1624 
1625  part->start = part_start;
1626  part->end = part_end;
1627 
1628  if (u->buffer.pos < u->buffer.last) {
1629  continue;
1630  }
1631 
1632  return NGX_AGAIN;
1633  }
1634 }
1635 
1636 
1637 static ngx_int_t
1638 ngx_http_fastcgi_input_filter_init(void *data)
1639 {
1640  ngx_http_request_t *r = data;
1642 
1643  flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
1644 
1645  r->upstream->pipe->length = flcf->keep_conn ?
1646  (off_t) sizeof(ngx_http_fastcgi_header_t) : -1;
1647 
1648  return NGX_OK;
1649 }
1650 
1651 
1652 static ngx_int_t
1653 ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
1654 {
1655  u_char *m, *msg;
1656  ngx_int_t rc;
1657  ngx_buf_t *b, **prev;
1658  ngx_chain_t *cl;
1659  ngx_http_request_t *r;
1662 
1663  if (buf->pos == buf->last) {
1664  return NGX_OK;
1665  }
1666 
1667  r = p->input_ctx;
1668  f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
1669  flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
1670 
1671  b = NULL;
1672  prev = &buf->shadow;
1673 
1674  f->pos = buf->pos;
1675  f->last = buf->last;
1676 
1677  for ( ;; ) {
1678  if (f->state < ngx_http_fastcgi_st_data) {
1679 
1680  rc = ngx_http_fastcgi_process_record(r, f);
1681 
1682  if (rc == NGX_AGAIN) {
1683  break;
1684  }
1685 
1686  if (rc == NGX_ERROR) {
1687  return NGX_ERROR;
1688  }
1689 
1690  if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
1692 
1693  if (!flcf->keep_conn) {
1694  p->upstream_done = 1;
1695  }
1696 
1698  "http fastcgi closed stdout");
1699 
1700  continue;
1701  }
1702 
1703  if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
1704 
1706  "http fastcgi sent end request");
1707 
1708  if (!flcf->keep_conn) {
1709  p->upstream_done = 1;
1710  break;
1711  }
1712 
1713  continue;
1714  }
1715  }
1716 
1717 
1718  if (f->state == ngx_http_fastcgi_st_padding) {
1719 
1720  if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
1721 
1722  if (f->pos + f->padding < f->last) {
1723  p->upstream_done = 1;
1724  break;
1725  }
1726 
1727  if (f->pos + f->padding == f->last) {
1728  p->upstream_done = 1;
1729  r->upstream->keepalive = 1;
1730  break;
1731  }
1732 
1733  f->padding -= f->last - f->pos;
1734 
1735  break;
1736  }
1737 
1738  if (f->pos + f->padding < f->last) {
1740  f->pos += f->padding;
1741 
1742  continue;
1743  }
1744 
1745  if (f->pos + f->padding == f->last) {
1747 
1748  break;
1749  }
1750 
1751  f->padding -= f->last - f->pos;
1752 
1753  break;
1754  }
1755 
1756 
1757  /* f->state == ngx_http_fastcgi_st_data */
1758 
1759  if (f->type == NGX_HTTP_FASTCGI_STDERR) {
1760 
1761  if (f->length) {
1762 
1763  if (f->pos == f->last) {
1764  break;
1765  }
1766 
1767  msg = f->pos;
1768 
1769  if (f->pos + f->length <= f->last) {
1770  f->pos += f->length;
1771  f->length = 0;
1773 
1774  } else {
1775  f->length -= f->last - f->pos;
1776  f->pos = f->last;
1777  }
1778 
1779  for (m = f->pos - 1; msg < m; m--) {
1780  if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
1781  break;
1782  }
1783  }
1784 
1785  ngx_log_error(NGX_LOG_ERR, p->log, 0,
1786  "FastCGI sent in stderr: \"%*s\"",
1787  m + 1 - msg, msg);
1788 
1789  } else {
1791  }
1792 
1793  continue;
1794  }
1795 
1796  if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
1797 
1798  if (f->pos + f->length <= f->last) {
1800  f->pos += f->length;
1801 
1802  continue;
1803  }
1804 
1805  f->length -= f->last - f->pos;
1806 
1807  break;
1808  }
1809 
1810 
1811  /* f->type == NGX_HTTP_FASTCGI_STDOUT */
1812 
1813  if (f->pos == f->last) {
1814  break;
1815  }
1816 
1817  if (p->free) {
1818  cl = p->free;
1819  b = cl->buf;
1820  p->free = cl->next;
1821  ngx_free_chain(p->pool, cl);
1822 
1823  } else {
1824  b = ngx_alloc_buf(p->pool);
1825  if (b == NULL) {
1826  return NGX_ERROR;
1827  }
1828  }
1829 
1830  ngx_memzero(b, sizeof(ngx_buf_t));
1831 
1832  b->pos = f->pos;
1833  b->start = buf->start;
1834  b->end = buf->end;
1835  b->tag = p->tag;
1836  b->temporary = 1;
1837  b->recycled = 1;
1838 
1839  *prev = b;
1840  prev = &b->shadow;
1841 
1842  cl = ngx_alloc_chain_link(p->pool);
1843  if (cl == NULL) {
1844  return NGX_ERROR;
1845  }
1846 
1847  cl->buf = b;
1848  cl->next = NULL;
1849 
1850  if (p->in) {
1851  *p->last_in = cl;
1852  } else {
1853  p->in = cl;
1854  }
1855  p->last_in = &cl->next;
1856 
1857 
1858  /* STUB */ b->num = buf->num;
1859 
1861  "input buf #%d %p", b->num, b->pos);
1862 
1863  if (f->pos + f->length <= f->last) {
1865  f->pos += f->length;
1866  b->last = f->pos;
1867 
1868  continue;
1869  }
1870 
1871  f->length -= f->last - f->pos;
1872 
1873  b->last = f->last;
1874 
1875  break;
1876 
1877  }
1878 
1879  if (flcf->keep_conn) {
1880 
1881  /* set p->length, minimal amount of data we want to see */
1882 
1883  if (f->state < ngx_http_fastcgi_st_data) {
1884  p->length = 1;
1885 
1886  } else if (f->state == ngx_http_fastcgi_st_padding) {
1887  p->length = f->padding;
1888 
1889  } else {
1890  /* ngx_http_fastcgi_st_data */
1891 
1892  p->length = f->length;
1893  }
1894  }
1895 
1896  if (b) {
1897  b->shadow = buf;
1898  b->last_shadow = 1;
1899 
1901  "input buf %p %z", b->pos, b->last - b->pos);
1902 
1903  return NGX_OK;
1904  }
1905 
1906  /* there is no data record in the buf, add it to free chain */
1907 
1908  if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
1909  return NGX_ERROR;
1910  }
1911 
1912  return NGX_OK;
1913 }
1914 
1915 
1916 static ngx_int_t
1917 ngx_http_fastcgi_process_record(ngx_http_request_t *r,
1919 {
1920  u_char ch, *p;
1922 
1923  state = f->state;
1924 
1925  for (p = f->pos; p < f->last; p++) {
1926 
1927  ch = *p;
1928 
1930  "http fastcgi record byte: %02Xd", ch);
1931 
1932  switch (state) {
1933 
1935  if (ch != 1) {
1937  "upstream sent unsupported FastCGI "
1938  "protocol version: %d", ch);
1939  return NGX_ERROR;
1940  }
1941  state = ngx_http_fastcgi_st_type;
1942  break;
1943 
1945  switch (ch) {
1949  f->type = (ngx_uint_t) ch;
1950  break;
1951  default:
1953  "upstream sent invalid FastCGI "
1954  "record type: %d", ch);
1955  return NGX_ERROR;
1956 
1957  }
1959  break;
1960 
1961  /* we support the single request per connection */
1962 
1964  if (ch != 0) {
1966  "upstream sent unexpected FastCGI "
1967  "request id high byte: %d", ch);
1968  return NGX_ERROR;
1969  }
1971  break;
1972 
1974  if (ch != 1) {
1976  "upstream sent unexpected FastCGI "
1977  "request id low byte: %d", ch);
1978  return NGX_ERROR;
1979  }
1981  break;
1982 
1984  f->length = ch << 8;
1986  break;
1987 
1989  f->length |= (size_t) ch;
1991  break;
1992 
1994  f->padding = (size_t) ch;
1996  break;
1997 
1999  state = ngx_http_fastcgi_st_data;
2000 
2002  "http fastcgi record length: %z", f->length);
2003 
2004  f->pos = p + 1;
2005  f->state = state;
2006 
2007  return NGX_OK;
2008 
2009  /* suppress warning */
2012  break;
2013  }
2014  }
2015 
2016  f->state = state;
2017 
2018  return NGX_AGAIN;
2019 }
2020 
2021 
2022 static void
2023 ngx_http_fastcgi_abort_request(ngx_http_request_t *r)
2024 {
2026  "abort http fastcgi request");
2027 
2028  return;
2029 }
2030 
2031 
2032 static void
2033 ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
2034 {
2036  "finalize http fastcgi request");
2037 
2038  return;
2039 }
2040 
2041 
2042 static ngx_int_t
2043 ngx_http_fastcgi_add_variables(ngx_conf_t *cf)
2044 {
2045  ngx_http_variable_t *var, *v;
2046 
2047  for (v = ngx_http_fastcgi_vars; v->name.len; v++) {
2048  var = ngx_http_add_variable(cf, &v->name, v->flags);
2049  if (var == NULL) {
2050  return NGX_ERROR;
2051  }
2052 
2053  var->get_handler = v->get_handler;
2054  var->data = v->data;
2055  }
2056 
2057  return NGX_OK;
2058 }
2059 
2060 
2061 static void *
2062 ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
2063 {
2065 
2066  conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_loc_conf_t));
2067  if (conf == NULL) {
2068  return NULL;
2069  }
2070 
2071  /*
2072  * set by ngx_pcalloc():
2073  *
2074  * conf->upstream.bufs.num = 0;
2075  * conf->upstream.ignore_headers = 0;
2076  * conf->upstream.next_upstream = 0;
2077  * conf->upstream.cache_use_stale = 0;
2078  * conf->upstream.cache_methods = 0;
2079  * conf->upstream.temp_path = NULL;
2080  * conf->upstream.hide_headers_hash = { NULL, 0 };
2081  * conf->upstream.uri = { 0, NULL };
2082  * conf->upstream.location = NULL;
2083  * conf->upstream.store_lengths = NULL;
2084  * conf->upstream.store_values = NULL;
2085  *
2086  * conf->index.len = { 0, NULL };
2087  */
2088 
2089  conf->upstream.store = NGX_CONF_UNSET;
2093 
2095 
2099 
2102 
2106 
2109 
2110 #if (NGX_HTTP_CACHE)
2111  conf->upstream.cache = NGX_CONF_UNSET_PTR;
2112  conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
2113  conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
2114  conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
2115  conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
2116  conf->upstream.cache_lock = NGX_CONF_UNSET;
2117  conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
2118 #endif
2119 
2122 
2124 
2125  /* "fastcgi_cyclic_temp_file" is disabled */
2126  conf->upstream.cyclic_temp_file = 0;
2127 
2129 
2130  conf->keep_conn = NGX_CONF_UNSET;
2131 
2132  ngx_str_set(&conf->upstream.module, "fastcgi");
2133 
2134  return conf;
2135 }
2136 
2137 
2138 static char *
2139 ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
2140 {
2141  ngx_http_fastcgi_loc_conf_t *prev = parent;
2142  ngx_http_fastcgi_loc_conf_t *conf = child;
2143 
2144  size_t size;
2145  ngx_hash_init_t hash;
2147 
2148  if (conf->upstream.store != 0) {
2150  prev->upstream.store, 0);
2151 
2152  if (conf->upstream.store_lengths == NULL) {
2155  }
2156  }
2157 
2159  prev->upstream.store_access, 0600);
2160 
2162  prev->upstream.buffering, 1);
2163 
2165  prev->upstream.ignore_client_abort, 0);
2166 
2168  prev->upstream.local, NULL);
2169 
2171  prev->upstream.connect_timeout, 60000);
2172 
2174  prev->upstream.send_timeout, 60000);
2175 
2177  prev->upstream.read_timeout, 60000);
2178 
2180  prev->upstream.send_lowat, 0);
2181 
2183  prev->upstream.buffer_size,
2184  (size_t) ngx_pagesize);
2185 
2186 
2188  8, ngx_pagesize);
2189 
2190  if (conf->upstream.bufs.num < 2) {
2192  "there must be at least 2 \"fastcgi_buffers\"");
2193  return NGX_CONF_ERROR;
2194  }
2195 
2196 
2197  size = conf->upstream.buffer_size;
2198  if (size < conf->upstream.bufs.size) {
2199  size = conf->upstream.bufs.size;
2200  }
2201 
2202 
2206 
2208  conf->upstream.busy_buffers_size = 2 * size;
2209  } else {
2210  conf->upstream.busy_buffers_size =
2212  }
2213 
2214  if (conf->upstream.busy_buffers_size < size) {
2216  "\"fastcgi_busy_buffers_size\" must be equal to or greater than "
2217  "the maximum of the value of \"fastcgi_buffer_size\" and "
2218  "one of the \"fastcgi_buffers\"");
2219 
2220  return NGX_CONF_ERROR;
2221  }
2222 
2223  if (conf->upstream.busy_buffers_size
2224  > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
2225  {
2227  "\"fastcgi_busy_buffers_size\" must be less than "
2228  "the size of all \"fastcgi_buffers\" minus one buffer");
2229 
2230  return NGX_CONF_ERROR;
2231  }
2232 
2233 
2237 
2239  conf->upstream.temp_file_write_size = 2 * size;
2240  } else {
2243  }
2244 
2245  if (conf->upstream.temp_file_write_size < size) {
2247  "\"fastcgi_temp_file_write_size\" must be equal to or greater "
2248  "than the maximum of the value of \"fastcgi_buffer_size\" and "
2249  "one of the \"fastcgi_buffers\"");
2250 
2251  return NGX_CONF_ERROR;
2252  }
2253 
2254 
2258 
2260  conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
2261  } else {
2264  }
2265 
2266  if (conf->upstream.max_temp_file_size != 0
2267  && conf->upstream.max_temp_file_size < size)
2268  {
2270  "\"fastcgi_max_temp_file_size\" must be equal to zero to disable "
2271  "temporary files usage or must be equal to or greater than "
2272  "the maximum of the value of \"fastcgi_buffer_size\" and "
2273  "one of the \"fastcgi_buffers\"");
2274 
2275  return NGX_CONF_ERROR;
2276  }
2277 
2278 
2280  prev->upstream.ignore_headers,
2282 
2283 
2285  prev->upstream.next_upstream,
2289 
2293  }
2294 
2296  prev->upstream.temp_path,
2297  &ngx_http_fastcgi_temp_path)
2298  != NGX_OK)
2299  {
2300  return NGX_CONF_ERROR;
2301  }
2302 
2303 #if (NGX_HTTP_CACHE)
2304 
2305  ngx_conf_merge_ptr_value(conf->upstream.cache,
2306  prev->upstream.cache, NULL);
2307 
2308  if (conf->upstream.cache && conf->upstream.cache->data == NULL) {
2309  ngx_shm_zone_t *shm_zone;
2310 
2311  shm_zone = conf->upstream.cache;
2312 
2314  "\"fastcgi_cache\" zone \"%V\" is unknown",
2315  &shm_zone->shm.name);
2316 
2317  return NGX_CONF_ERROR;
2318  }
2319 
2320  ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
2321  prev->upstream.cache_min_uses, 1);
2322 
2323  ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
2324  prev->upstream.cache_use_stale,
2327 
2328  if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
2329  conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
2331  }
2332 
2333  if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
2334  conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
2335  }
2336 
2337  if (conf->upstream.cache_methods == 0) {
2338  conf->upstream.cache_methods = prev->upstream.cache_methods;
2339  }
2340 
2341  conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
2342 
2343  ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
2344  prev->upstream.cache_bypass, NULL);
2345 
2346  ngx_conf_merge_ptr_value(conf->upstream.no_cache,
2347  prev->upstream.no_cache, NULL);
2348 
2349  if (conf->upstream.no_cache && conf->upstream.cache_bypass == NULL) {
2350  ngx_log_error(NGX_LOG_WARN, cf->log, 0,
2351  "\"fastcgi_no_cache\" functionality has been changed in 0.8.46, "
2352  "now it should be used together with \"fastcgi_cache_bypass\"");
2353  }
2354 
2355  ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
2356  prev->upstream.cache_valid, NULL);
2357 
2358  if (conf->cache_key.value.data == NULL) {
2359  conf->cache_key = prev->cache_key;
2360  }
2361 
2362  ngx_conf_merge_value(conf->upstream.cache_lock,
2363  prev->upstream.cache_lock, 0);
2364 
2365  ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
2366  prev->upstream.cache_lock_timeout, 5000);
2367 
2368 #endif
2369 
2371  prev->upstream.pass_request_headers, 1);
2373  prev->upstream.pass_request_body, 1);
2374 
2376  prev->upstream.intercept_errors, 0);
2377 
2379 
2380  ngx_conf_merge_value(conf->keep_conn, prev->keep_conn, 0);
2381 
2382 
2383  ngx_conf_merge_str_value(conf->index, prev->index, "");
2384 
2385  hash.max_size = 512;
2387  hash.name = "fastcgi_hide_headers_hash";
2388 
2390  &prev->upstream, ngx_http_fastcgi_hide_headers, &hash)
2391  != NGX_OK)
2392  {
2393  return NGX_CONF_ERROR;
2394  }
2395 
2396  if (conf->upstream.upstream == NULL) {
2397  conf->upstream.upstream = prev->upstream.upstream;
2398  }
2399 
2400  if (conf->fastcgi_lengths == NULL) {
2401  conf->fastcgi_lengths = prev->fastcgi_lengths;
2402  conf->fastcgi_values = prev->fastcgi_values;
2403  }
2404 
2405  if (conf->upstream.upstream || conf->fastcgi_lengths) {
2407  if (clcf->handler == NULL && clcf->lmt_excpt) {
2408  clcf->handler = ngx_http_fastcgi_handler;
2409  }
2410  }
2411 
2412 #if (NGX_PCRE)
2413  if (conf->split_regex == NULL) {
2414  conf->split_regex = prev->split_regex;
2415  conf->split_name = prev->split_name;
2416  }
2417 #endif
2418 
2419  if (ngx_http_fastcgi_merge_params(cf, conf, prev) != NGX_OK) {
2420  return NGX_CONF_ERROR;
2421  }
2422 
2423  return NGX_CONF_OK;
2424 }
2425 
2426 
2427 static ngx_int_t
2428 ngx_http_fastcgi_merge_params(ngx_conf_t *cf,
2430 {
2431  u_char *p;
2432  size_t size;
2433  uintptr_t *code;
2434  ngx_uint_t i, nsrc;
2435  ngx_array_t headers_names;
2436 #if (NGX_HTTP_CACHE)
2437  ngx_array_t params_merged;
2438 #endif
2439  ngx_hash_key_t *hk;
2440  ngx_hash_init_t hash;
2444 
2445  if (conf->params_source == NULL) {
2446  conf->params_source = prev->params_source;
2447 
2448  if (prev->headers_hash.buckets
2449 #if (NGX_HTTP_CACHE)
2450  && ((conf->upstream.cache == NULL)
2451  == (prev->upstream.cache == NULL))
2452 #endif
2453  )
2454  {
2455  conf->flushes = prev->flushes;
2456  conf->params_len = prev->params_len;
2457  conf->params = prev->params;
2458  conf->headers_hash = prev->headers_hash;
2459  conf->header_params = prev->header_params;
2460 
2461  return NGX_OK;
2462  }
2463  }
2464 
2465  if (conf->params_source == NULL
2466 #if (NGX_HTTP_CACHE)
2467  && (conf->upstream.cache == NULL)
2468 #endif
2469  )
2470  {
2471  conf->headers_hash.buckets = (void *) 1;
2472  return NGX_OK;
2473  }
2474 
2475  conf->params_len = ngx_array_create(cf->pool, 64, 1);
2476  if (conf->params_len == NULL) {
2477  return NGX_ERROR;
2478  }
2479 
2480  conf->params = ngx_array_create(cf->pool, 512, 1);
2481  if (conf->params == NULL) {
2482  return NGX_ERROR;
2483  }
2484 
2485  if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
2486  != NGX_OK)
2487  {
2488  return NGX_ERROR;
2489  }
2490 
2491  if (conf->params_source) {
2492  src = conf->params_source->elts;
2493  nsrc = conf->params_source->nelts;
2494 
2495  } else {
2496  src = NULL;
2497  nsrc = 0;
2498  }
2499 
2500 #if (NGX_HTTP_CACHE)
2501 
2502  if (conf->upstream.cache) {
2503  ngx_keyval_t *h;
2505 
2506  if (ngx_array_init(&params_merged, cf->temp_pool, 4,
2507  sizeof(ngx_http_upstream_param_t))
2508  != NGX_OK)
2509  {
2510  return NGX_ERROR;
2511  }
2512 
2513  for (i = 0; i < nsrc; i++) {
2514 
2515  s = ngx_array_push(&params_merged);
2516  if (s == NULL) {
2517  return NGX_ERROR;
2518  }
2519 
2520  *s = src[i];
2521  }
2522 
2523  h = ngx_http_fastcgi_cache_headers;
2524 
2525  while (h->key.len) {
2526 
2527  src = params_merged.elts;
2528  nsrc = params_merged.nelts;
2529 
2530  for (i = 0; i < nsrc; i++) {
2531  if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
2532  goto next;
2533  }
2534  }
2535 
2536  s = ngx_array_push(&params_merged);
2537  if (s == NULL) {
2538  return NGX_ERROR;
2539  }
2540 
2541  s->key = h->key;
2542  s->value = h->value;
2543  s->skip_empty = 0;
2544 
2545  next:
2546 
2547  h++;
2548  }
2549 
2550  src = params_merged.elts;
2551  nsrc = params_merged.nelts;
2552  }
2553 
2554 #endif
2555 
2556  for (i = 0; i < nsrc; i++) {
2557 
2558  if (src[i].key.len > sizeof("HTTP_") - 1
2559  && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
2560  {
2561  hk = ngx_array_push(&headers_names);
2562  if (hk == NULL) {
2563  return NGX_ERROR;
2564  }
2565 
2566  hk->key.len = src[i].key.len - 5;
2567  hk->key.data = src[i].key.data + 5;
2568  hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
2569  hk->value = (void *) 1;
2570 
2571  if (src[i].value.len == 0) {
2572  continue;
2573  }
2574  }
2575 
2576  copy = ngx_array_push_n(conf->params_len,
2577  sizeof(ngx_http_script_copy_code_t));
2578  if (copy == NULL) {
2579  return NGX_ERROR;
2580  }
2581 
2583  copy->len = src[i].key.len;
2584 
2585  copy = ngx_array_push_n(conf->params_len,
2586  sizeof(ngx_http_script_copy_code_t));
2587  if (copy == NULL) {
2588  return NGX_ERROR;
2589  }
2590 
2592  copy->len = src[i].skip_empty;
2593 
2594 
2595  size = (sizeof(ngx_http_script_copy_code_t)
2596  + src[i].key.len + sizeof(uintptr_t) - 1)
2597  & ~(sizeof(uintptr_t) - 1);
2598 
2599  copy = ngx_array_push_n(conf->params, size);
2600  if (copy == NULL) {
2601  return NGX_ERROR;
2602  }
2603 
2605  copy->len = src[i].key.len;
2606 
2607  p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
2608  ngx_memcpy(p, src[i].key.data, src[i].key.len);
2609 
2610 
2611  ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
2612 
2613  sc.cf = cf;
2614  sc.source = &src[i].value;
2615  sc.flushes = &conf->flushes;
2616  sc.lengths = &conf->params_len;
2617  sc.values = &conf->params;
2618 
2619  if (ngx_http_script_compile(&sc) != NGX_OK) {
2620  return NGX_ERROR;
2621  }
2622 
2623  code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
2624  if (code == NULL) {
2625  return NGX_ERROR;
2626  }
2627 
2628  *code = (uintptr_t) NULL;
2629 
2630 
2631  code = ngx_array_push_n(conf->params, sizeof(uintptr_t));
2632  if (code == NULL) {
2633  return NGX_ERROR;
2634  }
2635 
2636  *code = (uintptr_t) NULL;
2637  }
2638 
2639  code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
2640  if (code == NULL) {
2641  return NGX_ERROR;
2642  }
2643 
2644  *code = (uintptr_t) NULL;
2645 
2646  conf->header_params = headers_names.nelts;
2647 
2648  hash.hash = &conf->headers_hash;
2649  hash.key = ngx_hash_key_lc;
2650  hash.max_size = 512;
2651  hash.bucket_size = 64;
2652  hash.name = "fastcgi_params_hash";
2653  hash.pool = cf->pool;
2654  hash.temp_pool = NULL;
2655 
2656  return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
2657 }
2658 
2659 
2660 static ngx_int_t
2661 ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r,
2662  ngx_http_variable_value_t *v, uintptr_t data)
2663 {
2664  u_char *p;
2667 
2668  flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
2669 
2670  f = ngx_http_fastcgi_split(r, flcf);
2671 
2672  if (f == NULL) {
2673  return NGX_ERROR;
2674  }
2675 
2676  if (f->script_name.len == 0
2677  || f->script_name.data[f->script_name.len - 1] != '/')
2678  {
2679  v->len = f->script_name.len;
2680  v->valid = 1;
2681  v->no_cacheable = 0;
2682  v->not_found = 0;
2683  v->data = f->script_name.data;
2684 
2685  return NGX_OK;
2686  }
2687 
2688  v->len = f->script_name.len + flcf->index.len;
2689 
2690  v->data = ngx_pnalloc(r->pool, v->len);
2691  if (v->data == NULL) {
2692  return NGX_ERROR;
2693  }
2694 
2695  p = ngx_copy(v->data, f->script_name.data, f->script_name.len);
2696  ngx_memcpy(p, flcf->index.data, flcf->index.len);
2697 
2698  return NGX_OK;
2699 }
2700 
2701 
2702 static ngx_int_t
2703 ngx_http_fastcgi_path_info_variable(ngx_http_request_t *r,
2704  ngx_http_variable_value_t *v, uintptr_t data)
2705 {
2708 
2709  flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
2710 
2711  f = ngx_http_fastcgi_split(r, flcf);
2712 
2713  if (f == NULL) {
2714  return NGX_ERROR;
2715  }
2716 
2717  v->len = f->path_info.len;
2718  v->valid = 1;
2719  v->no_cacheable = 0;
2720  v->not_found = 0;
2721  v->data = f->path_info.data;
2722 
2723  return NGX_OK;
2724 }
2725 
2726 
2727 static ngx_http_fastcgi_ctx_t *
2728 ngx_http_fastcgi_split(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
2729 {
2731 #if (NGX_PCRE)
2732  ngx_int_t n;
2733  int captures[(1 + 2) * 3];
2734 
2735  f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
2736 
2737  if (f == NULL) {
2738  f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
2739  if (f == NULL) {
2740  return NULL;
2741  }
2742 
2743  ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
2744  }
2745 
2746  if (f->script_name.len) {
2747  return f;
2748  }
2749 
2750  if (flcf->split_regex == NULL) {
2751  f->script_name = r->uri;
2752  return f;
2753  }
2754 
2755  n = ngx_regex_exec(flcf->split_regex, &r->uri, captures, (1 + 2) * 3);
2756 
2757  if (n >= 0) { /* match */
2758  f->script_name.len = captures[3] - captures[2];
2759  f->script_name.data = r->uri.data + captures[2];
2760 
2761  f->path_info.len = captures[5] - captures[4];
2762  f->path_info.data = r->uri.data + captures[4];
2763 
2764  return f;
2765  }
2766 
2767  if (n == NGX_REGEX_NO_MATCHED) {
2768  f->script_name = r->uri;
2769  return f;
2770  }
2771 
2773  ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
2774  n, &r->uri, &flcf->split_name);
2775  return NULL;
2776 
2777 #else
2778 
2779  f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
2780 
2781  if (f == NULL) {
2782  f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
2783  if (f == NULL) {
2784  return NULL;
2785  }
2786 
2787  ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
2788  }
2789 
2790  f->script_name = r->uri;
2791 
2792  return f;
2793 
2794 #endif
2795 }
2796 
2797 
2798 static char *
2799 ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
2800 {
2801  ngx_http_fastcgi_loc_conf_t *flcf = conf;
2802 
2803  ngx_url_t u;
2804  ngx_str_t *value, *url;
2805  ngx_uint_t n;
2808 
2809  if (flcf->upstream.upstream || flcf->fastcgi_lengths) {
2810  return "is duplicate";
2811  }
2812 
2814 
2815  clcf->handler = ngx_http_fastcgi_handler;
2816 
2817  if (clcf->name.data[clcf->name.len - 1] == '/') {
2818  clcf->auto_redirect = 1;
2819  }
2820 
2821  value = cf->args->elts;
2822 
2823  url = &value[1];
2824 
2826 
2827  if (n) {
2828 
2829  ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
2830 
2831  sc.cf = cf;
2832  sc.source = url;
2833  sc.lengths = &flcf->fastcgi_lengths;
2834  sc.values = &flcf->fastcgi_values;
2835  sc.variables = n;
2836  sc.complete_lengths = 1;
2837  sc.complete_values = 1;
2838 
2839  if (ngx_http_script_compile(&sc) != NGX_OK) {
2840  return NGX_CONF_ERROR;
2841  }
2842 
2843  return NGX_CONF_OK;
2844  }
2845 
2846  ngx_memzero(&u, sizeof(ngx_url_t));
2847 
2848  u.url = value[1];
2849  u.no_resolve = 1;
2850 
2851  flcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
2852  if (flcf->upstream.upstream == NULL) {
2853  return NGX_CONF_ERROR;
2854  }
2855 
2856  return NGX_CONF_OK;
2857 }
2858 
2859 
2860 static char *
2861 ngx_http_fastcgi_split_path_info(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
2862 {
2863 #if (NGX_PCRE)
2864  ngx_http_fastcgi_loc_conf_t *flcf = conf;
2865 
2866  ngx_str_t *value;
2868  u_char errstr[NGX_MAX_CONF_ERRSTR];
2869 
2870  value = cf->args->elts;
2871 
2872  flcf->split_name = value[1];
2873 
2874  ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
2875 
2876  rc.pattern = value[1];
2877  rc.pool = cf->pool;
2879  rc.err.data = errstr;
2880 
2881  if (ngx_regex_compile(&rc) != NGX_OK) {
2882  ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
2883  return NGX_CONF_ERROR;
2884  }
2885 
2886  if (rc.captures != 2) {
2888  "pattern \"%V\" must have 2 captures", &value[1]);
2889  return NGX_CONF_ERROR;
2890  }
2891 
2892  flcf->split_regex = rc.regex;
2893 
2894  return NGX_CONF_OK;
2895 
2896 #else
2897 
2899  "\"%V\" requires PCRE library", &cmd->name);
2900  return NGX_CONF_ERROR;
2901 
2902 #endif
2903 }
2904 
2905 
2906 static char *
2907 ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
2908 {
2909  ngx_http_fastcgi_loc_conf_t *flcf = conf;
2910 
2911  ngx_str_t *value;
2913 
2914  if (flcf->upstream.store != NGX_CONF_UNSET
2915  || flcf->upstream.store_lengths)
2916  {
2917  return "is duplicate";
2918  }
2919 
2920  value = cf->args->elts;
2921 
2922  if (ngx_strcmp(value[1].data, "off") == 0) {
2923  flcf->upstream.store = 0;
2924  return NGX_CONF_OK;
2925  }
2926 
2927 #if (NGX_HTTP_CACHE)
2928 
2929  if (flcf->upstream.cache != NGX_CONF_UNSET_PTR
2930  && flcf->upstream.cache != NULL)
2931  {
2932  return "is incompatible with \"fastcgi_cache\"";
2933  }
2934 
2935 #endif
2936 
2937  if (ngx_strcmp(value[1].data, "on") == 0) {
2938  flcf->upstream.store = 1;
2939  return NGX_CONF_OK;
2940  }
2941 
2942  /* include the terminating '\0' into script */
2943  value[1].len++;
2944 
2945  ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
2946 
2947  sc.cf = cf;
2948  sc.source = &value[1];
2949  sc.lengths = &flcf->upstream.store_lengths;
2950  sc.values = &flcf->upstream.store_values;
2952  sc.complete_lengths = 1;
2953  sc.complete_values = 1;
2954 
2955  if (ngx_http_script_compile(&sc) != NGX_OK) {
2956  return NGX_CONF_ERROR;
2957  }
2958 
2959  return NGX_CONF_OK;
2960 }
2961 
2962 
2963 #if (NGX_HTTP_CACHE)
2964 
2965 static char *
2966 ngx_http_fastcgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
2967 {
2968  ngx_http_fastcgi_loc_conf_t *flcf = conf;
2969 
2970  ngx_str_t *value;
2971 
2972  value = cf->args->elts;
2973 
2974  if (flcf->upstream.cache != NGX_CONF_UNSET_PTR) {
2975  return "is duplicate";
2976  }
2977 
2978  if (ngx_strcmp(value[1].data, "off") == 0) {
2979  flcf->upstream.cache = NULL;
2980  return NGX_CONF_OK;
2981  }
2982 
2983  if (flcf->upstream.store > 0 || flcf->upstream.store_lengths) {
2984  return "is incompatible with \"fastcgi_store\"";
2985  }
2986 
2987  flcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
2988  &ngx_http_fastcgi_module);
2989  if (flcf->upstream.cache == NULL) {
2990  return NGX_CONF_ERROR;
2991  }
2992 
2993  return NGX_CONF_OK;
2994 }
2995 
2996 
2997 static char *
2998 ngx_http_fastcgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
2999 {
3000  ngx_http_fastcgi_loc_conf_t *flcf = conf;
3001 
3002  ngx_str_t *value;
3004 
3005  value = cf->args->elts;
3006 
3007  if (flcf->cache_key.value.data) {
3008  return "is duplicate";
3009  }
3010 
3012 
3013  ccv.cf = cf;
3014  ccv.value = &value[1];
3015  ccv.complex_value = &flcf->cache_key;
3016 
3017  if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3018  return NGX_CONF_ERROR;
3019  }
3020 
3021  return NGX_CONF_OK;
3022 }
3023 
3024 #endif
3025 
3026 
3027 static char *
3028 ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data)
3029 {
3030 #if (NGX_FREEBSD)
3031  ssize_t *np = data;
3032 
3033  if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
3035  "\"fastcgi_send_lowat\" must be less than %d "
3036  "(sysctl net.inet.tcp.sendspace)",
3038 
3039  return NGX_CONF_ERROR;
3040  }
3041 
3042 #elif !(NGX_HAVE_SO_SNDLOWAT)
3043  ssize_t *np = data;
3044 
3046  "\"fastcgi_send_lowat\" is not supported, ignored");
3047 
3048  *np = 0;
3049 
3050 #endif
3051 
3052  return NGX_CONF_OK;
3053 }