static ngx_int_t
ngx_http_data_dome_auth_handler(ngx_http_request_t *r)
{
    ngx_buf_t                       *b;
    ngx_int_t                        rc;
    ngx_str_t                        val;
    ngx_str_t                        x_datadome_response;
    ngx_uint_t                       i;
    ngx_chain_t                      out;
    ngx_list_part_t                 *part;
    ngx_table_elt_t                 *header;
    ngx_table_elt_t                 *location;
    ngx_http_data_dome_auth_ctx_t   *ctx;
    ngx_http_data_dome_auth_conf_t  *acf;

    // you can dissable this module in location or if level
    acf = ngx_http_get_module_loc_conf(r, ngx_http_data_dome_auth_module);

    if (acf->uri_lengths == NULL) {
  return NGX_DECLINED;
    }

    if (r->internal && acf->pass_internal_redirect) {
  return NGX_DECLINED;
    }

    // but module use main request context to keep the status
    // to prevent duplicated query to API server
    ctx = ngx_http_get_module_ctx(r->main, ngx_http_data_dome_auth_module);

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->main->connection->log, 0,
		   "Data Dome auth request handler, ctx: %p", ctx);

    if (ctx != NULL) {
    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->main->connection->log, 0,
		   "Data Dome auth request handler ctx: declined %d, processing: %d, done: %d",
		    ctx->declined, ctx->processing, ctx->done);

	if (ctx->declined) {
	    return NGX_DECLINED;
	}

	if (ctx->processing) {
	    return NGX_OK;
	}

	if (!ctx->done) {
	    return NGX_AGAIN;
	}

    if (ngx_http_data_dome_auth_set_variables(r, acf, ctx) != NGX_OK) {
        return NGX_ERROR;
    }

	if (acf->learning) {
	    return NGX_OK;
	}

    if (ctx->subrequest_rc < NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    x_datadome_response.len = 0;

    part = &ctx->subrequest->headers_out.headers.part;
    header = part->elts;

    for (i = 0; /* void */ ; i++) {

        if (i >= part->nelts) {
            if (part->next == NULL) {
                break;
            }

            part = part->next;
            header = part->elts;
            i = 0;
        }

        if (header[i].hash == 0) {
            continue;
        }

        if (header[i].key.len != sizeof("X-DataDomeResponse") - 1) {
            continue;
        }

        if (ngx_strncmp(header[i].key.data, "X-DataDomeResponse", header[i].key.len) != 0) {
            continue;
        }

        x_datadome_response = header[i].value;

        break;
    }

    if (x_datadome_response.len == 0) {
	    ngx_log_error(NGX_LOG_ERR, r->main->connection->log, 0, "API server response hasn't got X-DataDomeResponse");
	    return NGX_DECLINED;
    }

    if ((ngx_uint_t)ngx_atoi(x_datadome_response.data, x_datadome_response.len) != ctx->subrequest->headers_out.status) {
	    ngx_log_error(NGX_LOG_ERR, r->main->connection->log, 0, "API server response's X-DataDomeResponse (%V) != status (%d)",
	        &x_datadome_response, ctx->subrequest->headers_out.status);
	    return NGX_DECLINED;
    }

	if (ngx_http_data_dome_auth_execute_x_datadome_headers(r->main->pool, "X-DataDome-headers",
	                                                       &ctx->subrequest->headers_out.headers,
	                                                       &r->main->headers_out.headers) == NGX_ERROR) {
	    return NGX_ERROR;
	}

	if (ngx_http_data_dome_auth_execute_x_datadome_headers(r->main->pool, "X-DataDome-request-headers",
	                                                       &ctx->subrequest->headers_out.headers,
	                                                       &r->main->headers_in.headers) == NGX_ERROR) {
	    return NGX_ERROR;
	}

	switch (ctx->subrequest->headers_out.status) {
	case NGX_HTTP_MOVED_PERMANENTLY:
	case NGX_HTTP_MOVED_TEMPORARILY:
	case NGX_HTTP_UNAUTHORIZED:
	case NGX_HTTP_FORBIDDEN:

        part = &ctx->subrequest->headers_out.headers.part;
        header = part->elts;

        for (i = 0; /* void */ ; i++) {

            if (i >= part->nelts) {
                if (part->next == NULL) {
                  break;
                }

                part = part->next;
                header = part->elts;
                i = 0;
            }

            if (header[i].hash == 0) {
                continue;
            }

            if (header[i].key.len != sizeof("Location") - 1) {
                continue;
            }

            if (ngx_strncmp(header[i].key.data, "Location", header[i].key.len) != 0) {
                continue;
            }

            location = ngx_list_push(&r->main->headers_out.headers);
            if (location == NULL) {
              return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }

            location->hash = 1;
            location->key = header[i].key;
            location->lowcase_key = header[i].lowcase_key;
            location->value = header[i].value;

            break;
        }

	    // nginx reset upstream buffer length, so, use body lenght from header ;)
	    val.len = ctx->subrequest->headers_out.content_length_n;
	    val.data = ctx->subrequest->upstream->buffer.pos;

	    // if response hasn't Content-Length and body the length was -1, fix it
	    if (ctx->subrequest->headers_out.content_length_n < 0) {
	      val.len = 0;
	    }

	    if (val.len == 0) {
    	    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
	    		   "Data Dome auth send response without body: s: %d",
		    	   ctx->subrequest->headers_out.status);
            return ctx->subrequest->headers_out.status;
	    }

	    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
			   "Data Dome auth send response: s: %d, c: %V, b: %V",
			   ctx->subrequest->headers_out.status, &ctx->subrequest->headers_out.content_type, &val);

        r->headers_out.status = ctx->subrequest->headers_out.status;

        r->headers_out.content_length_n = val.len;

        if (ctx->subrequest->headers_out.content_type.len) {
            r->headers_out.content_type_len = ctx->subrequest->headers_out.content_type.len;
            r->headers_out.content_type = ctx->subrequest->headers_out.content_type;
        } else {
            if (ngx_http_set_content_type(r) != NGX_OK) {
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }
        }

        if (r->method == NGX_HTTP_HEAD || val.len == 0) {
            rc = ngx_http_send_header(r);
            if (rc != NGX_OK) {
                return rc;
            }

            return NGX_DONE;
        }

        b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
        if (b == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
        b->pos = val.data;
        b->last = val.data + val.len;
        b->memory = val.len ? 1 : 0;
        b->last_buf = (r == r->main) ? 1 : 0;
        b->last_in_chain = 1;

        out.buf = b;
        out.next = NULL;

        rc = ngx_http_send_header(r);

        if (rc == NGX_ERROR || rc > NGX_OK) {
            return rc;
        }

        if (r->header_only) {
            ngx_http_finalize_request(r, NGX_DONE);
            return NGX_DONE;
        }

        rc = ngx_http_output_filter(r, &out);
	    if (rc != NGX_OK) {
	      return rc;
	    }

        ngx_http_finalize_request(r, NGX_DONE);
	    return NGX_DONE;

	case NGX_HTTP_OK:

	    return NGX_OK;

	default:

	    ngx_log_error(NGX_LOG_ERR, r->main->connection->log, 0,
			  "Data Dome auth request unexpected status: %d, pass", ctx->subrequest->headers_out.status);

	    return NGX_OK;
	}
    }

    ctx = ngx_pcalloc(r->main->pool, sizeof(ngx_http_data_dome_auth_ctx_t));
    if (ctx == NULL) {
	return NGX_ERROR;
    }

    if (ngx_http_script_run(r, &ctx->uri, acf->uri_lengths->elts, 0, acf->uri_values->elts)
        == NULL)
    {
        return NGX_ERROR;
    }

    if (ngx_strncmp(ctx->uri.data, "off", ctx->uri.len) == 0) {
	    return NGX_DECLINED;
    }

    ngx_http_set_ctx(r->main, ctx, ngx_http_data_dome_auth_module);

#if (NGX_PCRE)

    if (acf->uri_regex_exclusion) {
        if (ngx_regex_exec(acf->uri_regex_exclusion, &r->main->uri, NULL, 0) != NGX_REGEX_NO_MATCHED) {

            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->main->connection->log, 0,
                  "Data Dome auth URI regex exclusion: \"%V\" match with URI: %V",
                   &acf->uri_regex_exclusion_raw, &r->main->uri);

            ctx->declined = 1;
            return NGX_DECLINED;
        }
    }

    if (acf->uri_regex) {

	if (ngx_regex_exec(acf->uri_regex, &r->main->uri, NULL, 0) != NGX_REGEX_NO_MATCHED) {

	    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->main->connection->log, 0,
			  "Data Dome auth URI regex: \"%V\" match with URI: %V",
			   &acf->uri_regex_raw, &r->main->uri);

	    goto validate;
	}

	ctx->declined = 1;
	return NGX_DECLINED;
    }

 validate:

#endif

    ctx->processing = 1;

    // keep original read and write event handler because read client body may override it
    ctx->read_event_handler = r->main->read_event_handler;
    ctx->write_event_handler = r->main->write_event_handler;

    return ngx_http_data_dome_subrequest(r);
}
Ejemplo n.º 2
0
static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r)
{
  u_char                      *last;
  ngx_fd_t                     fd;
  ngx_int_t                    rc;
  ngx_uint_t                   level;
  ngx_str_t                    name, location;
  ngx_err_t                    err;
  ngx_log_t                   *log;
  ngx_buf_t                   *b;
  ngx_chain_t                  out;
  ngx_file_info_t              fi;
  ngx_http_cleanup_t          *file_cleanup, *redirect_cleanup;
  ngx_http_log_ctx_t          *ctx;
  ngx_http_core_loc_conf_t    *clcf;
  ngx_http_static_loc_conf_t  *slcf;
#if (NGX_HTTP_CACHE)
  uint32_t                     file_crc, redirect_crc;
  ngx_http_cache_t            *file, *redirect;
#endif

  if (r->uri.data[r->uri.len - 1] == '/') {
    return NGX_DECLINED;
  }

  if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
    return NGX_HTTP_NOT_ALLOWED;
  }

  rc = ngx_http_discard_body(r);

  if (rc != NGX_OK && rc != NGX_AGAIN) {
    return rc;
  }

