Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_http_uwsgi_module.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Unbit S.a.s. 2009-2010
4  * Copyright (C) 2008 Manlio Perillo (manlio.perillo@gmail.com)
5  * Copyright (C) Igor Sysoev
6  * Copyright (C) Nginx, Inc.
7  */
8 
9 
10 #include <ngx_config.h>
11 #include <ngx_core.h>
12 #include <ngx_http.h>
13 
14 
15 typedef struct {
17 
22 
25 
28 
29 #if (NGX_HTTP_CACHE)
30  ngx_http_complex_value_t cache_key;
31 #endif
32 
34 
38 
39 
40 static ngx_int_t ngx_http_uwsgi_eval(ngx_http_request_t *r,
42 static ngx_int_t ngx_http_uwsgi_create_request(ngx_http_request_t *r);
43 static ngx_int_t ngx_http_uwsgi_reinit_request(ngx_http_request_t *r);
44 static ngx_int_t ngx_http_uwsgi_process_status_line(ngx_http_request_t *r);
45 static ngx_int_t ngx_http_uwsgi_process_header(ngx_http_request_t *r);
46 static void ngx_http_uwsgi_abort_request(ngx_http_request_t *r);
47 static void ngx_http_uwsgi_finalize_request(ngx_http_request_t *r,
48  ngx_int_t rc);
49 
50 static void *ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf);
51 static char *ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent,
52  void *child);
53 static ngx_int_t ngx_http_uwsgi_merge_params(ngx_conf_t *cf,
55 
56 static char *ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_command_t *cmd,
57  void *conf);
58 static char *ngx_http_uwsgi_store(ngx_conf_t *cf, ngx_command_t *cmd,
59  void *conf);
60 
61 #if (NGX_HTTP_CACHE)
62 static ngx_int_t ngx_http_uwsgi_create_key(ngx_http_request_t *r);
63 static char *ngx_http_uwsgi_cache(ngx_conf_t *cf, ngx_command_t *cmd,
64  void *conf);
65 static char *ngx_http_uwsgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
66  void *conf);
67 #endif
68 
69 
70 static ngx_conf_num_bounds_t ngx_http_uwsgi_modifier_bounds = {
72 };
73 
74 
75 static ngx_conf_bitmask_t ngx_http_uwsgi_next_upstream_masks[] = {
78  { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
84  { ngx_null_string, 0 }
85 };
86 
87 
89 
90 
91 static ngx_command_t ngx_http_uwsgi_commands[] = {
92 
93  { ngx_string("uwsgi_pass"),
95  ngx_http_uwsgi_pass,
97  0,
98  NULL },
99 
100  { ngx_string("uwsgi_modifier1"),
104  offsetof(ngx_http_uwsgi_loc_conf_t, modifier1),
105  &ngx_http_uwsgi_modifier_bounds },
106 
107  { ngx_string("uwsgi_modifier2"),
111  offsetof(ngx_http_uwsgi_loc_conf_t, modifier2),
112  &ngx_http_uwsgi_modifier_bounds },
113 
114  { ngx_string("uwsgi_store"),
116  ngx_http_uwsgi_store,
118  0,
119  NULL },
120 
121  { ngx_string("uwsgi_store_access"),
125  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.store_access),
126  NULL },
127 
128  { ngx_string("uwsgi_buffering"),
132  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.buffering),
133  NULL },
134 
135  { ngx_string("uwsgi_ignore_client_abort"),
139  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ignore_client_abort),
140  NULL },
141 
142  { ngx_string("uwsgi_bind"),
146  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.local),
147  NULL },
148 
149  { ngx_string("uwsgi_connect_timeout"),
153  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.connect_timeout),
154  NULL },
155 
156  { ngx_string("uwsgi_send_timeout"),
160  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.send_timeout),
161  NULL },
162 
163  { ngx_string("uwsgi_buffer_size"),
167  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.buffer_size),
168  NULL },
169 
170  { ngx_string("uwsgi_pass_request_headers"),
174  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.pass_request_headers),
175  NULL },
176 
177  { ngx_string("uwsgi_pass_request_body"),
181  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.pass_request_body),
182  NULL },
183 
184  { ngx_string("uwsgi_intercept_errors"),
188  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.intercept_errors),
189  NULL },
190 
191  { ngx_string("uwsgi_read_timeout"),
195  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.read_timeout),
196  NULL },
197 
198  { ngx_string("uwsgi_buffers"),
202  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.bufs),
203  NULL },
204 
205  { ngx_string("uwsgi_busy_buffers_size"),
209  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.busy_buffers_size_conf),
210  NULL },
211 
212 #if (NGX_HTTP_CACHE)
213 
214  { ngx_string("uwsgi_cache"),
216  ngx_http_uwsgi_cache,
218  0,
219  NULL },
220 
221  { ngx_string("uwsgi_cache_key"),
223  ngx_http_uwsgi_cache_key,
225  0,
226  NULL },
227 
228  { ngx_string("uwsgi_cache_path"),
231  0,
232  0,
233  &ngx_http_uwsgi_module },
234 
235  { ngx_string("uwsgi_cache_bypass"),
239  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_bypass),
240  NULL },
241 
242  { ngx_string("uwsgi_no_cache"),
246  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.no_cache),
247  NULL },
248 
249  { ngx_string("uwsgi_cache_valid"),
253  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_valid),
254  NULL },
255 
256  { ngx_string("uwsgi_cache_min_uses"),
260  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_min_uses),
261  NULL },
262 
263  { ngx_string("uwsgi_cache_use_stale"),
267  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_use_stale),
268  &ngx_http_uwsgi_next_upstream_masks },
269 
270  { ngx_string("uwsgi_cache_methods"),
274  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_methods),
276 
277  { ngx_string("uwsgi_cache_lock"),
281  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_lock),
282  NULL },
283 
284  { ngx_string("uwsgi_cache_lock_timeout"),
288  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_lock_timeout),
289  NULL },
290 
291 #endif
292 
293  { ngx_string("uwsgi_temp_path"),
297  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.temp_path),
298  NULL },
299 
300  { ngx_string("uwsgi_max_temp_file_size"),
304  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.max_temp_file_size_conf),
305  NULL },
306 
307  { ngx_string("uwsgi_temp_file_write_size"),
311  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.temp_file_write_size_conf),
312  NULL },
313 
314  { ngx_string("uwsgi_next_upstream"),
318  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.next_upstream),
319  &ngx_http_uwsgi_next_upstream_masks },
320 
321  { ngx_string("uwsgi_param"),
325  offsetof(ngx_http_uwsgi_loc_conf_t, params_source),
326  NULL },
327 
328  { ngx_string("uwsgi_string"),
332  offsetof(ngx_http_uwsgi_loc_conf_t, uwsgi_string),
333  NULL },
334 
335  { ngx_string("uwsgi_pass_header"),
339  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.pass_headers),
340  NULL },
341 
342  { ngx_string("uwsgi_hide_header"),
346  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.hide_headers),
347  NULL },
348 
349  { ngx_string("uwsgi_ignore_headers"),
353  offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ignore_headers),
355 
357 };
358 
359 
360 static ngx_http_module_t ngx_http_uwsgi_module_ctx = {
361  NULL, /* preconfiguration */
362  NULL, /* postconfiguration */
363 
364  NULL, /* create main configuration */
365  NULL, /* init main configuration */
366 
367  NULL, /* create server configuration */
368  NULL, /* merge server configuration */
369 
370  ngx_http_uwsgi_create_loc_conf, /* create location configuration */
371  ngx_http_uwsgi_merge_loc_conf /* merge location configuration */
372 };
373 
374 
375 ngx_module_t ngx_http_uwsgi_module = {
377  &ngx_http_uwsgi_module_ctx, /* module context */
378  ngx_http_uwsgi_commands, /* module directives */
379  NGX_HTTP_MODULE, /* module type */
380  NULL, /* init master */
381  NULL, /* init module */
382  NULL, /* init process */
383  NULL, /* init thread */
384  NULL, /* exit thread */
385  NULL, /* exit process */
386  NULL, /* exit master */
388 };
389 
390 
391 static ngx_str_t ngx_http_uwsgi_hide_headers[] = {
392  ngx_string("X-Accel-Expires"),
393  ngx_string("X-Accel-Redirect"),
394  ngx_string("X-Accel-Limit-Rate"),
395  ngx_string("X-Accel-Buffering"),
396  ngx_string("X-Accel-Charset"),
398 };
399 
400 
401 #if (NGX_HTTP_CACHE)
402 
403 static ngx_keyval_t ngx_http_uwsgi_cache_headers[] = {
404  { ngx_string("HTTP_IF_MODIFIED_SINCE"), ngx_string("") },
405  { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
406  { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("") },
407  { ngx_string("HTTP_IF_MATCH"), ngx_string("") },
408  { ngx_string("HTTP_RANGE"), ngx_string("") },
409  { ngx_string("HTTP_IF_RANGE"), ngx_string("") },
411 };
412 
413 #endif
414 
415 
416 static ngx_path_init_t ngx_http_uwsgi_temp_path = {
418 };
419 
420 
421 static ngx_int_t
422 ngx_http_uwsgi_handler(ngx_http_request_t *r)
423 {
424  ngx_int_t rc;
425  ngx_http_status_t *status;
428 
429  if (r->subrequest_in_memory) {
431  "ngx_http_uwsgi_module does not support "
432  "subrequests in memory");
434  }
435 
436  if (ngx_http_upstream_create(r) != NGX_OK) {
438  }
439 
440  status = ngx_pcalloc(r->pool, sizeof(ngx_http_status_t));
441  if (status == NULL) {
443  }
444 
445  ngx_http_set_ctx(r, status, ngx_http_uwsgi_module);
446 
447  uwcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module);
448 
449  if (uwcf->uwsgi_lengths) {
450  if (ngx_http_uwsgi_eval(r, uwcf) != NGX_OK) {
452  }
453  }
454 
455  u = r->upstream;
456 
457  ngx_str_set(&u->schema, "uwsgi://");
458  u->output.tag = (ngx_buf_tag_t) &ngx_http_uwsgi_module;
459 
460  u->conf = &uwcf->upstream;
461 
462 #if (NGX_HTTP_CACHE)
463  u->create_key = ngx_http_uwsgi_create_key;
464 #endif
465  u->create_request = ngx_http_uwsgi_create_request;
466  u->reinit_request = ngx_http_uwsgi_reinit_request;
467  u->process_header = ngx_http_uwsgi_process_status_line;
468  u->abort_request = ngx_http_uwsgi_abort_request;
469  u->finalize_request = ngx_http_uwsgi_finalize_request;
470  r->state = 0;
471 
472  u->buffering = uwcf->upstream.buffering;
473 
474  u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
475  if (u->pipe == NULL) {
477  }
478 
480  u->pipe->input_ctx = r;
481 
483 
484  if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
485  return rc;
486  }
487 
488  return NGX_DONE;
489 }
490 
491 
492 static ngx_int_t
493 ngx_http_uwsgi_eval(ngx_http_request_t *r, ngx_http_uwsgi_loc_conf_t * uwcf)
494 {
495  ngx_url_t url;
497 
498  ngx_memzero(&url, sizeof(ngx_url_t));
499 
500  if (ngx_http_script_run(r, &url.url, uwcf->uwsgi_lengths->elts, 0,
501  uwcf->uwsgi_values->elts)
502  == NULL)
503  {
504  return NGX_ERROR;
505  }
506 
507  url.no_resolve = 1;
508 
509  if (ngx_parse_url(r->pool, &url) != NGX_OK) {
510  if (url.err) {
512  "%s in upstream \"%V\"", url.err, &url.url);
513  }
514 
515  return NGX_ERROR;
516  }
517 
518  u = r->upstream;
519 
521  if (u->resolved == NULL) {
522  return NGX_ERROR;
523  }
524 
525  if (url.addrs && url.addrs[0].sockaddr) {
526  u->resolved->sockaddr = url.addrs[0].sockaddr;
527  u->resolved->socklen = url.addrs[0].socklen;
528  u->resolved->naddrs = 1;
529  u->resolved->host = url.addrs[0].name;
530 
531  } else {
532  u->resolved->host = url.host;
533  u->resolved->port = url.port;
534  u->resolved->no_port = url.no_port;
535  }
536 
537  return NGX_OK;
538 }
539 
540 
541 #if (NGX_HTTP_CACHE)
542 
543 static ngx_int_t
544 ngx_http_uwsgi_create_key(ngx_http_request_t *r)
545 {
546  ngx_str_t *key;
548 
549  key = ngx_array_push(&r->cache->keys);
550  if (key == NULL) {
551  return NGX_ERROR;
552  }
553 
554  uwcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module);
555 
556  if (ngx_http_complex_value(r, &uwcf->cache_key, key) != NGX_OK) {
557  return NGX_ERROR;
558  }
559 
560  return NGX_OK;
561 }
562 
563 #endif
564 
565 
566 static ngx_int_t
567 ngx_http_uwsgi_create_request(ngx_http_request_t *r)
568 {
569  u_char ch, *lowcase_key;
570  size_t key_len, val_len, len, allocated;
571  ngx_uint_t i, n, hash, skip_empty, header_params;
572  ngx_buf_t *b;
573  ngx_chain_t *cl, *body;
574  ngx_list_part_t *part;
575  ngx_table_elt_t *header, **ignored;
580 
581  len = 0;
582  header_params = 0;
583  ignored = NULL;
584 
585  uwcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module);
586 
587  if (uwcf->params_len) {
589 
591  le.flushed = 1;
592 
593  le.ip = uwcf->params_len->elts;
594  le.request = r;
595 
596  while (*(uintptr_t *) le.ip) {
597 
598  lcode = *(ngx_http_script_len_code_pt *) le.ip;
599  key_len = lcode(&le);
600 
601  lcode = *(ngx_http_script_len_code_pt *) le.ip;
602  skip_empty = lcode(&le);
603 
604  for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode (&le)) {
605  lcode = *(ngx_http_script_len_code_pt *) le.ip;
606  }
607  le.ip += sizeof(uintptr_t);
608 
609  if (skip_empty && val_len == 0) {
610  continue;
611  }
612 
613  len += 2 + key_len + 2 + val_len;
614  }
615  }
616 
617  if (uwcf->upstream.pass_request_headers) {
618 
619  allocated = 0;
620  lowcase_key = NULL;
621 
622  if (uwcf->header_params) {
623  n = 0;
624  part = &r->headers_in.headers.part;
625 
626  while (part) {
627  n += part->nelts;
628  part = part->next;
629  }
630 
631  ignored = ngx_palloc(r->pool, n * sizeof(void *));
632  if (ignored == NULL) {
633  return NGX_ERROR;
634  }
635  }
636 
637  part = &r->headers_in.headers.part;
638  header = part->elts;
639 
640  for (i = 0; /* void */ ; i++) {
641 
642  if (i >= part->nelts) {
643  if (part->next == NULL) {
644  break;
645  }
646 
647  part = part->next;
648  header = part->elts;
649  i = 0;
650  }
651 
652  if (uwcf->header_params) {
653  if (allocated < header[i].key.len) {
654  allocated = header[i].key.len + 16;
655  lowcase_key = ngx_pnalloc(r->pool, allocated);
656  if (lowcase_key == NULL) {
657  return NGX_ERROR;
658  }
659  }
660 
661  hash = 0;
662 
663  for (n = 0; n < header[i].key.len; n++) {
664  ch = header[i].key.data[n];
665 
666  if (ch >= 'A' && ch <= 'Z') {
667  ch |= 0x20;
668 
669  } else if (ch == '-') {
670  ch = '_';
671  }
672 
673  hash = ngx_hash(hash, ch);
674  lowcase_key[n] = ch;
675  }
676 
677  if (ngx_hash_find(&uwcf->headers_hash, hash, lowcase_key, n)) {
678  ignored[header_params++] = &header[i];
679  continue;
680  }
681  }
682 
683  len += 2 + sizeof("HTTP_") - 1 + header[i].key.len
684  + 2 + header[i].value.len;
685  }
686  }
687 
688  len += uwcf->uwsgi_string.len;
689 
690 #if 0
691  /* allow custom uwsgi packet */
692  if (len > 0 && len < 2) {
694  "uwsgi request is too little: %uz", len);
695  return NGX_ERROR;
696  }
697 #endif
698 
699  b = ngx_create_temp_buf(r->pool, len + 4);
700  if (b == NULL) {
701  return NGX_ERROR;
702  }
703 
704  cl = ngx_alloc_chain_link(r->pool);
705  if (cl == NULL) {
706  return NGX_ERROR;
707  }
708 
709  cl->buf = b;
710 
711  *b->last++ = (u_char) uwcf->modifier1;
712  *b->last++ = (u_char) (len & 0xff);
713  *b->last++ = (u_char) ((len >> 8) & 0xff);
714  *b->last++ = (u_char) uwcf->modifier2;
715 
716  if (uwcf->params_len) {
718 
719  e.ip = uwcf->params->elts;
720  e.pos = b->last;
721  e.request = r;
722  e.flushed = 1;
723 
724  le.ip = uwcf->params_len->elts;
725 
726  while (*(uintptr_t *) le.ip) {
727 
728  lcode = *(ngx_http_script_len_code_pt *) le.ip;
729  key_len = (u_char) lcode (&le);
730 
731  lcode = *(ngx_http_script_len_code_pt *) le.ip;
732  skip_empty = lcode(&le);
733 
734  for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
735  lcode = *(ngx_http_script_len_code_pt *) le.ip;
736  }
737  le.ip += sizeof(uintptr_t);
738 
739  if (skip_empty && val_len == 0) {
740  e.skip = 1;
741 
742  while (*(uintptr_t *) e.ip) {
743  code = *(ngx_http_script_code_pt *) e.ip;
744  code((ngx_http_script_engine_t *) &e);
745  }
746  e.ip += sizeof(uintptr_t);
747 
748  e.skip = 0;
749 
750  continue;
751  }
752 
753  *e.pos++ = (u_char) (key_len & 0xff);
754  *e.pos++ = (u_char) ((key_len >> 8) & 0xff);
755 
756  code = *(ngx_http_script_code_pt *) e.ip;
757  code((ngx_http_script_engine_t *) & e);
758 
759  *e.pos++ = (u_char) (val_len & 0xff);
760  *e.pos++ = (u_char) ((val_len >> 8) & 0xff);
761 
762  while (*(uintptr_t *) e.ip) {
763  code = *(ngx_http_script_code_pt *) e.ip;
764  code((ngx_http_script_engine_t *) & e);
765  }
766 
767  e.ip += sizeof(uintptr_t);
768 
770  "uwsgi param: \"%*s: %*s\"",
771  key_len, e.pos - (key_len + 2 + val_len),
772  val_len, e.pos - val_len);
773  }
774 
775  b->last = e.pos;
776  }
777 
778  if (uwcf->upstream.pass_request_headers) {
779 
780  part = &r->headers_in.headers.part;
781  header = part->elts;
782 
783  for (i = 0; /* void */ ; i++) {
784 
785  if (i >= part->nelts) {
786  if (part->next == NULL) {
787  break;
788  }
789 
790  part = part->next;
791  header = part->elts;
792  i = 0;
793  }
794 
795  for (n = 0; n < header_params; n++) {
796  if (&header[i] == ignored[n]) {
797  goto next;
798  }
799  }
800 
801  key_len = sizeof("HTTP_") - 1 + header[i].key.len;
802  *b->last++ = (u_char) (key_len & 0xff);
803  *b->last++ = (u_char) ((key_len >> 8) & 0xff);
804 
805  b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1);
806  for (n = 0; n < header[i].key.len; n++) {
807  ch = header[i].key.data[n];
808 
809  if (ch >= 'a' && ch <= 'z') {
810  ch &= ~0x20;
811 
812  } else if (ch == '-') {
813  ch = '_';
814  }
815 
816  *b->last++ = ch;
817  }
818 
819  val_len = header[i].value.len;
820  *b->last++ = (u_char) (val_len & 0xff);
821  *b->last++ = (u_char) ((val_len >> 8) & 0xff);
822  b->last = ngx_copy(b->last, header[i].value.data, val_len);
823 
825  "uwsgi param: \"%*s: %*s\"",
826  key_len, b->last - (key_len + 2 + val_len),
827  val_len, b->last - val_len);
828  next:
829 
830  continue;
831  }
832  }
833 
834  b->last = ngx_copy(b->last, uwcf->uwsgi_string.data,
835  uwcf->uwsgi_string.len);
836 
837  if (uwcf->upstream.pass_request_body) {
838  body = r->upstream->request_bufs;
839  r->upstream->request_bufs = cl;
840 
841  while (body) {
842  b = ngx_alloc_buf(r->pool);
843  if (b == NULL) {
844  return NGX_ERROR;
845  }
846 
847  ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
848 
849  cl->next = ngx_alloc_chain_link(r->pool);
850  if (cl->next == NULL) {
851  return NGX_ERROR;
852  }
853 
854  cl = cl->next;
855  cl->buf = b;
856 
857  body = body->next;
858  }
859 
860  } else {
861  r->upstream->request_bufs = cl;
862  }
863 
864  cl->next = NULL;
865 
866  return NGX_OK;
867 }
868 
869 
870 static ngx_int_t
871 ngx_http_uwsgi_reinit_request(ngx_http_request_t *r)
872 {
873  ngx_http_status_t *status;
874 
875  status = ngx_http_get_module_ctx(r, ngx_http_uwsgi_module);
876 
877  if (status == NULL) {
878  return NGX_OK;
879  }
880 
881  status->code = 0;
882  status->count = 0;
883  status->start = NULL;
884  status->end = NULL;
885 
886  r->upstream->process_header = ngx_http_uwsgi_process_status_line;
887  r->state = 0;
888 
889  return NGX_OK;
890 }
891 
892 
893 static ngx_int_t
894 ngx_http_uwsgi_process_status_line(ngx_http_request_t *r)
895 {
896  size_t len;
897  ngx_int_t rc;
898  ngx_http_status_t *status;
900 
901  status = ngx_http_get_module_ctx(r, ngx_http_uwsgi_module);
902 
903  if (status == NULL) {
904  return NGX_ERROR;
905  }
906 
907  u = r->upstream;
908 
909  rc = ngx_http_parse_status_line(r, &u->buffer, status);
910 
911  if (rc == NGX_AGAIN) {
912  return rc;
913  }
914 
915  if (rc == NGX_ERROR) {
916  u->process_header = ngx_http_uwsgi_process_header;
917  return ngx_http_uwsgi_process_header(r);
918  }
919 
920  if (u->state) {
921  u->state->status = status->code;
922  }
923 
924  u->headers_in.status_n = status->code;
925 
926  len = status->end - status->start;
927  u->headers_in.status_line.len = len;
928 
930  if (u->headers_in.status_line.data == NULL) {
931  return NGX_ERROR;
932  }
933 
934  ngx_memcpy(u->headers_in.status_line.data, status->start, len);
935 
937  "http uwsgi status %ui \"%V\"",
939 
940  u->process_header = ngx_http_uwsgi_process_header;
941 
942  return ngx_http_uwsgi_process_header(r);
943 }
944 
945 
946 static ngx_int_t
947 ngx_http_uwsgi_process_header(ngx_http_request_t *r)
948 {
949  ngx_str_t *status_line;
950  ngx_int_t rc, status;
951  ngx_table_elt_t *h;
955 
957 
958  for ( ;; ) {
959 
960  rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
961 
962  if (rc == NGX_OK) {
963 
964  /* a header line has been parsed successfully */
965 
967  if (h == NULL) {
968  return NGX_ERROR;
969  }
970 
971  h->hash = r->header_hash;
972 
974  h->value.len = r->header_end - r->header_start;
975 
976  h->key.data = ngx_pnalloc(r->pool,
977  h->key.len + 1 + h->value.len + 1
978  + h->key.len);
979  if (h->key.data == NULL) {
980  return NGX_ERROR;
981  }
982 
983  h->value.data = h->key.data + h->key.len + 1;
984  h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;
985 
987  h->key.data[h->key.len] = '\0';
989  h->value.data[h->value.len] = '\0';
990 
991  if (h->key.len == r->lowcase_index) {
993 
994  } else {
995  ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
996  }
997 
998  hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
999  h->lowcase_key, h->key.len);
1000 
1001  if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1002  return NGX_ERROR;
1003  }
1004 
1006  "http uwsgi header: \"%V: %V\"", &h->key, &h->value);
1007 
1008  continue;
1009  }
1010 
1011  if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1012 
1013  /* a whole header has been parsed successfully */
1014 
1016  "http uwsgi header done");
1017 
1018  u = r->upstream;
1019 
1020  if (u->headers_in.status_n) {
1021  goto done;
1022  }
1023 
1024  if (u->headers_in.status) {
1025  status_line = &u->headers_in.status->value;
1026 
1027  status = ngx_atoi(status_line->data, 3);
1028  if (status == NGX_ERROR) {
1030  "upstream sent invalid status \"%V\"",
1031  status_line);
1033  }
1034 
1035  u->headers_in.status_n = status;
1036  u->headers_in.status_line = *status_line;
1037 
1038  } else if (u->headers_in.location) {
1039  u->headers_in.status_n = 302;
1041  "302 Moved Temporarily");
1042 
1043  } else {
1044  u->headers_in.status_n = 200;
1045  ngx_str_set(&u->headers_in.status_line, "200 OK");
1046  }
1047 
1048  if (u->state) {
1049  u->state->status = u->headers_in.status_n;
1050  }
1051 
1052  done:
1053 
1055  && r->headers_in.upgrade)
1056  {
1057  u->upgrade = 1;
1058  }
1059 
1060  return NGX_OK;
1061  }
1062 
1063  if (rc == NGX_AGAIN) {
1064  return NGX_AGAIN;
1065  }
1066 
1067  /* there was error while a header line parsing */
1068 
1070  "upstream sent invalid header");
1071 
1073  }
1074 }
1075 
1076 
1077 static void
1078 ngx_http_uwsgi_abort_request(ngx_http_request_t *r)
1079 {
1081  "abort http uwsgi request");
1082 
1083  return;
1084 }
1085 
1086 
1087 static void
1088 ngx_http_uwsgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
1089 {
1091  "finalize http uwsgi request");
1092 
1093  return;
1094 }
1095 
1096 
1097 static void *
1098 ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf)
1099 {
1101 
1102  conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_uwsgi_loc_conf_t));
1103  if (conf == NULL) {
1104  return NULL;
1105  }
1106 
1109 
1110  conf->upstream.store = NGX_CONF_UNSET;
1114 
1116 
1120 
1123 
1127 
1130 
1131 #if (NGX_HTTP_CACHE)
1132  conf->upstream.cache = NGX_CONF_UNSET_PTR;
1133  conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
1134  conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
1135  conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
1136  conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
1137  conf->upstream.cache_lock = NGX_CONF_UNSET;
1138  conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
1139 #endif
1140 
1143 
1145 
1146  /* "uwsgi_cyclic_temp_file" is disabled */
1147  conf->upstream.cyclic_temp_file = 0;
1148 
1149  conf->upstream.change_buffering = 1;
1150 
1151  ngx_str_set(&conf->upstream.module, "uwsgi");
1152 
1153  return conf;
1154 }
1155 
1156 
1157 static char *
1158 ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
1159 {
1160  ngx_http_uwsgi_loc_conf_t *prev = parent;
1161  ngx_http_uwsgi_loc_conf_t *conf = child;
1162 
1163  size_t size;
1164  ngx_hash_init_t hash;
1166 
1167  if (conf->upstream.store != 0) {
1169 
1170  if (conf->upstream.store_lengths == NULL) {
1173  }
1174  }
1175 
1177  prev->upstream.store_access, 0600);
1178 
1180  prev->upstream.buffering, 1);
1181 
1183  prev->upstream.ignore_client_abort, 0);
1184 
1186  prev->upstream.local, NULL);
1187 
1189  prev->upstream.connect_timeout, 60000);
1190 
1192  prev->upstream.send_timeout, 60000);
1193 
1195  prev->upstream.read_timeout, 60000);
1196 
1198  prev->upstream.send_lowat, 0);
1199 
1201  prev->upstream.buffer_size,
1202  (size_t) ngx_pagesize);
1203 
1204 
1206  8, ngx_pagesize);
1207 
1208  if (conf->upstream.bufs.num < 2) {
1210  "there must be at least 2 \"uwsgi_buffers\"");
1211  return NGX_CONF_ERROR;
1212  }
1213 
1214 
1215  size = conf->upstream.buffer_size;
1216  if (size < conf->upstream.bufs.size) {
1217  size = conf->upstream.bufs.size;
1218  }
1219 
1220 
1224 
1226  conf->upstream.busy_buffers_size = 2 * size;
1227  } else {
1228  conf->upstream.busy_buffers_size =
1230  }
1231 
1232  if (conf->upstream.busy_buffers_size < size) {
1234  "\"uwsgi_busy_buffers_size\" must be equal to or greater "
1235  "than the maximum of the value of \"uwsgi_buffer_size\" and "
1236  "one of the \"uwsgi_buffers\"");
1237 
1238  return NGX_CONF_ERROR;
1239  }
1240 
1241  if (conf->upstream.busy_buffers_size
1242  > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
1243  {
1245  "\"uwsgi_busy_buffers_size\" must be less than "
1246  "the size of all \"uwsgi_buffers\" minus one buffer");
1247 
1248  return NGX_CONF_ERROR;
1249  }
1250 
1251 
1255 
1257  conf->upstream.temp_file_write_size = 2 * size;
1258  } else {
1261  }
1262 
1263  if (conf->upstream.temp_file_write_size < size) {
1265  "\"uwsgi_temp_file_write_size\" must be equal to or greater than "
1266  "the maximum of the value of \"uwsgi_buffer_size\" and "
1267  "one of the \"uwsgi_buffers\"");
1268 
1269  return NGX_CONF_ERROR;
1270  }
1271 
1272 
1276 
1278  conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
1279  } else {
1282  }
1283 
1284  if (conf->upstream.max_temp_file_size != 0
1285  && conf->upstream.max_temp_file_size < size) {
1287  "\"uwsgi_max_temp_file_size\" must be equal to zero to disable "
1288  "temporary files usage or must be equal to or greater than "
1289  "the maximum of the value of \"uwsgi_buffer_size\" and "
1290  "one of the \"uwsgi_buffers\"");
1291 
1292  return NGX_CONF_ERROR;
1293  }
1294 
1295 
1297  prev->upstream.ignore_headers,
1299 
1300 
1302  prev->upstream.next_upstream,
1306 
1310  }
1311 
1313  prev->upstream.temp_path,
1314  &ngx_http_uwsgi_temp_path)
1315  != NGX_OK)
1316  {
1317  return NGX_CONF_ERROR;
1318  }
1319 
1320 #if (NGX_HTTP_CACHE)
1321 
1322  ngx_conf_merge_ptr_value(conf->upstream.cache,
1323  prev->upstream.cache, NULL);
1324 
1325  if (conf->upstream.cache && conf->upstream.cache->data == NULL) {
1326  ngx_shm_zone_t *shm_zone;
1327 
1328  shm_zone = conf->upstream.cache;
1329 
1331  "\"uwsgi_cache\" zone \"%V\" is unknown",
1332  &shm_zone->shm.name);
1333 
1334  return NGX_CONF_ERROR;
1335  }
1336 
1337  ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
1338  prev->upstream.cache_min_uses, 1);
1339 
1340  ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
1341  prev->upstream.cache_use_stale,
1344 
1345  if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
1346  conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
1348  }
1349 
1350  if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
1351  conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
1352  }
1353 
1354  if (conf->upstream.cache_methods == 0) {
1355  conf->upstream.cache_methods = prev->upstream.cache_methods;
1356  }
1357 
1358  conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
1359 
1360  ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
1361  prev->upstream.cache_bypass, NULL);
1362 
1363  ngx_conf_merge_ptr_value(conf->upstream.no_cache,
1364  prev->upstream.no_cache, NULL);
1365 
1366  ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
1367  prev->upstream.cache_valid, NULL);
1368 
1369  if (conf->cache_key.value.data == NULL) {
1370  conf->cache_key = prev->cache_key;
1371  }
1372 
1373  ngx_conf_merge_value(conf->upstream.cache_lock,
1374  prev->upstream.cache_lock, 0);
1375 
1376  ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
1377  prev->upstream.cache_lock_timeout, 5000);
1378 
1379 #endif
1380 
1382  prev->upstream.pass_request_headers, 1);
1384  prev->upstream.pass_request_body, 1);
1385 
1387  prev->upstream.intercept_errors, 0);
1388 
1390 
1391  hash.max_size = 512;
1393  hash.name = "uwsgi_hide_headers_hash";
1394 
1396  &prev->upstream, ngx_http_uwsgi_hide_headers, &hash)
1397  != NGX_OK)
1398  {
1399  return NGX_CONF_ERROR;
1400  }
1401 
1402  if (conf->upstream.upstream == NULL) {
1403  conf->upstream.upstream = prev->upstream.upstream;
1404  }
1405 
1406  if (conf->uwsgi_lengths == NULL) {
1407  conf->uwsgi_lengths = prev->uwsgi_lengths;
1408  conf->uwsgi_values = prev->uwsgi_values;
1409  }
1410 
1411  if (conf->upstream.upstream || conf->uwsgi_lengths) {
1413  if (clcf->handler == NULL && clcf->lmt_excpt) {
1414  clcf->handler = ngx_http_uwsgi_handler;
1415  }
1416  }
1417 
1420 
1421  if (ngx_http_uwsgi_merge_params(cf, conf, prev) != NGX_OK) {
1422  return NGX_CONF_ERROR;
1423  }
1424 
1425  return NGX_CONF_OK;
1426 }
1427 
1428 
1429 static ngx_int_t
1430 ngx_http_uwsgi_merge_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf,
1432 {
1433  u_char *p;
1434  size_t size;
1435  uintptr_t *code;
1436  ngx_uint_t i, nsrc;
1437  ngx_array_t headers_names;
1438 #if (NGX_HTTP_CACHE)
1439  ngx_array_t params_merged;
1440 #endif
1441  ngx_hash_key_t *hk;
1442  ngx_hash_init_t hash;
1446 
1447  if (conf->params_source == NULL) {
1448  conf->params_source = prev->params_source;
1449 
1450  if (prev->headers_hash.buckets
1451 #if (NGX_HTTP_CACHE)
1452  && ((conf->upstream.cache == NULL)
1453  == (prev->upstream.cache == NULL))
1454 #endif
1455  )
1456  {
1457  conf->flushes = prev->flushes;
1458  conf->params_len = prev->params_len;
1459  conf->params = prev->params;
1460  conf->headers_hash = prev->headers_hash;
1461  conf->header_params = prev->header_params;
1462 
1463  return NGX_OK;
1464  }
1465  }
1466 
1467  if (conf->params_source == NULL
1468 #if (NGX_HTTP_CACHE)
1469  && (conf->upstream.cache == NULL)
1470 #endif
1471  )
1472  {
1473  conf->headers_hash.buckets = (void *) 1;
1474  return NGX_OK;
1475  }
1476 
1477  conf->params_len = ngx_array_create(cf->pool, 64, 1);
1478  if (conf->params_len == NULL) {
1479  return NGX_ERROR;
1480  }
1481 
1482  conf->params = ngx_array_create(cf->pool, 512, 1);
1483  if (conf->params == NULL) {
1484  return NGX_ERROR;
1485  }
1486 
1487  if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
1488  != NGX_OK)
1489  {
1490  return NGX_ERROR;
1491  }
1492 
1493  if (conf->params_source) {
1494  src = conf->params_source->elts;
1495  nsrc = conf->params_source->nelts;
1496 
1497  } else {
1498  src = NULL;
1499  nsrc = 0;
1500  }
1501 
1502 #if (NGX_HTTP_CACHE)
1503 
1504  if (conf->upstream.cache) {
1505  ngx_keyval_t *h;
1507 
1508  if (ngx_array_init(&params_merged, cf->temp_pool, 4,
1509  sizeof(ngx_http_upstream_param_t))
1510  != NGX_OK)
1511  {
1512  return NGX_ERROR;
1513  }
1514 
1515  for (i = 0; i < nsrc; i++) {
1516 
1517  s = ngx_array_push(&params_merged);
1518  if (s == NULL) {
1519  return NGX_ERROR;
1520  }
1521 
1522  *s = src[i];
1523  }
1524 
1525  h = ngx_http_uwsgi_cache_headers;
1526 
1527  while (h->key.len) {
1528 
1529  src = params_merged.elts;
1530  nsrc = params_merged.nelts;
1531 
1532  for (i = 0; i < nsrc; i++) {
1533  if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
1534  goto next;
1535  }
1536  }
1537 
1538  s = ngx_array_push(&params_merged);
1539  if (s == NULL) {
1540  return NGX_ERROR;
1541  }
1542 
1543  s->key = h->key;
1544  s->value = h->value;
1545  s->skip_empty = 0;
1546 
1547  next:
1548 
1549  h++;
1550  }
1551 
1552  src = params_merged.elts;
1553  nsrc = params_merged.nelts;
1554  }
1555 
1556 #endif
1557 
1558  for (i = 0; i < nsrc; i++) {
1559 
1560  if (src[i].key.len > sizeof("HTTP_") - 1
1561  && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
1562  {
1563  hk = ngx_array_push(&headers_names);
1564  if (hk == NULL) {
1565  return NGX_ERROR;
1566  }
1567 
1568  hk->key.len = src[i].key.len - 5;
1569  hk->key.data = src[i].key.data + 5;
1570  hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
1571  hk->value = (void *) 1;
1572 
1573  if (src[i].value.len == 0) {
1574  continue;
1575  }
1576  }
1577 
1578  copy = ngx_array_push_n(conf->params_len,
1579  sizeof(ngx_http_script_copy_code_t));
1580  if (copy == NULL) {
1581  return NGX_ERROR;
1582  }
1583 
1585  copy->len = src[i].key.len;
1586 
1587  copy = ngx_array_push_n(conf->params_len,
1588  sizeof(ngx_http_script_copy_code_t));
1589  if (copy == NULL) {
1590  return NGX_ERROR;
1591  }
1592 
1594  copy->len = src[i].skip_empty;
1595 
1596 
1597  size = (sizeof(ngx_http_script_copy_code_t)
1598  + src[i].key.len + sizeof(uintptr_t) - 1)
1599  & ~(sizeof(uintptr_t) - 1);
1600 
1601  copy = ngx_array_push_n(conf->params, size);
1602  if (copy == NULL) {
1603  return NGX_ERROR;
1604  }
1605 
1607  copy->len = src[i].key.len;
1608 
1609  p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
1610  ngx_memcpy(p, src[i].key.data, src[i].key.len);
1611 
1612 
1613  ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
1614 
1615  sc.cf = cf;
1616  sc.source = &src[i].value;
1617  sc.flushes = &conf->flushes;
1618  sc.lengths = &conf->params_len;
1619  sc.values = &conf->params;
1620 
1621  if (ngx_http_script_compile(&sc) != NGX_OK) {
1622  return NGX_ERROR;
1623  }
1624 
1625  code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
1626  if (code == NULL) {
1627  return NGX_ERROR;
1628  }
1629 
1630  *code = (uintptr_t) NULL;
1631 
1632 
1633  code = ngx_array_push_n(conf->params, sizeof(uintptr_t));
1634  if (code == NULL) {
1635  return NGX_ERROR;
1636  }
1637 
1638  *code = (uintptr_t) NULL;
1639  }
1640 
1641  code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
1642  if (code == NULL) {
1643  return NGX_ERROR;
1644  }
1645 
1646  *code = (uintptr_t) NULL;
1647 
1648  conf->header_params = headers_names.nelts;
1649 
1650  hash.hash = &conf->headers_hash;
1651  hash.key = ngx_hash_key_lc;
1652  hash.max_size = 512;
1653  hash.bucket_size = 64;
1654  hash.name = "uwsgi_params_hash";
1655  hash.pool = cf->pool;
1656  hash.temp_pool = NULL;
1657 
1658  return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
1659 }
1660 
1661 
1662 static char *
1663 ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1664 {
1665  ngx_http_uwsgi_loc_conf_t *uwcf = conf;
1666 
1667  ngx_url_t u;
1668  ngx_str_t *value, *url;
1669  ngx_uint_t n;
1672 
1673  if (uwcf->upstream.upstream || uwcf->uwsgi_lengths) {
1674  return "is duplicate";
1675  }
1676 
1678  clcf->handler = ngx_http_uwsgi_handler;
1679 
1680  value = cf->args->elts;
1681 
1682  url = &value[1];
1683 
1685 
1686  if (n) {
1687 
1688  ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
1689 
1690  sc.cf = cf;
1691  sc.source = url;
1692  sc.lengths = &uwcf->uwsgi_lengths;
1693  sc.values = &uwcf->uwsgi_values;
1694  sc.variables = n;
1695  sc.complete_lengths = 1;
1696  sc.complete_values = 1;
1697 
1698  if (ngx_http_script_compile(&sc) != NGX_OK) {
1699  return NGX_CONF_ERROR;
1700  }
1701 
1702  return NGX_CONF_OK;
1703  }
1704 
1705  ngx_memzero(&u, sizeof(ngx_url_t));
1706 
1707  u.url = value[1];
1708  u.no_resolve = 1;
1709 
1710  uwcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
1711  if (uwcf->upstream.upstream == NULL) {
1712  return NGX_CONF_ERROR;
1713  }
1714 
1715  if (clcf->name.data[clcf->name.len - 1] == '/') {
1716  clcf->auto_redirect = 1;
1717  }
1718 
1719  return NGX_CONF_OK;
1720 }
1721 
1722 
1723 static char *
1724 ngx_http_uwsgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1725 {
1726  ngx_http_uwsgi_loc_conf_t *uwcf = conf;
1727 
1728  ngx_str_t *value;
1730 
1731  if (uwcf->upstream.store != NGX_CONF_UNSET || uwcf->upstream.store_lengths)
1732  {
1733  return "is duplicate";
1734  }
1735 
1736  value = cf->args->elts;
1737 
1738  if (ngx_strcmp(value[1].data, "off") == 0) {
1739  uwcf->upstream.store = 0;
1740  return NGX_CONF_OK;
1741  }
1742 
1743 #if (NGX_HTTP_CACHE)
1744 
1745  if (uwcf->upstream.cache != NGX_CONF_UNSET_PTR
1746  && uwcf->upstream.cache != NULL)
1747  {
1748  return "is incompatible with \"uwsgi_cache\"";
1749  }
1750 
1751 #endif
1752 
1753  if (ngx_strcmp(value[1].data, "on") == 0) {
1754  uwcf->upstream.store = 1;
1755  return NGX_CONF_OK;
1756  }
1757 
1758  /* include the terminating '\0' into script */
1759  value[1].len++;
1760 
1761  ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
1762 
1763  sc.cf = cf;
1764  sc.source = &value[1];
1765  sc.lengths = &uwcf->upstream.store_lengths;
1766  sc.values = &uwcf->upstream.store_values;
1767  sc.variables = ngx_http_script_variables_count(&value[1]);;
1768  sc.complete_lengths = 1;
1769  sc.complete_values = 1;
1770 
1771  if (ngx_http_script_compile(&sc) != NGX_OK) {
1772  return NGX_CONF_ERROR;
1773  }
1774 
1775  return NGX_CONF_OK;
1776 }
1777 
1778 
1779 #if (NGX_HTTP_CACHE)
1780 
1781 static char *
1782 ngx_http_uwsgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1783 {
1784  ngx_http_uwsgi_loc_conf_t *uwcf = conf;
1785 
1786  ngx_str_t *value;
1787 
1788  value = cf->args->elts;
1789 
1790  if (uwcf->upstream.cache != NGX_CONF_UNSET_PTR) {
1791  return "is duplicate";
1792  }
1793 
1794  if (ngx_strcmp(value[1].data, "off") == 0) {
1795  uwcf->upstream.cache = NULL;
1796  return NGX_CONF_OK;
1797  }
1798 
1799  if (uwcf->upstream.store > 0 || uwcf->upstream.store_lengths) {
1800  return "is incompatible with \"uwsgi_store\"";
1801  }
1802 
1803  uwcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
1804  &ngx_http_uwsgi_module);
1805  if (uwcf->upstream.cache == NULL) {
1806  return NGX_CONF_ERROR;
1807  }
1808 
1809  return NGX_CONF_OK;
1810 }
1811 
1812 
1813 static char *
1814 ngx_http_uwsgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1815 {
1816  ngx_http_uwsgi_loc_conf_t *uwcf = conf;
1817 
1818  ngx_str_t *value;
1820 
1821  value = cf->args->elts;
1822 
1823  if (uwcf->cache_key.value.data) {
1824  return "is duplicate";
1825  }
1826 
1828 
1829  ccv.cf = cf;
1830  ccv.value = &value[1];
1831  ccv.complex_value = &uwcf->cache_key;
1832 
1833  if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
1834  return NGX_CONF_ERROR;
1835  }
1836 
1837  return NGX_CONF_OK;
1838 }
1839 
1840 #endif