Проблемы с получением request body

tigran.bayburtsyan nginx-forum at nginx.us
Mon Dec 1 13:35:35 UTC 2014


Привет.
Я пишу модуль для Nginx в котором будут обрабатываются POST запросы.
Нашел несколько opensource проектов в которых тоже обрабатываются запросы
такого типа.
Например https://github.com/calio/form-input-nginx-module .
Сделал этот функционал , но оно работает только на локальной среде. Если
пробую с какого то online сервера то ответ от Nginx пустой.

Как я представляю в remote сервере request_body приходит гораздо медленнее
чем на локале и где то возврашет ответ до исполнения хандлера
ngx_http_read_client_request_body(r,toxic_post_body_handler).
Покапал в интернете ничего нет по этой теме. Просмотрел коды у других
модулей вроде у меня тоже так же. 

Вот мой код. 

#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#include <ngx_event.h>

............................... // Еше несколько 

typedef struct {
    char *key;
    void(*callback)(const char *str, unsigned int str_length);
} toxic_request_callback;

typedef struct
{
  unsigned done:1;
  unsigned waiting_more_body:1;
  unsigned body_end:1;
} toxic_ctx;


static char *ngx_http_toxic(ngx_conf_t *cf, void *post, void *data);


static ngx_conf_post_handler_pt ngx_http_toxic_p = ngx_http_toxic;

typedef struct {
    ngx_str_t   name;
} ngx_http_toxic_loc_conf_t;

static void * ngx_http_toxic_create_loc_conf(ngx_conf_t *cf)
{
    ngx_http_toxic_loc_conf_t  *conf;

    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_toxic_loc_conf_t));
    if (conf == NULL) {
        return NULL;
    }

    return conf;
}

static ngx_command_t ngx_http_toxic_commands[] = {
    { ngx_string("toxic"),
      NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_str_slot,
      NGX_HTTP_LOC_CONF_OFFSET,
      offsetof(ngx_http_toxic_loc_conf_t, name),
      &ngx_http_toxic_p },

    ngx_null_command
};


static ngx_str_t toxic_string;
static ngx_http_module_t ngx_http_toxic_module_ctx = {
    NULL,                          /* preconfiguration */
    NULL,                          /* postconfiguration */

    NULL,                          /* create main configuration */
    NULL,                          /* init main configuration */

    NULL,                          /* create server configuration */
    NULL,                          /* merge server configuration */

    ngx_http_toxic_create_loc_conf, /* create location configuration */
    NULL                           /* merge location configuration */
};


ngx_module_t ngx_http_toxic_module = {
    NGX_MODULE_V1,
    &ngx_http_toxic_module_ctx,    /* module context */
    ngx_http_toxic_commands,       /* module directives */
    NGX_HTTP_MODULE,               /* module type */
    NULL,                          /* init master */
    NULL,                          /* init module */
    NULL,                          /* init process */
    NULL,                          /* init thread */
    NULL,                          /* exit thread */
    NULL,                          /* exit process */
    NULL,                          /* exit master */
    NGX_MODULE_V1_PADDING
};

static ngx_int_t
ngx_http_toxic_handler(ngx_http_request_t *r);

static ngx_int_t toxic_excecute(ngx_http_request_t *r, char *content_type)
{
    char * base_str;
    int base_len = 0;

....................................................... // функционал с
base_str и base_len 

        r->headers_out.content_type_len = strlen(content_type);
        r->headers_out.content_type.data = (u_char *) content_type;
        r->headers_out.status = NGX_HTTP_OK;
        r->headers_out.content_length_n = base_len;
        ngx_http_send_header(r);


        ngx_buf_t   *b;
        ngx_chain_t  *out;
        out = ngx_pcalloc(r->pool, sizeof(out));
        b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
        if (b == NULL) {
            return 0;
        }
        out->buf = b;
        out->next = NULL;

        /* adjust the pointers of the buffer */
        b->pos = (u_char*)base_str;
        b->last = (u_char*)base_str + base_len;
        b->memory = 1;    /* this buffer is in memory */
        b->last_buf = 1;  /* this is the last buffer in the buffer chain */

        /* send the buffer chain of response */
        ngx_int_t rc;
        rc = ngx_http_output_filter ( r , out );
        while( rc == NGX_AGAIN ) {
            if( out->next == NULL )
                break;
            rc = ngx_http_output_filter ( r , out->next );
            out = out->next;
        }

    return NGX_DONE;
}


static void toxic_post_body_handler(ngx_http_request_t *r)
{
    toxic_ctx *ctx;

    ctx = ngx_http_get_module_ctx(r, ngx_http_toxic_module);
    ctx->done = 1;
#if defined(nginx_version) && nginx_version >= 8011
    r->main->count--;
#endif
    /* waiting_more_body my rewrite phase handler */
    if (ctx->waiting_more_body) {
        ctx->waiting_more_body = 0;
        ngx_http_core_run_phases(r->main); // Думаю проблема здесь но не
представляю что делать
    }


    // предполагаю что здесь уже весь POST пришел
    ngx_buf_t * buf;
    ngx_chain_t * chain;
    char *post_body= "";
    int post_len=0;
    chain = r->request_body->bufs;
    while (chain) {
        buf = chain->buf;
        int len = buf->end - buf->start;
        if(post_len > 0)
        {
            post_body = (char*)realloc(post_body, sizeof(char) * (len +
post_len));
            strncat(post_body, (char *)buf->start, len);
        }
        else
        {
            post_body = (char*)malloc(sizeof(char) * len);
            int i;
            for(i=0;i<len;i++)
            {
                post_body[i] = buf->start[i];
            }
            post_body[len] = '\0';
        }
        post_len += len;
        chain = chain->next;
    }
    
 ............................ // функционал с post_body и post_len

}

/*
 * Main handler function of the module.
 */
static ngx_int_t
ngx_http_toxic_handler(ngx_http_request_t *r)
{
    ngx_int_t    rc;
    toxic_ctx       *ctx;

    if ((r->method & (NGX_HTTP_POST|NGX_HTTP_PUT))) {
        ctx = ngx_http_get_module_ctx(r, ngx_http_toxic_module);

           if (ctx != NULL) {
                if (ctx->done) {
                    return NGX_DECLINED;
                }

                return NGX_DONE;
            }

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

        ngx_http_set_ctx(r, ctx, ngx_http_toxic_module);

            rc =
ngx_http_read_client_request_body(r,toxic_post_body_handler);
            if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
                    return rc;
            }

            if (rc == NGX_AGAIN) {
               ctx->waiting_more_body = 1;
               ngx_http_set_ctx(r, ctx, ngx_http_toxic_module);
               return NGX_DONE;
            }
    }

    ngx_http_finalize_request(r, toxic_excecute(r, "text/html"));

    return NGX_OK;
}

/*
 * Function for the directive toxic , it validates its value
 * and copies it to a static variable to be printed later
 */
static char * ngx_http_toxic(ngx_conf_t *cf, void *post, void *data)
{
    ngx_http_core_loc_conf_t *clcf;

    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
    clcf->handler = ngx_http_toxic_handler;

    ngx_str_t  *name = data; // i.e., first field of
ngx_http_toxic_loc_conf_t

    if (ngx_strcmp(name->data, "") == 0) {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}

Posted at Nginx Forum: http://forum.nginx.org/read.php?21,255240,255240#msg-255240



Подробная информация о списке рассылки nginx-ru