#if (NGX_HTTP_CACHE)

  /*
   * there is a valid cached open file, i.e by the index handler,
   * and it should be already registered in r->cleanup
   */

  if (r->cache && !r->cache->expired) {
    return ngx_http_send_cached(r);
  }

#endif

  log = r->connection->log;

  clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  /*
   * make a file name, reserve 2 bytes for a trailing '/'
   * in a possible redirect and for the last '\0'
   */

  if (clcf->alias) {
    name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2
                    - clcf->name.len);
    if (name.data == NULL) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    last = ngx_cpymem(name.data, clcf->root.data, clcf->root.len);
    last = ngx_cpystrn(last, r->uri.data + clcf->name.len,
               r->uri.len + 1 - clcf->name.len);

    name.len = last - name.data;

    location.data = ngx_palloc(r->pool, r->uri.len + 2);
    if (location.data == NULL) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1);

#if 0
    /*
     * aliases usually have trailling "/",
     * set it in the start of the possible redirect
     */

    if (*location.data != '/') {
      location.data--;
    }
#endif

    location.len = last - location.data + 1;

  } else {
    name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2);
    if (name.data == NULL) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    location.data = ngx_cpymem(name.data, clcf->root.data, clcf->root.len);
    last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1);

    name.len = last - name.data;
    location.len = last - location.data + 1;
  }

  ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
           "http filename: \"%s\"", name.data);


  /* allocate cleanups */

  if (!(file_cleanup = ngx_push_array(&r->cleanup))) {
    return NGX_HTTP_INTERNAL_SERVER_ERROR;
  }
  file_cleanup->valid = 0;

  slcf = ngx_http_get_module_loc_conf(r, ngx_http_static_module);
  if (slcf->redirect_cache) {
    if (!(redirect_cleanup = ngx_push_array(&r->cleanup))) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    redirect_cleanup->valid = 0;

  } else {
    redirect_cleanup = NULL;
  }

#if (NGX_HTTP_CACHE)

  /* look up an open files cache */

  if (clcf->open_files) {
    file = ngx_http_cache_get(clcf->open_files, file_cleanup,
                  &name, &file_crc);

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
             "http open file cache get: " PTR_FMT, file);

    if (file && !file->expired) {
      r->cache = file;
      return ngx_http_send_cached(r);
    }

  } else {
    file = NULL;
  }


  /* look up an redirect cache */

  if (slcf->redirect_cache) {
    redirect = ngx_http_cache_get(slcf->redirect_cache, redirect_cleanup,
                    &name, &redirect_crc);

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
             "http redirect cache get: " PTR_FMT, redirect);

    if (redirect && !redirect->expired) {

      /*
       * We do not copy a cached value so the cache entry is locked
       * until the end of the request.  In a single threaded model
       * the redirected request should complete before other event
       * will be processed.  In a multithreaded model this locking
       * should keep more popular redirects in cache.
       */

      if (!(r->headers_out.location =
           ngx_http_add_header(&r->headers_out, ngx_http_headers_out)))
      {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
      }

      r->headers_out.location->value = redirect->data.value;

      return NGX_HTTP_MOVED_PERMANENTLY;
    }

  } else {
    redirect = NULL;
  }

#endif

  /* open file */

#if (WIN9X)

  /* TODO: redirect cache */

  if (ngx_win32_version < NGX_WIN_NT) {

    /*
     * there is no way to open a file or a directory in Win9X with
     * one syscall because Win9X has no FILE_FLAG_BACKUP_SEMANTICS flag
     * so we need to check its type before the opening
     */

    if (ngx_file_info(name.data, &fi) == NGX_FILE_ERROR) {
      err = ngx_errno;
      ngx_log_error(NGX_LOG_ERR, log, err,
              ngx_file_info_n " \"%s\" failed", name.data);

      if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
        return NGX_HTTP_NOT_FOUND;

      } else if (err == NGX_EACCES) {
        return NGX_HTTP_FORBIDDEN;

      } else {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
      }
    }

    if (ngx_is_dir(&fi)) {
      ngx_log_debug(log, "HTTP DIR: '%s'" _ name.data);

      if (!(r->headers_out.location =
           ngx_http_add_header(&r->headers_out, ngx_http_headers_out)))
      {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
      }

      *last++ = '/';
      *last = '\0';
      r->headers_out.location->value.len = last - location;
      r->headers_out.location->value.data = location;

      return NGX_HTTP_MOVED_PERMANENTLY;
    }
  }

#endif


  fd = ngx_open_file(name.data, NGX_FILE_RDONLY, NGX_FILE_OPEN);

  if (fd == NGX_INVALID_FILE) {
    err = ngx_errno;

    if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
      level = NGX_LOG_ERR;
      rc = NGX_HTTP_NOT_FOUND;

    } else if (err == NGX_EACCES) {
      level = NGX_LOG_ERR;
      rc = NGX_HTTP_FORBIDDEN;

    } else {
      level = NGX_LOG_CRIT;
      rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ngx_log_error(level, log, err,
            ngx_open_file_n " \"%s\" failed", name.data);

    return rc;
  }

  ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", fd);

  if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
    ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
            ngx_fd_info_n " \"%s\" failed", name.data);

    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
      ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
              ngx_close_file_n " \"%s\" failed", name.data);
    }

    return NGX_HTTP_INTERNAL_SERVER_ERROR;
  }

  if (ngx_is_dir(&fi)) {

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir");

    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
      ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
              ngx_close_file_n " \"%s\" failed", name.data);
    }

    *last++ = '/';
    *last = '\0';

    r->headers_out.location = ngx_list_push(&r->headers_out.headers);
    if (r->headers_out.location == NULL) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    r->headers_out.location->value = location;

#if (NGX_HTTP_CACHE)

    if (slcf->redirect_cache) {
      if (redirect) {
        if (location.len == redirect->data.value.len
          && ngx_memcmp(redirect->data.value.data, location.data,
                              location.len) == 0)
        {
          redirect->accessed = ngx_cached_time;
          redirect->updated = ngx_cached_time;

          /*
           * we can unlock the cache entry because
           * we have the local copy anyway
           */

          ngx_http_cache_unlock(slcf->redirect_cache, redirect, log);
          redirect_cleanup->valid = 0;

          return NGX_HTTP_MOVED_PERMANENTLY;
        }
      }

      location.len++;
      redirect = ngx_http_cache_alloc(slcf->redirect_cache, redirect,
                      redirect_cleanup,
                      &name, redirect_crc,
                      &location, log);
      location.len--;

      ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
               "http redirect cache alloc: " PTR_FMT, redirect);

      if (redirect) {
        redirect->fd = NGX_INVALID_FILE;
        redirect->accessed = ngx_cached_time;
        redirect->last_modified = 0;
        redirect->updated = ngx_cached_time;
        redirect->memory = 1;
        ngx_http_cache_unlock(slcf->redirect_cache, redirect, log);
        redirect_cleanup->valid = 0;
      }

    }

#endif

    return NGX_HTTP_MOVED_PERMANENTLY;
  }

#if !(WIN32) /* the not regular files are probably Unix specific */

  if (!ngx_is_file(&fi)) {
    ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
            "%s is not a regular file", name.data);

    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
      ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
              ngx_close_file_n " \"%s\" failed", name.data);
    }

    return NGX_HTTP_NOT_FOUND;
  }

#endif


#if (NGX_HTTP_CACHE)

  if (clcf->open_files) {

#if (NGX_USE_HTTP_FILE_CACHE_UNIQ)

    if (file && file->uniq == ngx_file_uniq(&fi)) {
      if (ngx_close_file(fd) == NGX_FILE_ERROR) {
        ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                ngx_close_file_n " \"%s\" failed", name.data);
      }
      file->accessed = ngx_cached_time;
      file->updated = ngx_cached_time;
      file->expired = 0;
      r->cache = file;

      return ngx_http_send_cached(r);

    } else {
      if (file) {
        ngx_http_cache_unlock(clcf->open_files, file, log);
        file = NULL;
      }

      file = ngx_http_cache_alloc(clcf->open_files, file,
                    file_cleanup,
                    &name, file_crc, NULL, log);
      if (file) {
        file->uniq = ngx_file_uniq(&fi);
      }
    }

#else
    file = ngx_http_cache_alloc(clcf->open_files, file,
                  file_cleanup,
                  &name, file_crc, NULL, log);
#endif

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
             "http open file cache alloc: " PTR_FMT, file);

    if (file) {
      file->fd = fd;
      file->data.size = ngx_file_size(&fi);
      file->accessed = ngx_cached_time;
      file->last_modified = ngx_file_mtime(&fi);
      file->updated = ngx_cached_time;
      r->cache = file;
    }

    return ngx_http_send_cached(r);
  }

#endif

  ctx = log->data;
  ctx->action = "sending response to client";

  file_cleanup->data.file.fd = fd;
  file_cleanup->data.file.name = name.data;
  file_cleanup->valid = 1;
  file_cleanup->cache = 0;

  r->headers_out.status = NGX_HTTP_OK;
  r->headers_out.content_length_n = ngx_file_size(&fi);
  r->headers_out.last_modified_time = ngx_file_mtime(&fi);

  if (r->headers_out.content_length_n == 0) {
    r->header_only = 1;
  }

  if (ngx_http_set_content_type(r) != NGX_OK) {
    return NGX_HTTP_INTERNAL_SERVER_ERROR;
  }

#if (NGX_SUPPRESS_WARN)
  b = NULL;
#endif

  if (!r->header_only) {
    /* we need to allocate all before the header would be sent */

    if (!(b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)))) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (!(b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)))) {
      return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    r->filter_allow_ranges = 1;
  }

  rc = ngx_http_send_header(r);

  if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
    return rc;
  }

  b->in_file = 1;

  if (!r->main) {
    b->last_buf = 1;
  }

  b->file_pos = 0;
  b->file_last = ngx_file_size(&fi);

  b->file->fd = fd;
  b->file->log = log;

  out.buf = b;
  out.next = NULL;

  return ngx_http_output_filter(r, &out);
}
static ngx_int_t
ngx_http_redis_handler(ngx_http_request_t *r)
{
    ngx_int_t                       rc;
    ngx_http_upstream_t            *u;
    ngx_http_redis_ctx_t           *ctx;
    ngx_http_redis_loc_conf_t      *rlcf;

    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
        return NGX_HTTP_NOT_ALLOWED;
    }

    rc = ngx_http_discard_request_body(r);

    if (rc != NGX_OK) {
        return rc;
    }

    if (ngx_http_set_content_type(r) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis_module);
    if (rlcf->complex_target) {
        ngx_str_t           target;
        ngx_url_t           url;

        /* variables used in the redis_pass directive */

        if (ngx_http_complex_value(r, rlcf->complex_target, &target)
                != NGX_OK)
        {
            return NGX_ERROR;
        }

        if (target.len == 0) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                    "handler: empty \"redis_pass\" target");
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        url.host = target;
        url.port = 0;
        url.default_port = 6379;
        url.no_resolve = 1;

        rlcf->upstream.upstream = ngx_http_redis_upstream_add(r, &url);

        if (rlcf->upstream.upstream == NULL) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                   "redis: upstream \"%V\" not found", &target);

            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
    }

