Hi Dk Jack, On Fri, Jul 13, 2018 at 01:18:40PM -0700, Dk Jack wrote: > Sorry, I made a typo in my earlier email. Please read the following > sentence: > > "When I send the response in the *content* phase handler, I am am seeing > 'header already sent' messages in the error log." > > as > > "When I send the response in the *access* phase handler, I am am seeing > 'header already sent' messages in the error log."
That's because you do not finalize the request after you send a response in the access handler. A content handler (standard static or another one) is still called at the content phase. It tries to send a second response and obviously gets this error. Finalize the request in the access phase after you send the response with this call: ngx_http_finalize_request(r, rc) where rc is what ngx_http_output_filter() returned. Then return NGX_DONE from the access handler to prevent further request processing. If you want to return a standard error page, simply return its HTTP status code from your access handler instead. > On Thu, Jul 12, 2018 at 1:29 PM Dk Jack <dnj0...@gmail.com> wrote: > > > 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; > > } > > > > > > > _______________________________________________ > nginx-devel mailing list > nginx-devel@nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel -- Roman Arutyunyan _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel