2: header already sent

Dk Jack dnj0496 at gmail.com
Thu Jul 12 20:29:58 UTC 2018


Hi,
Sorry for sending this again. I haven't been able to resolve my issue. I've
read several modules for example and gone over several docs etc. but with
no success so far.

In my module, I need to either drop the request or allow the request. When
I drop the request, I need to send custom response and status. The custom
response and status don't come from the config file. When I send the
response in the content phase handler, I am am seeing 'header already sent'
messages in the error log. How can prevent further processing of the
request after my handler is called for the terminal case?

Since my module needs to examine all requests irrespective of the uri, I
tried registering a content phase handler and send the custom response in
that handler. However, my content phase handler is never invoked. I suspect
some other content handler is overriding my content handler.  Is there a
way I can prevent that i.e. for a request, can I force only my content
handler to be called.

Please let me know what I am doing wrong? I just need to send/perform
custom response/actions when a request matches my criteria. I've include a
skeleton of my code.
Any inputs are greatly appreciated. Thanks.

regards,
Dk.

http_mod_send_response(ngx_http_request_t *r, ngx_uint_t custom_status,
char *body, ngx_int_t blen)
{
  ngx_int_t rc;
  ngx_log_t *log = r->connection->log;
  ngx_buf_t *buf = ngx_create_temp_buf(r->pool, (blen+16)); // pad.

  if (NULL == buf) {
    ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Failed to allocate buffer",
__FUNCTION__);
    return NGX_ERROR;
  }

  buf->last = ngx_copy(buf->start, (unsigned char*) data, dlen);
  rc = ngx_http_discard_request_body(r);
  if (rc != NGX_OK) {
    ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Discard req. body failed.
rc=%i", __FUNCTION__, rc);
    return rc;
  }

  r->headers_out.status = custom_status;
  r->headers_out.content_length_n = buf->last - buf->pos;
  r->headers_out.content_type.len = sizeof("text/plain") - 1;
  r->headers_out.content_type.data = (u_char *) "text/plain";

  rc = ngx_http_send_header(r);
  if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
    ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Send header failed. rc=%i",
__FUNCTION__, rc);
    return rc;
  }

  ngx_chain_t *out_chain = ngx_alloc_chain_link(r->pool);
  if (NULL == out_chain) {
    ngx_log_error(NGX_LOG_ERR, log, 0, "%s: Buffer chain alloc failed",
__FUNCTION__);
    return NGX_ERROR;
  }

  out_chain->buf = buf;
  out_chain->next = NULL;
  buf->last_buf = 1;
  buf->last_in_chain = 1;

  return ngx_http_output_filter(r, out_chain);
}

typedef struct {
  unsigned done:1;
} ngx_http_mod_ctx_t;

int
http_module_process_request(ngx_http_request_t *r, ngx_uint_t *status, char
*body, ngx_uint_t *blen)
{
  if (/* request matches criteria */) {
    /* other boiler plate code */
    *status = get_custom_status();
    *body = get_custom_body();
    *blen = ngx_strlen(body);
    return *status;    // this can be different from custom status.
  }

  return NGX_DECLINED;
}

static ngx_int_t
ngx_http_request_handler(ngx_http_request_t *r)
{
  ngx_http_mod_ctx_t *ctx = ngx_http_get_module_ctx(r, nginx_http_module);

  if (ctx) {
    ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "duplicate
    invokation");
    return NGX_DECLINED;
  } else {
    ctx = ngx_palloc(r->connection->pool, sizeof(ngx_http_mod_ctx_t));
    if (ctx == NULL) {
      ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
      "Out of memory. Cannot allocate context");
      return NGX_ERROR;
    }

    ctx->done = 0;
    ngx_http_set_ctx(r, ctx, nginx_http_module);
  }

  ngx_int_t rc = 0;
  char custom_body[512];
  ngx_uint_t blen;
  ngx_uint_t custom_status;
  if (!ctx->done) {
    rc = http_module_process_request(r, &custom_status, custom_body, &blen);
  }

  ctx->done = 1;
  if ((rc != 0) && (rc != NGX_DECLINED)) {
    return http_mod_send_response(r, custom_status, custom_body, blen);
    /* alternate implementation, send response in content handler.
      ngx_buf_t *buf = ngx_create_temp_buf(r->pool, blen);
      buf->last = ngx_copy(buf->start, (unsigned char*) data, dlen);
      ctx->custom_body = buf;
      ctx->rcode = custom_status;
     */
  }

  return NGX_DECLINED;
}

static ngx_int_t
http_module_content_handler(ngx_http_request_t *r)
{
  ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s: invoked",
__FUNCTION__);
  ngx_http_ss_ctx_t *ctx = ngx_http_get_module_ctx(r,
nginx_mitigator_module);

  if (ctx && ctx->content) {
    ctx->content = 0;
    return http_mod_send_response(r, ctx->rcode, ctx->custom_body);
  } else {
    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                  "%s: ctx = %p, content = %d", __FUNCTION__, ctx, ctx ?
ctx->content : -1);
  }

  return NGX_DECLINED;
}

static ngx_int_t
ngx_http_module_init (ngx_conf_t *cf)
{
  ngx_http_core_main_conf_t *cmcf = ngx_http_conf_get_module_main_conf(cf,
ngx_http_core_module);

  if (!cmcf) {
    ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Failed to retrieve module main
conf");
    return NGX_ERROR;
  }

  ngx_http_handler_pt *hptr =
ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
  if (hptr == NULL) {
    ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Could not retrieve access phase
handler");
    return NGX_ERROR;
  }

  *hptr = ngx_http_request_handler;
  ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed request
handler");

  ngx_http_handler_pt *cptr =
ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
  if (cptr == NULL) {
    ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Could not retrieve access phase
handler");
    return NGX_ERROR;
  }

  *cptr = ngx_http_request_handler;
  ngx_log_error(NGX_LOG_INFO, cf->log, 0, "[init] Installed request
handler");

  return NGX_OK;
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20180712/435774a9/attachment-0001.html>


More information about the nginx-devel mailing list