src/http/modules/ngx_http_mirror_module.c - nginx source code

Global variables defined

Data types defined

Functions defined

Source code


  1. /*
  2. * Copyright (C) Roman Arutyunyan
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>


  8. typedef struct {
  9.     ngx_array_t  *mirror;
  10.     ngx_flag_t    request_body;
  11. } ngx_http_mirror_loc_conf_t;


  12. typedef struct {
  13.     ngx_int_t     status;
  14. } ngx_http_mirror_ctx_t;


  15. static ngx_int_t ngx_http_mirror_handler(ngx_http_request_t *r);
  16. static void ngx_http_mirror_body_handler(ngx_http_request_t *r);
  17. static ngx_int_t ngx_http_mirror_handler_internal(ngx_http_request_t *r);
  18. static void *ngx_http_mirror_create_loc_conf(ngx_conf_t *cf);
  19. static char *ngx_http_mirror_merge_loc_conf(ngx_conf_t *cf, void *parent,
  20.     void *child);
  21. static char *ngx_http_mirror(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
  22. static ngx_int_t ngx_http_mirror_init(ngx_conf_t *cf);


  23. static ngx_command_t  ngx_http_mirror_commands[] = {

  24.     { ngx_string("mirror"),
  25.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  26.       ngx_http_mirror,
  27.       NGX_HTTP_LOC_CONF_OFFSET,
  28.       0,
  29.       NULL },

  30.     { ngx_string("mirror_request_body"),
  31.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  32.       ngx_conf_set_flag_slot,
  33.       NGX_HTTP_LOC_CONF_OFFSET,
  34.       offsetof(ngx_http_mirror_loc_conf_t, request_body),
  35.       NULL },

  36.       ngx_null_command
  37. };


  38. static ngx_http_module_t  ngx_http_mirror_module_ctx = {
  39.     NULL,                                  /* preconfiguration */
  40.     ngx_http_mirror_init,                  /* postconfiguration */

  41.     NULL,                                  /* create main configuration */
  42.     NULL,                                  /* init main configuration */

  43.     NULL,                                  /* create server configuration */
  44.     NULL,                                  /* merge server configuration */

  45.     ngx_http_mirror_create_loc_conf,       /* create location configuration */
  46.     ngx_http_mirror_merge_loc_conf         /* merge location configuration */
  47. };


  48. ngx_module_t  ngx_http_mirror_module = {
  49.     NGX_MODULE_V1,
  50.     &ngx_http_mirror_module_ctx,           /* module context */
  51.     ngx_http_mirror_commands,              /* module directives */
  52.     NGX_HTTP_MODULE,                       /* module type */
  53.     NULL,                                  /* init master */
  54.     NULL,                                  /* init module */
  55.     NULL,                                  /* init process */
  56.     NULL,                                  /* init thread */
  57.     NULL,                                  /* exit thread */
  58.     NULL,                                  /* exit process */
  59.     NULL,                                  /* exit master */
  60.     NGX_MODULE_V1_PADDING
  61. };


  62. static ngx_int_t
  63. ngx_http_mirror_handler(ngx_http_request_t *r)
  64. {
  65.     ngx_int_t                    rc;
  66.     ngx_http_mirror_ctx_t       *ctx;
  67.     ngx_http_mirror_loc_conf_t  *mlcf;

  68.     if (r != r->main) {
  69.         return NGX_DECLINED;
  70.     }

  71.     mlcf = ngx_http_get_module_loc_conf(r, ngx_http_mirror_module);

  72.     if (mlcf->mirror == NULL) {
  73.         return NGX_DECLINED;
  74.     }

  75.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "mirror handler");

  76.     if (mlcf->request_body) {
  77.         ctx = ngx_http_get_module_ctx(r, ngx_http_mirror_module);

  78.         if (ctx) {
  79.             return ctx->status;
  80.         }

  81.         ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_mirror_ctx_t));
  82.         if (ctx == NULL) {
  83.             return NGX_ERROR;
  84.         }

  85.         ctx->status = NGX_DONE;

  86.         ngx_http_set_ctx(r, ctx, ngx_http_mirror_module);

  87.         rc = ngx_http_read_client_request_body(r, ngx_http_mirror_body_handler);
  88.         if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  89.             return rc;
  90.         }

  91.         ngx_http_finalize_request(r, NGX_DONE);
  92.         return NGX_DONE;
  93.     }

  94.     return ngx_http_mirror_handler_internal(r);
  95. }


  96. static void
  97. ngx_http_mirror_body_handler(ngx_http_request_t *r)
  98. {
  99.     ngx_http_mirror_ctx_t  *ctx;

  100.     ctx = ngx_http_get_module_ctx(r, ngx_http_mirror_module);

  101.     ctx->status = ngx_http_mirror_handler_internal(r);

  102.     r->preserve_body = 1;

  103.     r->write_event_handler = ngx_http_core_run_phases;
  104.     ngx_http_core_run_phases(r);
  105. }


  106. static ngx_int_t
  107. ngx_http_mirror_handler_internal(ngx_http_request_t *r)
  108. {
  109.     ngx_str_t                   *name;
  110.     ngx_uint_t                   i;
  111.     ngx_http_request_t          *sr;
  112.     ngx_http_mirror_loc_conf_t  *mlcf;

  113.     mlcf = ngx_http_get_module_loc_conf(r, ngx_http_mirror_module);

  114.     name = mlcf->mirror->elts;

  115.     for (i = 0; i < mlcf->mirror->nelts; i++) {
  116.         if (ngx_http_subrequest(r, &name[i], &r->args, &sr, NULL,
  117.                                 NGX_HTTP_SUBREQUEST_BACKGROUND)
  118.             != NGX_OK)
  119.         {
  120.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  121.         }

  122.         sr->header_only = 1;
  123.         sr->method = r->method;
  124.         sr->method_name = r->method_name;
  125.     }

  126.     return NGX_DECLINED;
  127. }


  128. static void *
  129. ngx_http_mirror_create_loc_conf(ngx_conf_t *cf)
  130. {
  131.     ngx_http_mirror_loc_conf_t  *mlcf;

  132.     mlcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_mirror_loc_conf_t));
  133.     if (mlcf == NULL) {
  134.         return NULL;
  135.     }

  136.     mlcf->mirror = NGX_CONF_UNSET_PTR;
  137.     mlcf->request_body = NGX_CONF_UNSET;

  138.     return mlcf;
  139. }


  140. static char *
  141. ngx_http_mirror_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
  142. {
  143.     ngx_http_mirror_loc_conf_t *prev = parent;
  144.     ngx_http_mirror_loc_conf_t *conf = child;

  145.     ngx_conf_merge_ptr_value(conf->mirror, prev->mirror, NULL);
  146.     ngx_conf_merge_value(conf->request_body, prev->request_body, 1);

  147.     return NGX_CONF_OK;
  148. }


  149. static char *
  150. ngx_http_mirror(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  151. {
  152.     ngx_http_mirror_loc_conf_t *mlcf = conf;

  153.     ngx_str_t  *value, *s;

  154.     value = cf->args->elts;

  155.     if (ngx_strcmp(value[1].data, "off") == 0) {
  156.         if (mlcf->mirror != NGX_CONF_UNSET_PTR) {
  157.             return "is duplicate";
  158.         }

  159.         mlcf->mirror = NULL;
  160.         return NGX_CONF_OK;
  161.     }

  162.     if (mlcf->mirror == NULL) {
  163.         return "is duplicate";
  164.     }

  165.     if (mlcf->mirror == NGX_CONF_UNSET_PTR) {
  166.         mlcf->mirror = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
  167.         if (mlcf->mirror == NULL) {
  168.             return NGX_CONF_ERROR;
  169.         }
  170.     }

  171.     s = ngx_array_push(mlcf->mirror);
  172.     if (s == NULL) {
  173.         return NGX_CONF_ERROR;
  174.     }

  175.     *s = value[1];

  176.     return NGX_CONF_OK;
  177. }


  178. static ngx_int_t
  179. ngx_http_mirror_init(ngx_conf_t *cf)
  180. {
  181.     ngx_http_handler_pt        *h;
  182.     ngx_http_core_main_conf_t  *cmcf;

  183.     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);

  184.     h = ngx_array_push(&cmcf->phases[NGX_HTTP_PRECONTENT_PHASE].handlers);
  185.     if (h == NULL) {
  186.         return NGX_ERROR;
  187.     }

  188.     *h = ngx_http_mirror_handler;

  189.     return NGX_OK;
  190. }