~nginx/nginx/1.0

« back to all changes in this revision

Viewing changes to src/http/modules/ngx_http_fastcgi_module.c

  • Committer: Michael Lustfield
  • Date: 2010-12-01 08:06:25 UTC
  • Revision ID: michael@profarius.com-20101201080625-y8i4bq0e54ev2qwy
Tags: 0.9.0
Nginx v0.9.0

Show diffs side-by-side

added added

removed removed

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