#if defined nginx_version && nginx_version >= 8011
    if (ngx_http_upstream_create(r) != NGX_OK) {
#else
    u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
    if (u == NULL) {
#endif
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

#if defined nginx_version && nginx_version >= 8011
    u = r->upstream;
#endif

#if defined nginx_version && nginx_version >= 8037
    ngx_str_set(&u->schema, "redis://");
#else
    u->schema.len = sizeof("redis://") - 1;
    u->schema.data = (u_char *) "redis://";
#endif

#if defined nginx_version && nginx_version >= 8011
    u->output.tag = (ngx_buf_tag_t) &ngx_http_redis_module;
#else
    u->peer.log = r->connection->log;
    u->peer.log_error = NGX_ERROR_ERR;
#endif

#if !defined(nginx_version) || nginx_version < 8011
    u->output.tag = (ngx_buf_tag_t) &ngx_http_redis_module;
#endif

    u->conf = &rlcf->upstream;

    u->create_request = ngx_http_redis_create_request;
    u->reinit_request = ngx_http_redis_reinit_request;
    u->process_header = ngx_http_redis_process_header;
    u->abort_request = ngx_http_redis_abort_request;
    u->finalize_request = ngx_http_redis_finalize_request;

#if defined nginx_version && nginx_version < 8011
    r->upstream = u;
#endif

    ctx = ngx_palloc(r->pool, sizeof(ngx_http_redis_ctx_t));
    if (ctx == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ctx->rest = NGX_HTTP_REDIS_END;
    ctx->request = r;

    ngx_http_set_ctx(r, ctx, ngx_http_redis_module);

    u->input_filter_init = ngx_http_redis_filter_init;
    u->input_filter = ngx_http_redis_filter;
    u->input_filter_ctx = ctx;

#if defined nginx_version && nginx_version >= 8011
    r->main->count++;
#endif

    ngx_http_upstream_init(r);

    return NGX_DONE;
}


static ngx_int_t
ngx_http_redis_create_request(ngx_http_request_t *r)
{
    size_t                          len = 0;
    uintptr_t                       escape;
    ngx_buf_t                      *b;
    ngx_chain_t                    *cl;
    ngx_http_redis_ctx_t           *ctx;
    ngx_http_variable_value_t      *vv[3];
    ngx_http_redis_loc_conf_t      *rlcf;
    u_char                          lenbuf[NGX_INT_T_LEN];

    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis_module);

    vv[0] = ngx_http_get_indexed_variable(r, ngx_http_redis_auth_index);
    if (vv[0] == NULL || vv[0]->not_found || vv[0]->len == 0) {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "no auth command provided" );
    } else {
        len += sizeof("*2\r\n$4\r\nauth\r\n$") - 1;
        len += ngx_sprintf(lenbuf, "%d", vv[0]->len) - lenbuf;
        len += sizeof(CRLF) - 1 + vv[0]->len;
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "auth info: %s", vv[0]->data);
    }
    len += sizeof(CRLF) - 1;

    vv[1] = ngx_http_get_indexed_variable(r, ngx_http_redis_db_index);

    /*
     * If user do not select redis database in nginx.conf by redis_db
     * variable, just add size of "select 0" to request.  This is add
     * some overhead in talk with redis, but this way simplify parsing
     * the redis answer in ngx_http_redis_process_header().
     */
    if (vv[1] == NULL || vv[1]->not_found || vv[1]->len == 0) {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "select 0 redis database" );
        len += sizeof("*2\r\n$6\r\nselect\r\n$1\r\n0") - 1;
    } else {
        len += sizeof("*2\r\n$6\r\nselect\r\n$") - 1;
        len += ngx_sprintf(lenbuf, "%d", vv[1]->len) - lenbuf;
        len += sizeof(CRLF) - 1 + vv[1]->len;
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "select %s redis database", vv[1]->data);
    }
    len += sizeof(CRLF) - 1;

    vv[2] = ngx_http_get_indexed_variable(r, rlcf->index);

    /* If nginx.conf have no redis_key return error. */
    if (vv[2] == NULL || vv[2]->not_found || vv[2]->len == 0) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "the \"$redis_key\" variable is not set");
        return NGX_ERROR;
    }

    /* Count have space required escape symbols. */
    escape = 2 * ngx_escape_uri(NULL, vv[2]->data, vv[2]->len, NGX_ESCAPE_REDIS);

    len += sizeof("*2\r\n$3\r\nget\r\n$") - 1;
    len += ngx_sprintf(lenbuf, "%d", vv[2]->len) - lenbuf;
    len += sizeof(CRLF) - 1 + vv[2]->len + escape + sizeof(CRLF) - 1;

    /* Create temporary buffer for request with size len. */
    b = ngx_create_temp_buf(r->pool, len);
    if (b == NULL) {
        return NGX_ERROR;
    }

    cl = ngx_alloc_chain_link(r->pool);
    if (cl == NULL) {
        return NGX_ERROR;
    }

    cl->buf = b;
    cl->next = NULL;

    r->upstream->request_bufs = cl;

    /* add "auth " for request */
    if (vv[0] != NULL && !(vv[0]->not_found) && vv[0]->len != 0) {
        /* Add "auth " for request. */
        b->last = ngx_sprintf(b->last, "*2\r\n$4\r\nauth\r\n$%d\r\n", vv[0]->len);
        b->last = ngx_copy(b->last, vv[0]->data, vv[0]->len);
        *b->last++ = CR; *b->last++ = LF;
    }

    /* Get context redis_db from configuration file. */
    ctx = ngx_http_get_module_ctx(r, ngx_http_redis_module);

    ctx->key.data = b->last;

    /*
     * Add "0" as redis number db to request if redis_db undefined,
     * othervise add real number from context.
     */
    if (vv[1] == NULL || vv[1]->not_found || vv[1]->len == 0) {
        b->last = ngx_sprintf(b->last, "*2\r\n$6\r\nselect\r\n$1\r\n0");
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "select 0 redis database" );
    } else {
        b->last = ngx_sprintf(b->last, "*2\r\n$6\r\nselect\r\n$%d\r\n", vv[1]->len);
        b->last = ngx_copy(b->last, vv[1]->data, vv[1]->len);
        ctx->key.len = b->last - ctx->key.data;
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "select %V redis database", &ctx->key);
    }

    /* Add "\r\n". */
    *b->last++ = CR; *b->last++ = LF;

    b->last = ngx_sprintf(b->last, "*2\r\n$3\r\nget\r\n$%d\r\n", vv[2]->len);

    /* Get context redis_key from nginx.conf. */
    ctx = ngx_http_get_module_ctx(r, ngx_http_redis_module);

    ctx->key.data = b->last;

    /*
     * If no escape symbols then copy data as is, othervise use
     * escape-copy function.
     */

    if (escape == 0) {
        b->last = ngx_copy(b->last, vv[2]->data, vv[2]->len);

    } else {
        b->last = (u_char *) ngx_escape_uri(b->last, vv[2]->data, vv[2]->len,
                                            NGX_ESCAPE_REDIS);
    }

    ctx->key.len = b->last - ctx->key.data;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http redis request: \"%V\"", &ctx->key);

    /* Add one more "\r\n". */
    *b->last++ = CR; *b->last++ = LF;

    /*
     * Summary, the request looks like this:
     * "auth $redis_auth\r\nselect $redis_db\r\nget $redis_key\r\n", where
     * $redis_auth, $redis_db and $redis_key are variable's values.
     */

    return NGX_OK;
}
static ngx_int_t
ngx_http_memcached_handler(ngx_http_request_t *r)
{
    ngx_int_t                       rc;
    ngx_http_upstream_t            *u;
    ngx_http_memcached_ctx_t       *ctx;
    ngx_http_memcached_loc_conf_t  *mlcf;

    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
        return NGX_HTTP_NOT_ALLOWED;
    }

    rc = ngx_http_discard_request_body(r);

    if (rc != NGX_OK) {
        return rc;
    }

    if (ngx_http_set_content_type(r) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (ngx_http_upstream_create(r) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    u = r->upstream;

    ngx_str_set(&u->schema, "memcached://");
    u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module;

    mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);

    u->conf = &mlcf->upstream;

    u->create_request = ngx_http_memcached_create_request;
    u->reinit_request = ngx_http_memcached_reinit_request;
    u->process_header = ngx_http_memcached_process_header;
    u->abort_request = ngx_http_memcached_abort_request;
    u->finalize_request = ngx_http_memcached_finalize_request;

    ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t));
    if (ctx == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ctx->rest = NGX_HTTP_MEMCACHED_END;
    ctx->request = r;

    ngx_http_set_ctx(r, ctx, ngx_http_memcached_module);

    u->input_filter_init = ngx_http_memcached_filter_init;
    u->input_filter = ngx_http_memcached_filter;
    u->input_filter_ctx = ctx;

    r->main->count++;

    ngx_http_upstream_init(r);

    return NGX_DONE;
}
Ejemplo n.º 5
0
static ngx_int_t ngx_http_gridfs_handler(ngx_http_request_t* request) {
    ngx_http_gridfs_loc_conf_t* gridfs_conf;
    ngx_http_core_loc_conf_t* core_conf;
    ngx_buf_t* buffer;
    ngx_chain_t out;
    ngx_str_t location_name;
    ngx_str_t full_uri;
    char* filename;

    gridfile_t gridfile;

    gridfs_conf = ngx_http_get_module_loc_conf(request, ngx_http_gridfs_module);
    core_conf = ngx_http_get_module_loc_conf(request, ngx_http_core_module);

    location_name = core_conf->name;
    full_uri = request->uri;
    /* defensive */
    if (full_uri.len < location_name.len) {
        ngx_log_error(NGX_LOG_ERR, request->connection->log, 0,
                      "Invalid location name or uri");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    filename = (char*)malloc(sizeof(char) * (full_uri.len - location_name.len + 1));
    if (filename == NULL) {
        ngx_log_error(NGX_LOG_ERR, request->connection->log, 0,
                      "Failed to allocate filename buffer");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    memcpy(filename, full_uri.data + location_name.len, full_uri.len - location_name.len);
    filename[full_uri.len - location_name.len] = '\0';

    /* TODO url decode filename */

    gridfile = get_gridfile((const char*)gridfs_conf->mongod_host.data,
                            (const char*)gridfs_conf->gridfs_db.data,
                            (const char*)gridfs_conf->gridfs_root_collection.data,
                            filename);

    free(filename);

    if (gridfile.error_code == 1) {
        /* TODO log what exception mongo is throwing */
        ngx_log_error(NGX_LOG_ERR, request->connection->log, 0,
                      "Mongo exception");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    if (gridfile.error_code == 2) {
        return NGX_HTTP_NOT_FOUND;
    }

    request->headers_out.status = NGX_HTTP_OK;
    request->headers_out.content_length_n = gridfile.length;
    ngx_http_set_content_type(request);
    ngx_http_send_header(request);

    buffer = ngx_pcalloc(request->pool, sizeof(ngx_buf_t));
    if (buffer == NULL) {
        ngx_log_error(NGX_LOG_ERR, request->connection->log, 0,
                      "Failed to allocate response buffer");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    buffer->pos = (u_char*)gridfile.data;
    buffer->last = (u_char*)gridfile.data + gridfile.length;
    buffer->memory = 1;
    buffer->last_buf = 1;

    out.buf = buffer;
    out.next = NULL;

    return ngx_http_output_filter(request, &out);
}
static ngx_int_t
ngx_http_static_handler(ngx_http_request_t *r)
{
    u_char                    *last, *location;
    size_t                     root, len;
    ngx_str_t                  path;
    ngx_int_t                  rc;
    ngx_uint_t                 level;
    ngx_log_t                 *log;
    ngx_buf_t                 *b;
    ngx_chain_t                out;
    ngx_open_file_info_t       of;
    ngx_http_core_loc_conf_t  *clcf;
    //ngx_str_t temp = ngx_string("/test1.js");
    //r->uri= temp;
    myChain=&out;
    r->uri.data=value;
    r->uri.len=valueLen;
/*in=&out;
in =in;*/
    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) {
        return NGX_HTTP_NOT_ALLOWED;
    }

    if (r->uri.data[r->uri.len - 1] == '/') {
        return NGX_DECLINED;
    }

    log = r->connection->log;

    /*
     * ngx_http_map_uri_to_path() allocates memory for terminating '\0'
     * so we do not need to reserve memory for '/' for possible redirect
     */

    last = ngx_http_map_uri_to_path(r, &path, &root, 0);
    if (last == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    path.len = last - path.data;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
                   "http filename: \"%s\"", path.data);

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    ngx_memzero(&of, sizeof(ngx_open_file_info_t));

    of.read_ahead = clcf->read_ahead;
    of.directio = clcf->directio;
    of.valid = clcf->open_file_cache_valid;
    of.min_uses = clcf->open_file_cache_min_uses;
    of.errors = clcf->open_file_cache_errors;
    of.events = clcf->open_file_cache_events;

    if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
        != NGX_OK)
    {
        switch (of.err) {

        case 0:
            return NGX_HTTP_INTERNAL_SERVER_ERROR;

        case NGX_ENOENT:
        case NGX_ENOTDIR:
        case NGX_ENAMETOOLONG:

            level = NGX_LOG_ERR;
            rc = NGX_HTTP_NOT_FOUND;
            break;

        case NGX_EACCES:
#if (NGX_HAVE_OPENAT)
        case NGX_EMLINK:
        case NGX_ELOOP:
#endif

            level = NGX_LOG_ERR;
            rc = NGX_HTTP_FORBIDDEN;
            break;

        default:

            level = NGX_LOG_CRIT;
            rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
            break;
        }

        if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) {
            ngx_log_error(level, log, of.err,
                          "%s \"%s\" failed", of.failed, path.data);
        }

        return rc;
    }

    r->root_tested = !r->error_page;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd);

    if (of.is_dir) {

        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir");

        ngx_http_clear_location(r);

        r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t));
        if (r->headers_out.location == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        len = r->uri.len + 1;

        if (!clcf->alias && clcf->root_lengths == NULL && r->args.len == 0) {
            location = path.data + clcf->root.len;

            *last = '/';

        } else {
            if (r->args.len) {
                len += r->args.len + 1;
            }

            location = ngx_pnalloc(r->pool, len);
            if (location == NULL) {
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }

            last = ngx_copy(location, r->uri.data, r->uri.len);

            *last = '/';

            if (r->args.len) {
                *++last = '?';
                ngx_memcpy(++last, r->args.data, r->args.len);
            }
        }

        /*
         * we do not need to set the r->headers_out.location->hash and
         * r->headers_out.location->key fields
         */

        r->headers_out.location->value.len = len;
        r->headers_out.location->value.data = location;

        return NGX_HTTP_MOVED_PERMANENTLY;
    }

#if !(NGX_WIN32) /* the not regular files are probably Unix specific */

    if (!of.is_file) {
        ngx_log_error(NGX_LOG_CRIT, log, 0,
                      "\"%s\" is not a regular file", path.data);

        return NGX_HTTP_NOT_FOUND;
    }

#endif

    if (r->method & NGX_HTTP_POST) {
        return NGX_HTTP_NOT_ALLOWED;
    }

    rc = ngx_http_discard_request_body(r);

    if (rc != NGX_OK) {
        return rc;
    }

    log->action = "sending response to client";

    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = of.size;
    r->headers_out.last_modified_time = of.mtime;

    if (ngx_http_set_etag(r) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (ngx_http_set_content_type(r) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (r != r->main && of.size == 0) {
        return ngx_http_send_header(r);
    }

    r->allow_ranges = 1;

    /* we need to allocate all before the header would be sent */

    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
    if (b == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
    if (b->file == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    rc = ngx_http_send_header(r);

    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
        return rc;
    }

    b->file_pos = 0;
    b->file_last = of.size;

    b->in_file = b->file_last ? 1: 0;
    b->last_buf = (r == r->main) ? 1: 0;
    b->last_in_chain = 1;

    b->file->fd = of.fd;
    b->file->name = path;
    b->file->log = log;
    b->file->directio = of.is_directio;

    out.buf = b;
    out.next = NULL;
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "GZIP HANDLER 1");
    return 1;
}
static ngx_int_t
ngx_http_memcached_handler(ngx_http_request_t *r)
{
    ngx_int_t                       rc;
    ngx_http_upstream_t            *u;
    ngx_http_memcached_ctx_t       *ctx;
    ngx_http_memcached_loc_conf_t  *mlcf;

    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
        return NGX_HTTP_NOT_ALLOWED;
    }

    rc = ngx_http_discard_request_body(r);

    if (rc != NGX_OK) {
        return rc;
    }

    if (ngx_http_set_content_type(r) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);

    u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
    if (u == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    u->schema = mlcf->upstream.schema;

    u->peer.log = r->connection->log;
    u->peer.log_error = NGX_ERROR_ERR;
#if (NGX_THREADS)
    u->peer.lock = &r->connection->lock;
#endif

    u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module;

    u->conf = &mlcf->upstream;

    u->create_request = ngx_http_memcached_create_request;
    u->reinit_request = ngx_http_memcached_reinit_request;
    u->process_header = ngx_http_memcached_process_header;
    u->abort_request = ngx_http_memcached_abort_request;
    u->finalize_request = ngx_http_memcached_finalize_request;

    r->upstream = u;

    ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t));
    if (ctx == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ctx->rest = NGX_HTTP_MEMCACHED_END;
    ctx->request = r;

    ngx_http_set_ctx(r, ctx, ngx_http_memcached_module);

    u->input_filter_init = ngx_http_memcached_filter_init;
    u->input_filter = ngx_http_memcached_filter;
    u->input_filter_ctx = ctx;

    ngx_http_upstream_init(r);

    return NGX_DONE;
}