1
2 /*
3 * Copyright (C) 2009 Valery Kholodkov
4 */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_http.h>
10 #include <nginx.h>
11
12 /*
13 * NOTE: Once you change the value of this macro to >10,
14 * you need to do adapt the code accordingly
15 */
16 #define NGX_MOGILEFS_MAX_PATHS 10
17
18 typedef enum {
19 NGX_MOGILEFS_MAIN,
20 NGX_MOGILEFS_CREATE_OPEN,
21 NGX_MOGILEFS_CREATE_CLOSE,
22 NGX_MOGILEFS_FETCH,
23 } ngx_http_mogilefs_location_type_t;
24
25 typedef struct {
26 ngx_int_t status;
27 ngx_str_t name;
28 ngx_flag_t delete_ok;
29 } ngx_http_mogilefs_error_t;
30
31 typedef struct {
32 ngx_uint_t method;
33 ngx_str_t name;
34 ngx_str_t output_param;
35 ngx_str_t output_count_param;
36 } ngx_http_mogilefs_cmd_t;
37
38 typedef struct {
39 ngx_str_t source;
40 ngx_array_t *lengths;
41 ngx_array_t *values;
42 } ngx_http_mogilefs_class_template_t;
43
44 typedef struct ngx_http_mogilefs_loc_conf_s {
45 struct ngx_http_mogilefs_loc_conf_s *parent;
46 ngx_uint_t methods;
47 ngx_str_t key;
48 ngx_array_t *key_lengths;
49 ngx_array_t *key_values;
50 ngx_int_t index[NGX_MOGILEFS_MAX_PATHS];
51 ngx_http_upstream_conf_t upstream;
52 ngx_array_t *tracker_lengths;
53 ngx_array_t *tracker_values;
54 ngx_str_t domain;
55 ngx_array_t *class_templates;
56 ngx_str_t fetch_location;
57 ngx_flag_t noverify;
58 ngx_http_mogilefs_location_type_t location_type;
59 ngx_str_t create_open_spare_location;
60 ngx_str_t create_close_spare_location;
61 } ngx_http_mogilefs_loc_conf_t;
62
63 typedef struct {
64 ngx_str_t name, value;
65 } ngx_http_mogilefs_aux_param_t;
66
67 typedef struct {
68 ngx_http_mogilefs_cmd_t *cmd;
69 ngx_array_t sources;
70 ssize_t num_paths_returned;
71 ngx_array_t *aux_params;
72 ngx_str_t key;
73 ngx_int_t status;
74
75 struct sockaddr *peer_addr;
76 socklen_t peer_addr_len;
77 } ngx_http_mogilefs_ctx_t;
78
79 typedef enum {
80 START,
81 CREATE_OPEN,
82 FETCH,
83 CREATE_CLOSE,
84 } ngx_http_mogilefs_put_state_t;
85
86 typedef struct {
87 ngx_http_post_subrequest_t *psr;
88 ngx_http_mogilefs_put_state_t state;
89 ngx_int_t status;
90 ngx_http_mogilefs_ctx_t *create_open_ctx;
91 ngx_str_t key;
92
93 ngx_uint_t num_successful_stores;
94 } ngx_http_mogilefs_put_ctx_t;
95
96 typedef struct {
97 ssize_t priority;
98 ngx_str_t path;
99 } ngx_http_mogilefs_src_t;
100
101 static ngx_int_t ngx_http_mogilefs_put_handler(ngx_http_request_t *r);
102 static ngx_int_t ngx_http_mogilefs_finish_phase_handler(ngx_http_request_t *r, void *data, ngx_int_t rc);
103
104 static ngx_int_t ngx_http_mogilefs_eval_tracker(ngx_http_request_t *r, ngx_http_mogilefs_loc_conf_t *mgcf);
105 static ngx_int_t ngx_http_mogilefs_eval_class(ngx_http_request_t *r, ngx_http_mogilefs_loc_conf_t *mgcf);
106 static ngx_int_t ngx_http_mogilefs_eval_key(ngx_http_request_t *r, ngx_str_t *key);
107 static ngx_int_t ngx_http_mogilefs_set_cmd(ngx_http_request_t *r, ngx_http_mogilefs_ctx_t *ctx);
108
109 static ngx_int_t ngx_http_mogilefs_create_request(ngx_http_request_t *r);
110 static ngx_int_t ngx_http_mogilefs_reinit_request(ngx_http_request_t *r);
111 static ngx_int_t ngx_http_mogilefs_process_header(ngx_http_request_t *r);
112 static void ngx_http_mogilefs_abort_request(ngx_http_request_t *r);
113 static void ngx_http_mogilefs_finalize_request(ngx_http_request_t *r, ngx_int_t rc);
114
115 static ngx_int_t ngx_http_mogilefs_filter_init(void *data);
116 static ngx_int_t ngx_http_mogilefs_filter(void *data, ssize_t bytes);
117
118 static ngx_int_t ngx_http_mogilefs_parse_param(ngx_http_request_t *r, ngx_str_t *param);
119 static ngx_int_t ngx_http_mogilefs_add_aux_param(ngx_http_request_t *r, ngx_str_t *name,
120 ngx_str_t *value);
121
122 static ngx_int_t ngx_http_mogilefs_path_variable(ngx_http_request_t *r,
123 ngx_http_variable_value_t *v, uintptr_t data);
124
125 static void *ngx_http_mogilefs_create_loc_conf(ngx_conf_t *cf);
126 static char *ngx_http_mogilefs_merge_loc_conf(ngx_conf_t *cf, void *parent,
127 void *child);
128 static ngx_int_t ngx_http_mogilefs_add_variables(ngx_conf_t *cf);
129
130 static char *
131 ngx_http_mogilefs_tracker_command(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
132 static char *
133 ngx_http_mogilefs_class_command(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
134 static char *
135 ngx_http_mogilefs_pass_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
136
137 static ngx_int_t ngx_http_mogilefs_init(ngx_conf_t *cf);
138
139 static ngx_http_mogilefs_error_t ngx_http_mogilefs_errors[] = {
140 {NGX_HTTP_NOT_FOUND, ngx_string("unknown_key"), 1},
141 {NGX_HTTP_NOT_FOUND, ngx_string("domain_not_found"), 0},
142 {NGX_HTTP_SERVICE_UNAVAILABLE, ngx_string("no_devices"), 0},
143 {NGX_HTTP_BAD_REQUEST, ngx_string("no_key"), 0},
144 {NGX_HTTP_BAD_REQUEST, ngx_string("unreg_class"), 0},
145
146 {NGX_HTTP_INTERNAL_SERVER_ERROR, ngx_null_string, 0},
147 };
148
149 static ngx_http_mogilefs_cmd_t ngx_http_mogilefs_cmds[] = {
150 {NGX_HTTP_GET, ngx_string("get_paths"), ngx_string("path"), ngx_string("paths") },
151 {NGX_HTTP_HEAD, ngx_string("get_paths"), ngx_string("path"), ngx_string("paths") },
152 {NGX_HTTP_PUT, ngx_string("create_open"), ngx_string("path_"), ngx_string("dev_count") },
153 {NGX_HTTP_DELETE, ngx_string("delete"), ngx_null_string, ngx_null_string },
154
155 {0, ngx_null_string, ngx_null_string, ngx_null_string },
156 };
157
158 static ngx_conf_bitmask_t ngx_http_mogilefs_methods_mask[] = {
159 { ngx_string("get"), NGX_HTTP_GET },
160 { ngx_string("put"), NGX_HTTP_PUT },
161 { ngx_string("delete"), NGX_HTTP_DELETE },
162 { ngx_null_string, 0 }
163 };
164
165 static ngx_str_t ngx_http_mogilefs_put_method = { 3, (u_char *) "PUT " };
166
167 static ngx_command_t ngx_http_mogilefs_commands[] = {
168
169 { ngx_string("mogilefs_pass"),
170 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1|NGX_CONF_BLOCK,
171 ngx_http_mogilefs_pass_block,
172 NGX_HTTP_LOC_CONF_OFFSET,
173 0,
174 NULL },
175
176 { ngx_string("mogilefs_tracker"),
177 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
178 ngx_http_mogilefs_tracker_command,
179 NGX_HTTP_LOC_CONF_OFFSET,
180 0,
181 NULL },
182
183 { ngx_string("mogilefs_domain"),
184 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
185 ngx_conf_set_str_slot,
186 NGX_HTTP_LOC_CONF_OFFSET,
187 offsetof(ngx_http_mogilefs_loc_conf_t, domain),
188 NULL },
189
190 { ngx_string("mogilefs_connect_timeout"),
191 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
192 ngx_conf_set_msec_slot,
193 NGX_HTTP_LOC_CONF_OFFSET,
194 offsetof(ngx_http_mogilefs_loc_conf_t, upstream.connect_timeout),
195 NULL },
196
197 { ngx_string("mogilefs_send_timeout"),
198 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
199 ngx_conf_set_msec_slot,
200 NGX_HTTP_LOC_CONF_OFFSET,
201 offsetof(ngx_http_mogilefs_loc_conf_t, upstream.send_timeout),
202 NULL },
203
204 { ngx_string("mogilefs_read_timeout"),
205 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
206 ngx_conf_set_msec_slot,
207 NGX_HTTP_LOC_CONF_OFFSET,
208 offsetof(ngx_http_mogilefs_loc_conf_t, upstream.read_timeout),
209 NULL },
210
211 { ngx_string("mogilefs_noverify"),
212 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
213 ngx_conf_set_flag_slot,
214 NGX_HTTP_LOC_CONF_OFFSET,
215 offsetof(ngx_http_mogilefs_loc_conf_t, noverify),
216 NULL },
217
218 { ngx_string("mogilefs_methods"),
219 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
220 ngx_conf_set_bitmask_slot,
221 NGX_HTTP_LOC_CONF_OFFSET,
222 offsetof(ngx_http_mogilefs_loc_conf_t, methods),
223 &ngx_http_mogilefs_methods_mask },
224
225 { ngx_string("mogilefs_class"),
226 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
227 ngx_http_mogilefs_class_command,
228 NGX_HTTP_LOC_CONF_OFFSET,
229 offsetof(ngx_http_mogilefs_loc_conf_t, class_templates),
230 NULL },
231
232 ngx_null_command
233 };
234
235 static ngx_http_module_t ngx_http_mogilefs_module_ctx = {
236 ngx_http_mogilefs_add_variables, /* preconfiguration */
237 ngx_http_mogilefs_init, /* postconfiguration */
238
239 NULL, /* create main configuration */
240 NULL, /* init main configuration */
241
242 NULL, /* create server configuration */
243 NULL, /* merge server configuration */
244
245 ngx_http_mogilefs_create_loc_conf, /* create location configuration */
246 ngx_http_mogilefs_merge_loc_conf /* merge location configuration */
247 };
248
249 ngx_module_t ngx_http_mogilefs_module = {
250 NGX_MODULE_V1,
251 &ngx_http_mogilefs_module_ctx, /* module context */
252 ngx_http_mogilefs_commands, /* module directives */
253 NGX_HTTP_MODULE, /* module type */
254 NULL, /* init master */
255 NULL, /* init module */
256 NULL, /* init process */
257 NULL, /* init thread */
258 NULL, /* exit thread */
259 NULL, /* exit process */
260 NULL, /* exit master */
261 NGX_MODULE_V1_PADDING
262 };
263
264 static u_char ngx_http_mogilefs_path_str[] = "mogilefs_path#";
265 static ngx_str_t ngx_http_mogilefs_path = ngx_string(ngx_http_mogilefs_path_str);
266
267 static ngx_http_variable_t ngx_http_mogilefs_path_variable_template = { /* {{{ */
268 ngx_string(ngx_http_mogilefs_path_str), NULL, ngx_http_mogilefs_path_variable,
269 (uintptr_t) offsetof(ngx_http_mogilefs_ctx_t, sources),
270 NGX_HTTP_VAR_CHANGEABLE, 0
271 }; /* }}} */
272 static ngx_str_t ngx_http_mogilefs_class = ngx_string("class");
273 static ngx_str_t ngx_http_mogilefs_size = ngx_string("size");
274
275 static ngx_int_t
ngx_http_mogilefs_handler(ngx_http_request_t * r)276 ngx_http_mogilefs_handler(ngx_http_request_t *r)
277 {
278 ngx_int_t rc;
279 ngx_http_upstream_t *u;
280 ngx_http_mogilefs_ctx_t *ctx;
281 ngx_http_mogilefs_loc_conf_t *mgcf;
282
283 mgcf = ngx_http_get_module_loc_conf(r, ngx_http_mogilefs_module);
284
285 if (mgcf->location_type == NGX_MOGILEFS_MAIN) {
286 if(!(r->method & mgcf->methods)) {
287 return NGX_HTTP_NOT_ALLOWED;
288 }
289
290 if(r->method & NGX_HTTP_PUT) {
291 return NGX_DECLINED;
292 }
293 }
294
295 switch(r->method) {
296 case NGX_HTTP_GET:
297 if (ngx_http_set_content_type(r) != NGX_OK) {
298 return NGX_HTTP_INTERNAL_SERVER_ERROR;
299 }
300
301 case NGX_HTTP_DELETE:
302 rc = ngx_http_discard_request_body(r);
303
304 if (rc != NGX_OK) {
305 return rc;
306 }
307 break;
308 default:
309 break;
310 }
311
312 u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
313 if (u == NULL) {
314 return NGX_HTTP_INTERNAL_SERVER_ERROR;
315 }
316
317 u->peer.log = r->connection->log;
318 u->peer.log_error = NGX_ERROR_ERR;
319
320 u->output.tag = (ngx_buf_tag_t) &ngx_http_mogilefs_module;
321
322 u->conf = &mgcf->upstream;
323
324 u->create_request = ngx_http_mogilefs_create_request;
325 u->reinit_request = ngx_http_mogilefs_reinit_request;
326 u->process_header = ngx_http_mogilefs_process_header;
327 u->abort_request = ngx_http_mogilefs_abort_request;
328 u->finalize_request = ngx_http_mogilefs_finalize_request;
329
330 r->upstream = u;
331
332 ctx = ngx_http_get_module_ctx(r, ngx_http_mogilefs_module);
333
334 if(ctx == NULL) {
335 ctx = ngx_palloc(r->pool, sizeof(ngx_http_mogilefs_ctx_t));
336 if (ctx == NULL) {
337 return NGX_HTTP_INTERNAL_SERVER_ERROR;
338 }
339
340 ctx->peer_addr = NULL;
341 ctx->peer_addr_len = 0;
342
343 ctx->num_paths_returned = -1;
344 ctx->aux_params = NULL;
345 ctx->status = 0;
346
347 ngx_array_init(&ctx->sources, r->pool, 1, sizeof(ngx_http_mogilefs_src_t));
348
349 if(ngx_http_mogilefs_eval_key(r, &ctx->key) != NGX_OK) {
350 return NGX_HTTP_INTERNAL_SERVER_ERROR;
351 }
352
353 ngx_http_set_ctx(r, ctx, ngx_http_mogilefs_module);
354 }
355
356 u->input_filter_init = ngx_http_mogilefs_filter_init;
357 u->input_filter = ngx_http_mogilefs_filter;
358 u->input_filter_ctx = ctx;
359
360 if (mgcf->tracker_lengths != 0) {
361 if (ngx_http_mogilefs_eval_tracker(r, mgcf) != NGX_OK) {
362 return NGX_HTTP_INTERNAL_SERVER_ERROR;
363 }
364 }
365
366 if(ngx_http_mogilefs_set_cmd(r, ctx) != NGX_OK) {
367 return NGX_ERROR;
368 }
369
370 #if defined nginx_version && nginx_version >= 8011
371 r->main->count++;
372 #endif
373
374 ngx_http_upstream_init(r);
375
376 return NGX_DONE;
377 }
378
379 static void
ngx_http_mogilefs_body_handler(ngx_http_request_t * r)380 ngx_http_mogilefs_body_handler(ngx_http_request_t *r)
381 {
382 ngx_int_t rc;
383
384 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
385 "mogilefs body handler");
386
387 rc = ngx_http_mogilefs_put_handler(r);
388
389 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
390 ngx_http_finalize_request(r, rc);
391 }
392 }
393
394 static ngx_int_t
ngx_http_mogilefs_put_handler(ngx_http_request_t * r)395 ngx_http_mogilefs_put_handler(ngx_http_request_t *r)
396 {
397 ngx_http_mogilefs_put_ctx_t *ctx;
398 ngx_str_t args;
399 ngx_uint_t flags;
400 ngx_http_request_t *sr;
401 ngx_str_t spare_location = ngx_null_string, uri, value;
402 ngx_int_t rc;
403 u_char *p;
404 ngx_http_core_loc_conf_t *clcf;
405 ngx_http_mogilefs_loc_conf_t *mgcf;
406
407 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
408 "mogilefs put handler");
409
410 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
411 mgcf = ngx_http_get_module_loc_conf(r, ngx_http_mogilefs_module);
412
413 if (clcf->handler != ngx_http_mogilefs_handler ||
414 (mgcf->location_type == NGX_MOGILEFS_MAIN && !(r->method & mgcf->methods)))
415 {
416 return NGX_DECLINED;
417 }
418
419 ctx = ngx_http_get_module_ctx(r, ngx_http_mogilefs_module);
420
421 if(ctx == NULL) {
422 ctx = ngx_palloc(r->pool, sizeof(ngx_http_mogilefs_put_ctx_t));
423 if (ctx == NULL) {
424 return NGX_ERROR;
425 }
426
427 ctx->psr = NULL;
428 ctx->state = START;
429 ctx->status = 0;
430 ctx->create_open_ctx = NULL;
431
432 if(ngx_http_mogilefs_eval_key(r, &ctx->key) != NGX_OK) {
433 return NGX_HTTP_INTERNAL_SERVER_ERROR;
434 }
435
436 ngx_http_set_ctx(r, ctx, ngx_http_mogilefs_module);
437 }
438
439 if(ctx->psr == NULL) {
440 ctx->psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
441 if (ctx->psr == NULL) {
442 return NGX_ERROR;
443 }
444 }
445
446 if(r->request_body == NULL) {
447 rc = ngx_http_read_client_request_body(r, ngx_http_mogilefs_body_handler);
448
449 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
450 return rc;
451 }
452
453 return NGX_DONE;
454 }
455
456 // Still receiving body?
457 if(r->request_body->rest) {
458 return NGX_DONE;
459 }
460
461 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
462 "mogilefs put handler state: %ui, status: %i", ctx->state, ctx->status);
463
464 if(ctx->state == CREATE_OPEN || ctx->state == FETCH || ctx->state == CREATE_CLOSE) {
465 if(ctx->status != NGX_OK && ctx->status != NGX_HTTP_CREATED && ctx->status != NGX_HTTP_NO_CONTENT) {
466 return (ctx->status >= NGX_HTTP_SPECIAL_RESPONSE) ?
467 ctx->status : NGX_HTTP_INTERNAL_SERVER_ERROR;
468 }
469 }
470
471 switch(ctx->state) {
472 case START:
473 spare_location = mgcf->create_open_spare_location;
474 ctx->state = CREATE_OPEN;
475 break;
476 case CREATE_OPEN:
477 spare_location = mgcf->fetch_location;
478 ctx->state = FETCH;
479 break;
480 case FETCH:
481 spare_location = mgcf->create_close_spare_location;
482 ctx->state = CREATE_CLOSE;
483 break;
484 case CREATE_CLOSE:
485 r->headers_out.content_length_n = 0;
486 r->headers_out.status = NGX_HTTP_CREATED;
487
488 r->header_only = 1;
489
490 return ngx_http_send_header(r);
491 }
492
493 uri.len = spare_location.len + ctx->key.len;
494
495 uri.data = ngx_palloc(r->pool, uri.len);
496
497 p = ngx_cpymem(uri.data, spare_location.data, spare_location.len);
498
499 p = ngx_cpymem(p, ctx->key.data, ctx->key.len);
500
501 args.len = 0;
502 args.data = NULL;
503 flags = 0;
504
505 if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) {
506 return NGX_ERROR;
507 }
508
509 ctx->psr->handler = ngx_http_mogilefs_finish_phase_handler;
510 ctx->psr->data = ctx;
511
512 flags |= NGX_HTTP_SUBREQUEST_WAITED;
513
514 if(ctx->state == FETCH) {
515 flags |= NGX_HTTP_SUBREQUEST_IN_MEMORY;
516 }
517
518 rc = ngx_http_subrequest(r, &uri, &args, &sr, ctx->psr, flags);
519
520 if (rc == NGX_ERROR) {
521 return rc;
522 }
523
524 if(ctx->state == CREATE_CLOSE) {
525 ngx_http_set_ctx(sr, ctx->create_open_ctx, ngx_http_mogilefs_module);
526
527 value.data = ngx_palloc(r->pool, NGX_OFF_T_LEN);
528
529 if(value.data == NULL) {
530 return NGX_ERROR;
531 }
532
533 value.len = ngx_sprintf(value.data, "%O", r->headers_in.content_length_n)
534 - value.data;
535
536 if(ngx_http_mogilefs_add_aux_param(sr, &ngx_http_mogilefs_size, &value) != NGX_OK) {
537 return NGX_ERROR;
538 }
539 }
540
541 /*
542 * Nginx closes temporary file with buffered body
543 * whenever it starts sending reponse from upstream
544 * and it is not doing subrequest in memory.
545 *
546 * Since the request body in create_open subrequest is
547 * inherited from main request, it is necessary to prevent
548 * nginx from closing the temporary file with request body,
549 * before it could be passed to the storage node on fetch/store
550 * stage.
551 *
552 * We do it by "hiding" the request body from nginx internals.
553 */
554 if(ctx->state == CREATE_OPEN) {
555 sr->request_body = NULL;
556 }
557
558 sr->method = NGX_HTTP_PUT;
559 sr->method_name = ngx_http_mogilefs_put_method;
560
561 /*
562 * Wait for subrequest to complete
563 */
564 return NGX_DONE;
565 }
566
567 static ngx_int_t
ngx_http_mogilefs_finish_phase_handler(ngx_http_request_t * r,void * data,ngx_int_t rc)568 ngx_http_mogilefs_finish_phase_handler(ngx_http_request_t *r, void *data, ngx_int_t rc)
569 {
570 ngx_http_mogilefs_put_ctx_t *ctx = data;
571 ngx_http_mogilefs_ctx_t *subrequest_ctx;
572
573 subrequest_ctx = ngx_http_get_module_ctx(r, ngx_http_mogilefs_module);
574
575 if(ctx->state == CREATE_OPEN) {
576 ctx->create_open_ctx = subrequest_ctx;
577 }
578
579 ctx->status = (subrequest_ctx != NULL && subrequest_ctx->status >= NGX_HTTP_SPECIAL_RESPONSE)
580 ? subrequest_ctx->status : rc;
581
582 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
583 "mogilefs finish phase handler: state=%ui, status=%i", ctx->state, ctx->status);
584
585 return NGX_OK;
586 }
587
588 static ngx_int_t
ngx_http_mogilefs_eval_tracker(ngx_http_request_t * r,ngx_http_mogilefs_loc_conf_t * mgcf)589 ngx_http_mogilefs_eval_tracker(ngx_http_request_t *r, ngx_http_mogilefs_loc_conf_t *mgcf)
590 {
591 ngx_str_t tracker;
592 ngx_http_upstream_t *u;
593 ngx_http_mogilefs_ctx_t *ctx;
594
595 ctx = ngx_http_get_module_ctx(r, ngx_http_mogilefs_module);
596
597 if (ngx_http_script_run(r, &tracker, mgcf->tracker_lengths->elts, 0,
598 mgcf->tracker_values->elts)
599 == NULL)
600 {
601 return NGX_ERROR;
602 }
603
604 u = r->upstream;
605
606 u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
607 if (u->resolved == NULL) {
608 return NGX_ERROR;
609 }
610
611 if(ctx->peer_addr == NULL) {
612 u->resolved->host = tracker;
613 u->resolved->no_port = 1;
614 }
615 else {
616 u->resolved->sockaddr = ctx->peer_addr;
617 u->resolved->socklen = ctx->peer_addr_len;
618 u->resolved->naddrs = 1;
619 u->resolved->host = tracker;
620 }
621
622 return NGX_OK;
623 }
624
625 static ngx_int_t
ngx_http_mogilefs_eval_class(ngx_http_request_t * r,ngx_http_mogilefs_loc_conf_t * mgcf)626 ngx_http_mogilefs_eval_class(ngx_http_request_t *r, ngx_http_mogilefs_loc_conf_t *mgcf)
627 {
628 ngx_uint_t i;
629 ngx_http_mogilefs_class_template_t *t;
630 ngx_str_t class;
631
632 if(mgcf->class_templates == NULL) {
633 return NGX_DECLINED;
634 }
635
636 t = mgcf->class_templates->elts;
637
638 for(i = 0;i < mgcf->class_templates->nelts;i++) {
639 if(t->lengths != NULL && t->values != NULL) {
640 if(ngx_http_script_run(r, &class, t->lengths->elts, 0,
641 t->values->elts)
642 == NULL)
643 {
644 return NGX_ERROR;
645 }
646 }
647 else {
648 if(ngx_http_mogilefs_add_aux_param(r, &ngx_http_mogilefs_class, &t->source) != NGX_OK) {
649 return NGX_ERROR;
650 }
651
652 return NGX_OK;
653 }
654
655 if(class.len) {
656 if(ngx_http_mogilefs_add_aux_param(r, &ngx_http_mogilefs_class, &class) != NGX_OK) {
657 return NGX_ERROR;
658 }
659
660 return NGX_OK;
661 }
662
663 t++;
664 }
665
666 return NGX_DECLINED;
667 }
668 static ngx_int_t
ngx_http_mogilefs_eval_key(ngx_http_request_t * r,ngx_str_t * key)669 ngx_http_mogilefs_eval_key(ngx_http_request_t *r, ngx_str_t *key)
670 {
671 size_t loc_len;
672 ngx_http_mogilefs_loc_conf_t *mgcf;
673 ngx_http_core_loc_conf_t *clcf;
674
675 mgcf = ngx_http_get_module_loc_conf(r, ngx_http_mogilefs_module);
676 /*
677 * If key is empty take the remaining part of request URI,
678 * otherwise run script to obtain key
679 */
680 if(mgcf->key.len == 0) {
681 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
682
683 loc_len = r->valid_location ? clcf->name.len : 0;
684
685 key->data = r->uri.data + loc_len;
686 key->len = r->uri.len - loc_len;
687 }
688 else {
689 if(mgcf->key_lengths != NULL) {
690 if (ngx_http_script_run(r, key, mgcf->key_lengths->elts, 0,
691 mgcf->key_values->elts)
692 == NULL)
693 {
694 return NGX_ERROR;
695 }
696 }
697 else {
698 *key = mgcf->key;
699 }
700 }
701
702 return NGX_OK;
703 }
704
705 static ngx_int_t
ngx_http_mogilefs_set_cmd(ngx_http_request_t * r,ngx_http_mogilefs_ctx_t * ctx)706 ngx_http_mogilefs_set_cmd(ngx_http_request_t *r, ngx_http_mogilefs_ctx_t *ctx)
707 {
708 ngx_http_mogilefs_cmd_t *c;
709
710 c = ngx_http_mogilefs_cmds;
711
712 while(c->name.data != NULL) {
713 if(c->method & r->method)
714 break;
715
716 c++;
717 }
718
719 if(c->name.data != NULL) {
720 ctx->cmd = c;
721 return NGX_OK;
722 }
723
724 return NGX_ERROR;
725 }
726
727 static ngx_int_t
ngx_http_mogilefs_create_request(ngx_http_request_t * r)728 ngx_http_mogilefs_create_request(ngx_http_request_t *r)
729 {
730 size_t len;
731 uintptr_t escape_domain, escape_key;
732 ngx_str_t cmd;
733 ngx_buf_t *b;
734 ngx_chain_t *cl;
735 ngx_http_mogilefs_loc_conf_t *mgcf;
736 ngx_str_t request, domain;
737 ngx_http_mogilefs_ctx_t *ctx;
738 ngx_http_mogilefs_aux_param_t *a;
739 ngx_uint_t i;
740 ngx_int_t rc;
741
742 mgcf = ngx_http_get_module_loc_conf(r, ngx_http_mogilefs_module);
743
744 ctx = ngx_http_get_module_ctx(r, ngx_http_mogilefs_module);
745
746 /*
747 * Save peer address, so that we contact the same host while doing create_close
748 */
749 if(mgcf->location_type == NGX_MOGILEFS_CREATE_OPEN && ctx->cmd->method & NGX_HTTP_PUT) {
750 if(r->upstream->peer.sockaddr != NULL) {
751 ctx->peer_addr = ngx_palloc(r->main->pool, r->upstream->peer.socklen);
752
753 if(ctx->peer_addr == NULL) {
754 return NGX_ERROR;
755 }
756
757 ngx_memcpy(ctx->peer_addr, r->upstream->peer.sockaddr, r->upstream->peer.socklen);
758
759 ctx->peer_addr_len = r->upstream->peer.socklen;
760 }
761 }
762
763 cmd = ctx->cmd->name;
764
765 if(mgcf->location_type == NGX_MOGILEFS_CREATE_CLOSE && ctx->cmd->method & NGX_HTTP_PUT) {
766 cmd.data = (u_char*)"create_close";
767 cmd.len = sizeof("create_close") - 1;
768 }
769
770 if(ctx->key.len == 0) {
771 return NGX_HTTP_BAD_REQUEST;
772 }
773
774 if(mgcf->parent != NULL) {
775 domain.len = mgcf->parent->domain.len;
776 domain.data = mgcf->parent->domain.data;
777 }
778 else {
779 domain.len = mgcf->domain.len;
780 domain.data = mgcf->domain.data;
781 }
782
783 rc = ngx_http_mogilefs_eval_class(r, mgcf->parent != NULL ? mgcf->parent : mgcf);
784
785 if(rc == NGX_ERROR) {
786 return rc;
787 }
788
789 escape_domain = 2 * ngx_escape_uri(NULL, domain.data, domain.len, NGX_ESCAPE_MEMCACHED);
790 escape_key = 2 * ngx_escape_uri(NULL, ctx->key.data, ctx->key.len, NGX_ESCAPE_MEMCACHED);
791
792 len = cmd.len + 1 + sizeof("key=") - 1 + ctx->key.len + escape_key + 1 +
793 sizeof("domain=") - 1 + domain.len + escape_domain + sizeof(CRLF) - 1 +
794 (mgcf->noverify ? 1 + sizeof("noverify=1") - 1 : 0);
795
796 if(ctx->aux_params != NULL && ctx->aux_params->nelts) {
797 a = ctx->aux_params->elts;
798 for (i = 0; i < ctx->aux_params->nelts; i++) {
799 len += a[i].name.len + 1 + 1 + a[i].value.len;
800 }
801 }
802
803 b = ngx_create_temp_buf(r->pool, len);
804 if (b == NULL) {
805 return NGX_ERROR;
806 }
807
808 cl = ngx_alloc_chain_link(r->pool);
809 if (cl == NULL) {
810 return NGX_ERROR;
811 }
812
813 cl->buf = b;
814 cl->next = NULL;
815
816 r->upstream->request_bufs = cl;
817
818 b->last = ngx_copy(b->last, cmd.data, cmd.len);
819
820 *b->last++ = ' ';
821
822 b->last = ngx_copy(b->last, "key=", sizeof("key=") - 1);
823
824 if (escape_key == 0) {
825 b->last = ngx_copy(b->last, ctx->key.data, ctx->key.len);
826
827 } else {
828 b->last = (u_char *) ngx_escape_uri(b->last, ctx->key.data, ctx->key.len,
829 NGX_ESCAPE_MEMCACHED);
830 }
831
832 *b->last++ = '&';
833
834 b->last = ngx_copy(b->last, "domain=", sizeof("domain=") - 1);
835
836 if (escape_domain == 0) {
837 b->last = ngx_copy(b->last, domain.data, domain.len);
838
839 } else {
840 b->last = (u_char *) ngx_escape_uri(b->last, domain.data, domain.len,
841 NGX_ESCAPE_MEMCACHED);
842 }
843
844 if(mgcf->noverify) {
845 *b->last++ = '&';
846
847 b->last = ngx_copy(b->last, "noverify=1", sizeof("noverify=1") - 1);
848 }
849
850 if(ctx->aux_params != NULL && ctx->aux_params->nelts) {
851 a = ctx->aux_params->elts;
852 for (i = 0; i < ctx->aux_params->nelts; i++) {
853 *b->last++ = '&';
854
855 b->last = ngx_copy(b->last, a[i].name.data, a[i].name.len);
856
857 *b->last++ = '=';
858
859 b->last = ngx_copy(b->last, a[i].value.data, a[i].value.len);
860 }
861 }
862
863 request.data = b->pos;
864 request.len = b->last - b->pos;
865
866 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
867 "mogilefs request: \"%V\"", &request);
868
869 *b->last++ = CR; *b->last++ = LF;
870
871 return NGX_OK;
872 }
873
874 static ngx_int_t
ngx_http_mogilefs_reinit_request(ngx_http_request_t * r)875 ngx_http_mogilefs_reinit_request(ngx_http_request_t *r)
876 {
877 return NGX_OK;
878 }
879
ngx_http_mogilefs_cmp_sources(const void * one,const void * two)880 static int ngx_libc_cdecl ngx_http_mogilefs_cmp_sources(const void *one,
881 const void *two)
882 {
883 ngx_http_mogilefs_src_t *first, *second;
884
885 first = (ngx_http_mogilefs_src_t *) one;
886 second = (ngx_http_mogilefs_src_t *) two;
887
888 return first->priority - second->priority;
889 }
890
891 static ngx_int_t
ngx_http_mogilefs_process_ok_response(ngx_http_request_t * r,ngx_http_upstream_t * u,ngx_str_t * line)892 ngx_http_mogilefs_process_ok_response(ngx_http_request_t *r,
893 ngx_http_upstream_t *u, ngx_str_t *line)
894 {
895 u_char *p;
896 ngx_str_t param;
897 ngx_int_t rc;
898
899 ngx_table_elt_t *h;
900 ngx_http_upstream_header_t *hh;
901 ngx_http_upstream_main_conf_t *umcf;
902 ngx_http_mogilefs_loc_conf_t *mgcf;
903 ngx_http_variable_value_t *v;
904 ngx_http_mogilefs_ctx_t *ctx;
905 ngx_http_mogilefs_src_t *source;
906 ngx_uint_t i;
907
908 line->data += sizeof("OK ") - 1;
909 line->len -= sizeof("OK ") - 1;
910
911 p = line->data;
912
913 param.data = p;
914 param.len = 0;
915
916 while (*p != LF) {
917 if (*p == '&' || *p == CR) {
918 if(param.len != 0) {
919 rc = ngx_http_mogilefs_parse_param(r, ¶m);
920
921 if(rc != NGX_OK) {
922 return rc;
923 }
924
925 p++;
926
927 param.data = p;
928 param.len = 0;
929 }
930
931 if(*p == CR) {
932 break;
933 }
934 else {
935 continue;
936 }
937 }
938
939 param.len++;
940 p++;
941 }
942
943 ctx = ngx_http_get_module_ctx(r, ngx_http_mogilefs_module);
944
945 /*
946 * Convert ok response to delete into No content
947 */
948 if(ctx->cmd->method & NGX_HTTP_DELETE) {
949 r->headers_out.content_length_n = 0;
950 u->headers_in.status_n = NGX_HTTP_NO_CONTENT;
951 u->state->status = NGX_HTTP_NO_CONTENT;
952
953 // Return no content
954 u->buffer.pos = u->buffer.pos;
955
956 return NGX_OK;
957 }
958
959 /*
960 * If no paths retuned, but response was ok, tell the client it's unavailable
961 */
962 if((ctx->num_paths_returned <= 0 && (!(ctx->cmd->method & NGX_HTTP_PUT))) || ctx->sources.nelts == 0)
963 {
964 r->headers_out.content_length_n = 0;
965 u->headers_in.status_n = NGX_HTTP_SERVICE_UNAVAILABLE;
966 u->state->status = NGX_HTTP_SERVICE_UNAVAILABLE;
967
968 // Return no content
969 u->buffer.pos = u->buffer.pos;
970
971 return NGX_OK;
972 }
973
974 /*
975 * Sort sources and choose top source
976 */
977 if(ctx->sources.nelts > 1) {
978 ngx_qsort(ctx->sources.elts, ctx->sources.nelts, sizeof(ngx_http_mogilefs_src_t),
979 ngx_http_mogilefs_cmp_sources);
980 }
981
982 mgcf = ngx_http_get_module_loc_conf(r, ngx_http_mogilefs_module);
983
984 source = ctx->sources.elts;
985
986 /*
987 * Save peer address, so that we contact the same host while doing create_close
988 */
989 if(mgcf->location_type == NGX_MOGILEFS_CREATE_OPEN && ctx->cmd->method & NGX_HTTP_PUT) {
990 if(r->upstream->peer.sockaddr != NULL) {
991 ctx->peer_addr = ngx_palloc(r->main->pool, r->upstream->peer.socklen);
992
993 if(ctx->peer_addr == NULL) {
994 return NGX_ERROR;
995 }
996
997 ngx_memcpy(ctx->peer_addr, r->upstream->peer.sockaddr, r->upstream->peer.socklen);
998
999 ctx->peer_addr_len = r->upstream->peer.socklen;
1000 }
1001 }
1002
1003 /*
1004 * Set $mogilefs_path variables
1005 */
1006 for(i=0;i < ctx->sources.nelts;i++) {
1007 v = r->variables + mgcf->index[i];
1008
1009 v->data = source[i].path.data;
1010 v->len = source[i].path.len;
1011
1012 v->not_found = 0;
1013 v->no_cacheable = 0;
1014 v->valid = 1;
1015 }
1016
1017 /*
1018 * Redirect to fetch location
1019 */
1020 if (ctx->cmd->method & (NGX_HTTP_GET|NGX_HTTP_HEAD) && r->upstream->headers_in.x_accel_redirect == NULL) {
1021
1022 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1023
1024 h = ngx_list_push(&r->upstream->headers_in.headers);
1025 if (h == NULL) {
1026 return NGX_ERROR;
1027 }
1028
1029 h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(
1030 ngx_hash('x', '-'), 'a'), 'c'), 'c'), 'e'), 'l'), '-'), 'r'), 'e'), 'd'), 'i'), 'r'), 'e'), 'c'), 't');
1031
1032 h->key.len = sizeof("X-Accel-Redirect") - 1;
1033 h->key.data = (u_char *) "X-Accel-Redirect";
1034 h->value = mgcf->fetch_location;
1035 h->lowcase_key = (u_char *) "x-accel-redirect";
1036
1037 hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1038 h->lowcase_key, h->key.len);
1039
1040 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1041 return NGX_ERROR;
1042 }
1043 }
1044
1045 r->headers_out.content_length_n = 0;
1046 u->headers_in.status_n = 200;
1047 u->state->status = 200;
1048
1049 // Return no content
1050 u->buffer.pos = u->buffer.pos;
1051
1052 return NGX_OK;
1053 }
1054
1055 static ngx_int_t
ngx_http_mogilefs_process_error_response(ngx_http_request_t * r,ngx_http_upstream_t * u,ngx_str_t * line)1056 ngx_http_mogilefs_process_error_response(ngx_http_request_t *r,
1057 ngx_http_upstream_t *u, ngx_str_t *line)
1058 {
1059 ngx_http_mogilefs_error_t *e;
1060 ngx_http_mogilefs_ctx_t *ctx;
1061
1062 line->data += sizeof("ERR ") - 1;
1063 line->len -= sizeof("ERR ") - 1;
1064
1065 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1066 "mogilefs error: \"%V\"", line);
1067
1068 e = ngx_http_mogilefs_errors;
1069
1070 while(e->name.data != NULL) {
1071 if(line->len >= e->name.len &&
1072 ngx_strncmp(line->data, e->name.data, e->name.len) == 0)
1073 {
1074 break;
1075 }
1076
1077 e++;
1078 }
1079
1080 ctx = ngx_http_get_module_ctx(r, ngx_http_mogilefs_module);
1081
1082 /*
1083 * Convert unknown_key response to delete into No content
1084 */
1085 if(ctx->cmd->method & NGX_HTTP_DELETE && e->delete_ok) {
1086 r->headers_out.content_length_n = 0;
1087 u->headers_in.status_n = NGX_HTTP_NO_CONTENT;
1088 u->state->status = NGX_HTTP_NO_CONTENT;
1089
1090 // Return no content
1091 u->buffer.pos = u->buffer.pos;
1092
1093 return NGX_OK;
1094 }
1095
1096 r->headers_out.content_length_n = 0;
1097 u->headers_in.status_n = e->status;
1098 u->state->status = e->status;
1099 ctx->status = e->status;
1100
1101 // Return no content
1102 u->buffer.pos = u->buffer.pos;
1103
1104 return NGX_OK;
1105 }
1106
1107 static ngx_int_t
ngx_http_mogilefs_add_aux_param(ngx_http_request_t * r,ngx_str_t * name,ngx_str_t * value)1108 ngx_http_mogilefs_add_aux_param(ngx_http_request_t *r, ngx_str_t *name, ngx_str_t *value)
1109 {
1110 ngx_http_mogilefs_ctx_t *ctx;
1111 ngx_http_mogilefs_aux_param_t *p;
1112
1113 ctx = ngx_http_get_module_ctx(r, ngx_http_mogilefs_module);
1114 if(ctx == NULL) {
1115 return NGX_ERROR;
1116 }
1117
1118 if(ctx->aux_params == NULL) {
1119 ctx->aux_params = ngx_array_create(r->pool, 3, sizeof(ngx_http_mogilefs_aux_param_t));
1120
1121 if(ctx->aux_params == NULL) {
1122 return NGX_ERROR;
1123 }
1124 }
1125
1126 p = ngx_array_push(ctx->aux_params);
1127 if (p == NULL) {
1128 return NGX_ERROR;
1129 }
1130
1131 p->name = *name;
1132 p->value = *value;
1133
1134 return NGX_OK;
1135 }
1136
1137 static ngx_int_t
ngx_http_mogilefs_parse_param(ngx_http_request_t * r,ngx_str_t * param)1138 ngx_http_mogilefs_parse_param(ngx_http_request_t *r, ngx_str_t *param) {
1139 u_char *p, *src, *dst;
1140
1141 ngx_str_t name;
1142 ngx_str_t value;
1143
1144 ngx_http_mogilefs_ctx_t *ctx;
1145 ngx_http_mogilefs_src_t *source;
1146
1147 p = (u_char *) ngx_strchr(param->data, '=');
1148
1149 if(p == NULL) {
1150 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1151 "mogilefs tracker has sent invalid param: \"%V\"", param);
1152 return NGX_ERROR;
1153 }
1154
1155 name.data = param->data;
1156 name.len = p - param->data;
1157
1158 value.data = p + 1;
1159 value.len = param->len - (p - param->data) - 1;
1160
1161 src = dst = value.data;
1162
1163 ngx_unescape_uri(&dst, &src, value.len, NGX_UNESCAPE_URI);
1164
1165 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1166 "mogilefs param: \"%V\"=\"%V\"", &name, &value);
1167
1168 ctx = ngx_http_get_module_ctx(r, ngx_http_mogilefs_module);
1169
1170 if(name.len == sizeof("path") - 1
1171 && ngx_strncmp(name.data, "path", sizeof("path") - 1) == 0)
1172 {
1173 source = ngx_array_push(&ctx->sources);
1174
1175 if(source == NULL) {
1176 return NGX_ERROR;
1177 }
1178
1179 source->priority = 0;
1180 source->path = value;
1181
1182 if(ngx_http_mogilefs_add_aux_param(r, &name, &value) != NGX_OK) {
1183 return NGX_ERROR;
1184 }
1185 }
1186 else if(name.len >= ctx->cmd->output_param.len
1187 && ngx_strncmp(name.data, ctx->cmd->output_param.data, ctx->cmd->output_param.len) == 0
1188 && ngx_atoi(name.data + ctx->cmd->output_param.len, name.len - ctx->cmd->output_param.len) != NGX_ERROR)
1189 {
1190 source = ngx_array_push(&ctx->sources);
1191
1192 if(source == NULL) {
1193 return NGX_ERROR;
1194 }
1195
1196 source->priority = ngx_atoi(name.data + ctx->cmd->output_param.len, name.len - ctx->cmd->output_param.len);
1197 source->path = value;
1198 }
1199 else if(name.len == ctx->cmd->output_count_param.len &&
1200 ngx_strncmp(name.data, ctx->cmd->output_count_param.data, ctx->cmd->output_count_param.len) == 0)
1201 {
1202 ctx->num_paths_returned = ngx_atoi(value.data, value.len);
1203 }
1204 else {
1205 if(ngx_http_mogilefs_add_aux_param(r, &name, &value) != NGX_OK) {
1206 return NGX_ERROR;
1207 }
1208 }
1209
1210 return NGX_OK;
1211 }
1212
1213 static ngx_int_t
ngx_http_mogilefs_process_header(ngx_http_request_t * r)1214 ngx_http_mogilefs_process_header(ngx_http_request_t *r)
1215 {
1216 u_char *p;
1217 ngx_str_t line;
1218 ngx_http_upstream_t *u;
1219
1220 u = r->upstream;
1221
1222 for (p = u->buffer.pos; p < u->buffer.last; p++) {
1223 if (*p == LF) {
1224 goto found;
1225 }
1226 }
1227
1228 return NGX_AGAIN;
1229 found:
1230
1231 line.len = p - u->buffer.pos;
1232 line.data = u->buffer.pos;
1233
1234 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1235 "mogilefs: \"%V\"", &line);
1236
1237 if (line.len >= sizeof("ERR ") - 1 &&
1238 ngx_strncmp(line.data, "ERR ", sizeof("ERR ") - 1) == 0)
1239 {
1240 return ngx_http_mogilefs_process_error_response(r, u, &line);
1241 }
1242
1243 if (line.len >= sizeof("OK ") - 1 &&
1244 ngx_strncmp(line.data, "OK ", sizeof("OK ") - 1) == 0)
1245 {
1246 return ngx_http_mogilefs_process_ok_response(r, u, &line);
1247 }
1248
1249 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1250 "mogilefs tracker has sent invalid response: \"%V\"", &line);
1251
1252 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1253 }
1254
1255 static void
ngx_http_mogilefs_abort_request(ngx_http_request_t * r)1256 ngx_http_mogilefs_abort_request(ngx_http_request_t *r)
1257 {
1258 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1259 "abort mogilefs request");
1260 return;
1261 }
1262
1263 static void
ngx_http_mogilefs_finalize_request(ngx_http_request_t * r,ngx_int_t rc)1264 ngx_http_mogilefs_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
1265 {
1266 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1267 "finalize mogilefs request");
1268 return;
1269 }
1270
1271 static ngx_int_t
ngx_http_mogilefs_filter_init(void * data)1272 ngx_http_mogilefs_filter_init(void *data)
1273 {
1274 return NGX_OK;
1275 }
1276
1277 static ngx_int_t
ngx_http_mogilefs_filter(void * data,ssize_t bytes)1278 ngx_http_mogilefs_filter(void *data, ssize_t bytes)
1279 {
1280 return NGX_OK;
1281 }
1282
1283 static void *
ngx_http_mogilefs_create_loc_conf(ngx_conf_t * cf)1284 ngx_http_mogilefs_create_loc_conf(ngx_conf_t *cf)
1285 {
1286 ngx_http_mogilefs_loc_conf_t *conf;
1287
1288 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_mogilefs_loc_conf_t));
1289
1290 if (conf == NULL) {
1291 return NGX_CONF_ERROR;
1292 }
1293
1294 conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
1295 conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
1296 conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
1297
1298 conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
1299
1300 /* the hardcoded values */
1301 conf->upstream.cyclic_temp_file = 0;
1302 conf->upstream.buffering = 0;
1303 conf->upstream.ignore_client_abort = 0;
1304 conf->upstream.send_lowat = 0;
1305 conf->upstream.bufs.num = 0;
1306 conf->upstream.busy_buffers_size = 0;
1307 conf->upstream.max_temp_file_size = 0;
1308 conf->upstream.temp_file_write_size = 0;
1309 conf->upstream.intercept_errors = 1;
1310 conf->upstream.intercept_404 = 1;
1311 conf->upstream.pass_request_headers = 0;
1312 conf->upstream.pass_request_body = 0;
1313
1314 conf->noverify = NGX_CONF_UNSET;
1315 conf->methods = 0;
1316
1317 return conf;
1318 }
1319
1320 static char *
ngx_http_mogilefs_merge_loc_conf(ngx_conf_t * cf,void * parent,void * child)1321 ngx_http_mogilefs_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
1322 {
1323 ngx_http_mogilefs_loc_conf_t *prev = parent;
1324 ngx_http_mogilefs_loc_conf_t *conf = child;
1325
1326 ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
1327 prev->upstream.connect_timeout, 60000);
1328
1329 ngx_conf_merge_msec_value(conf->upstream.send_timeout,
1330 prev->upstream.send_timeout, 60000);
1331
1332 ngx_conf_merge_msec_value(conf->upstream.read_timeout,
1333 prev->upstream.read_timeout, 60000);
1334
1335 ngx_conf_merge_size_value(conf->upstream.buffer_size,
1336 prev->upstream.buffer_size,
1337 (size_t) ngx_pagesize);
1338
1339 ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
1340 prev->upstream.next_upstream,
1341 (NGX_CONF_BITMASK_SET
1342 |NGX_HTTP_UPSTREAM_FT_ERROR
1343 |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
1344
1345 if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
1346 conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
1347 |NGX_HTTP_UPSTREAM_FT_OFF;
1348 }
1349
1350 if (conf->upstream.upstream == NULL) {
1351 conf->upstream.upstream = prev->upstream.upstream;
1352 }
1353
1354 ngx_conf_merge_str_value(conf->domain, prev->domain, "default");
1355
1356 ngx_conf_merge_value(conf->noverify, prev->noverify, 0);
1357
1358 ngx_conf_merge_bitmask_value(conf->methods, prev->methods,
1359 (NGX_CONF_BITMASK_SET|NGX_HTTP_GET));
1360
1361 if(conf->methods & NGX_HTTP_GET) {
1362 conf->methods |= NGX_HTTP_HEAD;
1363 }
1364
1365 if(conf->class_templates == NULL) {
1366 conf->class_templates = prev->class_templates;
1367 }
1368
1369 return NGX_CONF_OK;
1370 }
1371
ngx_http_mogilefs_add_variables(ngx_conf_t * cf)1372 static ngx_int_t ngx_http_mogilefs_add_variables(ngx_conf_t *cf)
1373 {
1374 ngx_uint_t i;
1375 ngx_http_variable_t *var, *v;
1376 ngx_str_t name;
1377
1378 /*
1379 * Add 10 instances of mogilefs_path variable with
1380 * different names
1381 */
1382 v = &ngx_http_mogilefs_path_variable_template;
1383
1384 for(i=0;i<NGX_MOGILEFS_MAX_PATHS;i++) {
1385 name.data = v->name.data;
1386 name.len = v->name.len - 1;
1387
1388 if(i > 0) {
1389 name.data[name.len] = '0' + i;
1390 name.len++;
1391 }
1392
1393 var = ngx_http_add_variable(cf, &name, v->flags);
1394 if (var == NULL) {
1395 return NGX_ERROR;
1396 }
1397
1398 var->get_handler = v->get_handler;
1399 var->data = v->data;
1400 }
1401
1402 return NGX_OK;
1403 }
1404
ngx_http_mogilefs_path_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)1405 static ngx_int_t ngx_http_mogilefs_path_variable(ngx_http_request_t *r,
1406 ngx_http_variable_value_t *v, uintptr_t data)
1407 {
1408 v->valid = 1;
1409 v->no_cacheable = 0;
1410 v->not_found = 0;
1411
1412 v->len = 0;
1413 v->data = (u_char*)"";
1414
1415 return NGX_OK;
1416 }
1417
1418 static char *
ngx_http_mogilefs_tracker_command(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)1419 ngx_http_mogilefs_tracker_command(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1420 {
1421 ngx_http_mogilefs_loc_conf_t *mgcf = conf;
1422 ngx_str_t *value;
1423 ngx_url_t u;
1424 ngx_uint_t n;
1425 ngx_http_script_compile_t sc;
1426
1427 if (mgcf->upstream.upstream || mgcf->tracker_lengths) {
1428 return "is duplicate";
1429 }
1430
1431 value = cf->args->elts;
1432
1433 n = ngx_http_script_variables_count(&value[1]);
1434
1435 if(n) {
1436 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
1437
1438 sc.cf = cf;
1439 sc.source = &value[1];
1440 sc.lengths = &mgcf->tracker_lengths;
1441 sc.values = &mgcf->tracker_values;
1442 sc.variables = n;
1443 sc.complete_lengths = 1;
1444 sc.complete_values = 1;
1445
1446 if (ngx_http_script_compile(&sc) != NGX_OK) {
1447 return NGX_CONF_ERROR;
1448 }
1449
1450 return NGX_CONF_OK;
1451 }
1452
1453 ngx_memzero(&u, sizeof(ngx_url_t));
1454
1455 u.url = value[1];
1456 u.no_resolve = 1;
1457 u.default_port = 6001;
1458
1459 mgcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
1460 if (mgcf->upstream.upstream == NULL) {
1461 return NGX_CONF_ERROR;
1462 }
1463
1464 return NGX_CONF_OK;
1465 }
1466
1467 static char *
ngx_http_mogilefs_class_command(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)1468 ngx_http_mogilefs_class_command(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1469 {
1470 ngx_http_mogilefs_loc_conf_t *mgcf = conf;
1471 ngx_http_mogilefs_class_template_t *t;
1472 ngx_str_t *value;
1473 ngx_uint_t i, n;
1474 ngx_http_script_compile_t sc;
1475
1476 if(mgcf->class_templates == NULL) {
1477 mgcf->class_templates = ngx_array_create(cf->pool, cf->args->nelts,
1478 sizeof(ngx_http_mogilefs_class_template_t));
1479
1480 if(mgcf->class_templates == NULL) {
1481 return NGX_CONF_ERROR;
1482 }
1483 }
1484
1485 value = cf->args->elts;
1486
1487 for(i = 1;i < cf->args->nelts;i++) {
1488 t = ngx_array_push(mgcf->class_templates);
1489
1490 if(t == NULL) {
1491 return NGX_CONF_ERROR;
1492 }
1493
1494 t->source = value[i];
1495 t->lengths = NULL;
1496 t->values = NULL;
1497
1498 n = ngx_http_script_variables_count(&t->source);
1499
1500 if(n) {
1501 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
1502
1503 sc.cf = cf;
1504 sc.source = &value[i];
1505 sc.lengths = &t->lengths;
1506 sc.values = &t->values;
1507 sc.variables = n;
1508 sc.complete_lengths = 1;
1509 sc.complete_values = 1;
1510
1511 if (ngx_http_script_compile(&sc) != NGX_OK) {
1512 return NGX_CONF_ERROR;
1513 }
1514 }
1515 }
1516
1517 return NGX_CONF_OK;
1518 }
1519
1520 static char*
ngx_http_mogilefs_create_spare_location(ngx_conf_t * cf,ngx_http_conf_ctx_t ** octx,ngx_str_t * name,ngx_http_mogilefs_location_type_t location_type)1521 ngx_http_mogilefs_create_spare_location(ngx_conf_t *cf, ngx_http_conf_ctx_t **octx, ngx_str_t *name,
1522 ngx_http_mogilefs_location_type_t location_type)
1523 {
1524 ngx_http_mogilefs_loc_conf_t *mgcf, *pmgcf;
1525 ngx_http_conf_ctx_t *ctx, *pctx = cf->ctx;
1526 ngx_uint_t i;
1527 ngx_http_module_t *module;
1528 void *mconf;
1529 ngx_http_core_loc_conf_t *clcf, *pclcf, *rclcf;
1530 ngx_http_core_srv_conf_t *cscf;
1531
1532 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
1533 if (ctx == NULL) {
1534 return NGX_CONF_ERROR;
1535 }
1536
1537 pctx = cf->ctx;
1538 ctx->main_conf = pctx->main_conf;
1539 ctx->srv_conf = pctx->srv_conf;
1540
1541 ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
1542 if (ctx->loc_conf == NULL) {
1543 return NGX_CONF_ERROR;
1544 }
1545
1546 for (i = 0; ngx_modules[i]; i++) {
1547 if (ngx_modules[i]->type != NGX_HTTP_MODULE) {
1548 continue;
1549 }
1550
1551 module = ngx_modules[i]->ctx;
1552
1553 if (module->create_loc_conf) {
1554
1555 mconf = module->create_loc_conf(cf);
1556 if (mconf == NULL) {
1557 return NGX_CONF_ERROR;
1558 }
1559
1560 ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf;
1561 }
1562 }
1563
1564 pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
1565
1566 clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
1567
1568 mgcf = ctx->loc_conf[ngx_http_mogilefs_module.ctx_index];
1569
1570 mgcf->location_type = location_type;
1571
1572 if(location_type != NGX_MOGILEFS_FETCH) {
1573 pmgcf = pctx->loc_conf[ngx_http_mogilefs_module.ctx_index];
1574
1575 mgcf->methods = NGX_HTTP_PUT;
1576
1577 /*
1578 * Copy tracker configuration
1579 */
1580 mgcf->tracker_lengths = pmgcf->tracker_lengths;
1581 mgcf->tracker_values = pmgcf->tracker_values;
1582
1583 mgcf->parent = pmgcf;
1584
1585 ngx_memcpy(&mgcf->upstream, &pmgcf->upstream, sizeof(ngx_http_upstream_conf_t));
1586
1587 ngx_memcpy(mgcf->index, pmgcf->index, NGX_MOGILEFS_MAX_PATHS * sizeof(ngx_int_t));
1588
1589 clcf->handler = ngx_http_mogilefs_handler;
1590 }
1591
1592 name->len = sizeof("/mogstored_spare_") - 1 + NGX_OFF_T_LEN + 1;
1593
1594 name->data = ngx_palloc(cf->pool, name->len);
1595
1596 if(name->data == NULL) {
1597 return NGX_CONF_ERROR;
1598 }
1599
1600 name->len = ngx_sprintf(name->data, "/mogstored_spare_%O/", (off_t)(uintptr_t)clcf) - name->data;
1601
1602 clcf->loc_conf = ctx->loc_conf;
1603 clcf->name = *name;
1604 clcf->exact_match = 0;
1605 clcf->noname = 0;
1606 clcf->internal = 1;
1607 clcf->noregex = 1;
1608
1609 cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module);
1610
1611 rclcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index];
1612
1613 if (ngx_http_add_location(cf, &rclcf->locations, clcf) != NGX_OK) {
1614 return NGX_CONF_ERROR;
1615 }
1616
1617 if(octx != NULL) {
1618 *octx = ctx;
1619 }
1620
1621 return NGX_CONF_OK;
1622 }
1623
1624 static char *
ngx_http_mogilefs_pass_block(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)1625 ngx_http_mogilefs_pass_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1626 {
1627 ngx_http_mogilefs_loc_conf_t *pmgcf = conf;
1628 ngx_http_core_loc_conf_t *pclcf;
1629 ngx_http_conf_ctx_t *ctx;
1630 char *rv;
1631 ngx_str_t *value;
1632 ngx_conf_t save;
1633 ngx_http_script_compile_t sc;
1634 ngx_uint_t n, i;
1635 char *rc;
1636 ngx_str_t name;
1637
1638 if (pmgcf->fetch_location.len != 0) {
1639 return "is duplicate";
1640 }
1641
1642 if (pmgcf->upstream.upstream == 0 && pmgcf->tracker_lengths == NULL) {
1643 return "no tracker defined";
1644 }
1645
1646 for(i=0;i < NGX_MOGILEFS_MAX_PATHS;i++) {
1647 name.data = ngx_http_mogilefs_path.data;
1648 name.len = ngx_http_mogilefs_path.len - 1;
1649
1650 if(i > 0) {
1651 name.data[name.len] = '0' + i;
1652 name.len++;
1653 }
1654
1655 pmgcf->index[i] = ngx_http_get_variable_index(cf, &name);
1656
1657 if (pmgcf->index[i] == NGX_ERROR) {
1658 return NGX_CONF_ERROR;
1659 }
1660 }
1661
1662 rc = ngx_http_mogilefs_create_spare_location(cf, NULL, &pmgcf->create_open_spare_location,
1663 NGX_MOGILEFS_CREATE_OPEN);
1664
1665 if(rc != NGX_CONF_OK) {
1666 return rc;
1667 }
1668
1669 rc = ngx_http_mogilefs_create_spare_location(cf, &ctx, &pmgcf->fetch_location,
1670 NGX_MOGILEFS_FETCH);
1671
1672 if(rc != NGX_CONF_OK) {
1673 return rc;
1674 }
1675
1676 rc = ngx_http_mogilefs_create_spare_location(cf, NULL, &pmgcf->create_close_spare_location,
1677 NGX_MOGILEFS_CREATE_CLOSE);
1678
1679 if(rc != NGX_CONF_OK) {
1680 return rc;
1681 }
1682
1683 pmgcf->location_type = NGX_MOGILEFS_MAIN;
1684
1685 pclcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
1686 pclcf->handler = ngx_http_mogilefs_handler;
1687
1688 if(cf->args->nelts > 1) {
1689 value = cf->args->elts;
1690
1691 pmgcf->key = value[1];
1692
1693 n = ngx_http_script_variables_count(&pmgcf->key);
1694
1695 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
1696
1697 sc.cf = cf;
1698 sc.source = &pmgcf->key;
1699 sc.lengths = &pmgcf->key_lengths;
1700 sc.values = &pmgcf->key_values;
1701 sc.variables = n;
1702 sc.complete_lengths = 1;
1703 sc.complete_values = 1;
1704
1705 if (ngx_http_script_compile(&sc) != NGX_OK) {
1706 return NGX_CONF_ERROR;
1707 }
1708 }
1709
1710 save = *cf;
1711 cf->ctx = ctx;
1712 cf->cmd_type = NGX_HTTP_LOC_CONF;
1713
1714 rv = ngx_conf_parse(cf, NULL);
1715
1716 *cf = save;
1717
1718 return rv;
1719 }
1720
1721 static ngx_int_t
ngx_http_mogilefs_init(ngx_conf_t * cf)1722 ngx_http_mogilefs_init(ngx_conf_t *cf)
1723 {
1724 ngx_http_handler_pt *h;
1725 ngx_http_core_main_conf_t *cmcf;
1726
1727 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
1728
1729 h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
1730 if (h == NULL) {
1731 return NGX_ERROR;
1732 }
1733
1734 *h = ngx_http_mogilefs_put_handler;
1735
1736 return NGX_OK;
1737 }
1738