diff options
Diffstat (limited to 'storage/mroonga/vendor/groonga/src/httpd/nginx-module/ngx_http_groonga_module.c')
-rw-r--r-- | storage/mroonga/vendor/groonga/src/httpd/nginx-module/ngx_http_groonga_module.c | 277 |
1 files changed, 222 insertions, 55 deletions
diff --git a/storage/mroonga/vendor/groonga/src/httpd/nginx-module/ngx_http_groonga_module.c b/storage/mroonga/vendor/groonga/src/httpd/nginx-module/ngx_http_groonga_module.c index 26be6be7d0a..6ba1df4a9e8 100644 --- a/storage/mroonga/vendor/groonga/src/httpd/nginx-module/ngx_http_groonga_module.c +++ b/storage/mroonga/vendor/groonga/src/httpd/nginx-module/ngx_http_groonga_module.c @@ -1,6 +1,6 @@ /* -*- c-basic-offset: 2 -*- */ /* - Copyright(C) 2012-2014 Brazil + Copyright(C) 2012-2015 Brazil This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -16,9 +16,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> +#ifndef WIN32 +# define NGX_GRN_SUPPORT_STOP_BY_COMMAND +#endif #include <ngx_config.h> #include <ngx_core.h> @@ -26,6 +26,13 @@ #include <groonga.h> +#include <sys/stat.h> + +#ifdef NGX_GRN_SUPPORT_STOP_BY_COMMAND +# include <sys/types.h> +# include <unistd.h> +#endif + #define GRN_NO_FLAGS 0 typedef struct { @@ -56,9 +63,19 @@ typedef struct { typedef struct { grn_bool initialized; grn_ctx context; - grn_obj head; - grn_obj body; - grn_obj foot; + struct { + grn_bool processed; + grn_bool header_sent; + ngx_http_request_t *r; + ngx_int_t rc; + ngx_chain_t *free_chain; + ngx_chain_t *busy_chain; + } raw; + struct { + grn_obj head; + grn_obj body; + grn_obj foot; + } typed; } ngx_http_groonga_handler_data_t; typedef struct { @@ -126,18 +143,54 @@ ngx_http_groonga_logger_log(grn_ctx *ctx, grn_log_level level, const char level_marks[] = " EACewnid-"; u_char buffer[NGX_MAX_ERROR_STR]; u_char *last; - + size_t prefix_size; + size_t message_size; + size_t location_size; + size_t postfix_size; + size_t log_message_size; + +#define LOG_PREFIX_FORMAT "%s|%c|%s " + prefix_size = + strlen(timestamp) + + 1 /* | */ + + 1 /* %c */ + + 1 /* | */ + + strlen(title) + + 1 /* a space */; + message_size = strlen(message); if (location && *location) { - last = ngx_slprintf(buffer, buffer + NGX_MAX_ERROR_STR, - "%s|%c|%s %s %s\n", - timestamp, *(level_marks + level), title, message, - location); + location_size = 1 /* a space */ + strlen(location); } else { + location_size = 0; + } + postfix_size = 1 /* \n */; + log_message_size = prefix_size + message_size + location_size + postfix_size; + + if (log_message_size > NGX_MAX_ERROR_STR) { last = ngx_slprintf(buffer, buffer + NGX_MAX_ERROR_STR, - "%s|%c|%s %s\n", - timestamp, *(level_marks + level), title, message); + LOG_PREFIX_FORMAT, + timestamp, *(level_marks + level), title); + ngx_write_fd(logger_data->file->fd, buffer, last - buffer); + ngx_write_fd(logger_data->file->fd, (void *)message, message_size); + if (location_size > 0) { + ngx_write_fd(logger_data->file->fd, " ", 1); + ngx_write_fd(logger_data->file->fd, (void *)location, location_size); + } + ngx_write_fd(logger_data->file->fd, "\n", 1); + } else { + if (location && *location) { + last = ngx_slprintf(buffer, buffer + NGX_MAX_ERROR_STR, + LOG_PREFIX_FORMAT " %s %s\n", + timestamp, *(level_marks + level), title, message, + location); + } else { + last = ngx_slprintf(buffer, buffer + NGX_MAX_ERROR_STR, + LOG_PREFIX_FORMAT " %s\n", + timestamp, *(level_marks + level), title, message); + } + ngx_write_fd(logger_data->file->fd, buffer, last - buffer); } - ngx_write_fd(logger_data->file->fd, buffer, last - buffer); +#undef LOG_PREFIX_FORMAT } static void @@ -336,6 +389,7 @@ ngx_http_groonga_grn_obj_to_ngx_buf(ngx_pool_t *pool, grn_obj *object) buffer->pos = (u_char *)GRN_TEXT_VALUE(object); buffer->last = (u_char *)GRN_TEXT_VALUE(object) + GRN_TEXT_LEN(object); buffer->memory = 1; /* this buffer is in memory */ + buffer->in_file = 0; return buffer; } @@ -351,20 +405,109 @@ ngx_http_groonga_handler_cleanup(void *user_data) } context = &(data->context); - GRN_OBJ_FIN(context, &(data->head)); - GRN_OBJ_FIN(context, &(data->body)); - GRN_OBJ_FIN(context, &(data->foot)); + GRN_OBJ_FIN(context, &(data->typed.head)); + GRN_OBJ_FIN(context, &(data->typed.body)); + GRN_OBJ_FIN(context, &(data->typed.foot)); grn_logger_set(context, NULL); grn_query_logger_set(context, NULL); grn_ctx_fin(context); } static void -ngx_http_groonga_context_receive_handler(grn_ctx *context, - int flags, - void *callback_data) +ngx_http_groonga_handler_set_content_type(ngx_http_request_t *r, + const char *content_type) +{ + r->headers_out.content_type.len = strlen(content_type); + r->headers_out.content_type.data = (u_char *)content_type; + r->headers_out.content_type_len = r->headers_out.content_type.len; +} + +static void +ngx_http_groonga_context_receive_handler_raw(grn_ctx *context, + int flags, + ngx_http_groonga_handler_data_t *data) +{ + char *chunk = NULL; + unsigned int chunk_size = 0; + int recv_flags; + ngx_http_request_t *r; + ngx_log_t *log; + grn_bool is_last_chunk; + + grn_ctx_recv(context, &chunk, &chunk_size, &recv_flags); + data->raw.processed = GRN_TRUE; + + if (data->raw.rc != NGX_OK) { + return; + } + + r = data->raw.r; + log = r->connection->log; + is_last_chunk = (flags & GRN_CTX_TAIL); + + if (!data->raw.header_sent) { + ngx_http_groonga_handler_set_content_type(r, grn_ctx_get_mime_type(context)); + r->headers_out.status = NGX_HTTP_OK; + if (is_last_chunk) { + r->headers_out.content_length_n = chunk_size; + if (chunk_size == 0) { + r->header_only = 1; + } + } else { + r->headers_out.content_length_n = -1; + } + data->raw.rc = ngx_http_send_header(r); + data->raw.header_sent = GRN_TRUE; + + if (data->raw.rc != NGX_OK) { + return; + } + } + + if (chunk_size > 0 || is_last_chunk) { + ngx_chain_t *chain; + + chain = ngx_chain_get_free_buf(r->pool, &(data->raw.free_chain)); + if (!chain) { + ngx_log_error(NGX_LOG_ERR, log, 0, + "http_groonga: failed to allocate memory for chunked body"); + data->raw.rc = NGX_ERROR; + return; + } + if (chunk_size == 0) { + chain->buf->pos = NULL; + chain->buf->last = NULL; + chain->buf->memory = 0; + } else { + chain->buf->pos = (u_char *)chunk; + chain->buf->last = (u_char *)chunk + chunk_size; + chain->buf->memory = 1; + } + chain->buf->tag = (ngx_buf_tag_t)&ngx_http_groonga_module; + chain->buf->flush = 1; + chain->buf->temporary = 0; + chain->buf->in_file = 0; + if (is_last_chunk) { + chain->buf->last_buf = 1; + } else { + chain->buf->last_buf = 0; + } + chain->next = NULL; + + data->raw.rc = ngx_http_output_filter(r, chain); + ngx_chain_update_chains(r->pool, + &(data->raw.free_chain), + &(data->raw.busy_chain), + &chain, + (ngx_buf_tag_t)&ngx_http_groonga_module); + } +} + +static void +ngx_http_groonga_context_receive_handler_typed(grn_ctx *context, + int flags, + ngx_http_groonga_handler_data_t *data) { - ngx_http_groonga_handler_data_t *data = callback_data; char *result = NULL; unsigned int result_size = 0; int recv_flags; @@ -375,6 +518,7 @@ ngx_http_groonga_context_receive_handler(grn_ctx *context, grn_ctx_recv(context, &result, &result_size, &recv_flags); +#ifdef NGX_GRN_SUPPORT_STOP_BY_COMMAND if (recv_flags == GRN_CTX_QUIT) { ngx_int_t ngx_rc; ngx_int_t ngx_pid; @@ -385,8 +529,8 @@ ngx_http_groonga_context_receive_handler(grn_ctx *context, ngx_pid = getppid(); } - ngx_rc = ngx_os_signal_process((ngx_cycle_t*)ngx_cycle, - "stop", + ngx_rc = ngx_os_signal_process((ngx_cycle_t *)ngx_cycle, + "quit", ngx_pid); if (ngx_rc == NGX_OK) { context->stat &= ~GRN_CTX_QUIT; @@ -394,28 +538,47 @@ ngx_http_groonga_context_receive_handler(grn_ctx *context, context->stat |= GRN_CTX_QUIT; } else { context->rc = GRN_OPERATION_NOT_PERMITTED; - GRN_TEXT_PUTS(context, &(data->body), "false"); + GRN_TEXT_PUTS(context, &(data->typed.body), "false"); context->stat &= ~GRN_CTX_QUIT; } } +#endif if (result_size > 0 || - GRN_TEXT_LEN(&(data->body)) > 0 || + GRN_TEXT_LEN(&(data->typed.body)) > 0 || context->rc != GRN_SUCCESS) { if (result_size > 0) { - GRN_TEXT_PUT(context, &(data->body), result, result_size); + GRN_TEXT_PUT(context, &(data->typed.body), result, result_size); } grn_output_envelope(context, context->rc, - &(data->head), - &(data->body), - &(data->foot), + &(data->typed.head), + &(data->typed.body), + &(data->typed.foot), NULL, 0); } } +static void +ngx_http_groonga_context_receive_handler(grn_ctx *context, + int flags, + void *callback_data) +{ + ngx_http_groonga_handler_data_t *data = callback_data; + + switch (grn_ctx_get_output_type(context)) { + case GRN_CONTENT_GROONGA_COMMAND_LIST : + case GRN_CONTENT_NONE : + ngx_http_groonga_context_receive_handler_raw(context, flags, data); + break; + default : + ngx_http_groonga_context_receive_handler_typed(context, flags, data); + break; + } +} + static ngx_int_t ngx_http_groonga_extract_command_path(ngx_http_request_t *r, ngx_str_t *command_path) @@ -461,15 +624,6 @@ ngx_http_groonga_extract_command_path(ngx_http_request_t *r, return NGX_OK; } -static void -ngx_http_groonga_handler_set_content_type(ngx_http_request_t *r, - const char *content_type) -{ - r->headers_out.content_type.len = strlen(content_type); - r->headers_out.content_type.data = (u_char *)content_type; - r->headers_out.content_type_len = r->headers_out.content_type.len; -} - static ngx_int_t ngx_http_groonga_handler_create_data(ngx_http_request_t *r, ngx_http_groonga_handler_data_t **data_return) @@ -496,10 +650,20 @@ ngx_http_groonga_handler_create_data(ngx_http_request_t *r, if (rc != NGX_OK) { return rc; } + data->initialized = GRN_TRUE; - GRN_TEXT_INIT(&(data->head), GRN_NO_FLAGS); - GRN_TEXT_INIT(&(data->body), GRN_NO_FLAGS); - GRN_TEXT_INIT(&(data->foot), GRN_NO_FLAGS); + + data->raw.processed = GRN_FALSE; + data->raw.header_sent = GRN_FALSE; + data->raw.r = r; + data->raw.rc = NGX_OK; + data->raw.free_chain = NULL; + data->raw.busy_chain = NULL; + + GRN_TEXT_INIT(&(data->typed.head), GRN_NO_FLAGS); + GRN_TEXT_INIT(&(data->typed.body), GRN_NO_FLAGS); + GRN_TEXT_INIT(&(data->typed.foot), GRN_NO_FLAGS); + grn_ctx_use(context, grn_ctx_db(&(location_conf->context))); rc = ngx_http_groonga_context_check_error(r->connection->log, context); if (rc != NGX_OK) { @@ -553,9 +717,10 @@ ngx_http_groonga_handler_validate_post_command(ngx_http_request_t *r, context = &(data->context); ngx_http_groonga_handler_set_content_type(r, "text/plain"); - GRN_TEXT_PUTS(context, &(data->body), "command for POST must be <load>: <"); - GRN_TEXT_PUT(context, &(data->body), command.data, command.len); - GRN_TEXT_PUTS(context, &(data->body), ">"); + GRN_TEXT_PUTS(context, &(data->typed.body), + "command for POST must be <load>: <"); + GRN_TEXT_PUT(context, &(data->typed.body), command.data, command.len); + GRN_TEXT_PUTS(context, &(data->typed.body), ">"); return NGX_HTTP_BAD_REQUEST; } @@ -665,7 +830,7 @@ ngx_http_groonga_handler_process_body(ngx_http_request_t *r, body = r->request_body->bufs->buf; if (!body) { ngx_http_groonga_handler_set_content_type(r, "text/plain"); - GRN_TEXT_PUTS(context, &(data->body), "must send load data as body"); + GRN_TEXT_PUTS(context, &(data->typed.body), "must send load data as body"); return NGX_HTTP_BAD_REQUEST; } @@ -744,6 +909,10 @@ ngx_http_groonga_handler_send_response(ngx_http_request_t *r, ngx_chain_t head_chain, body_chain, foot_chain; ngx_chain_t *output_chain = NULL; + if (data->raw.processed) { + return data->raw.rc; + } + context = &(data->context); /* set the 'Content-type' header */ @@ -753,17 +922,17 @@ ngx_http_groonga_handler_send_response(ngx_http_request_t *r, } /* allocate buffers for a response body */ - head_buf = ngx_http_groonga_grn_obj_to_ngx_buf(r->pool, &(data->head)); + head_buf = ngx_http_groonga_grn_obj_to_ngx_buf(r->pool, &(data->typed.head)); if (!head_buf) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - body_buf = ngx_http_groonga_grn_obj_to_ngx_buf(r->pool, &(data->body)); + body_buf = ngx_http_groonga_grn_obj_to_ngx_buf(r->pool, &(data->typed.body)); if (!body_buf) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - foot_buf = ngx_http_groonga_grn_obj_to_ngx_buf(r->pool, &(data->foot)); + foot_buf = ngx_http_groonga_grn_obj_to_ngx_buf(r->pool, &(data->typed.foot)); if (!foot_buf) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -778,9 +947,9 @@ ngx_http_groonga_handler_send_response(ngx_http_request_t *r, /* set the status line */ r->headers_out.status = NGX_HTTP_OK; - r->headers_out.content_length_n = GRN_TEXT_LEN(&(data->head)) + - GRN_TEXT_LEN(&(data->body)) + - GRN_TEXT_LEN(&(data->foot)); + r->headers_out.content_length_n = GRN_TEXT_LEN(&(data->typed.head)) + + GRN_TEXT_LEN(&(data->typed.body)) + + GRN_TEXT_LEN(&(data->typed.foot)); if (r->headers_out.content_length_n == 0) { r->header_only = 1; } @@ -1072,7 +1241,7 @@ ngx_http_groonga_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) GRN_CACHE_DEFAULT_MAX_N_ENTRIES); #ifdef NGX_HTTP_GROONGA_LOG_PATH - { + if (!conf->log_file) { ngx_str_t default_log_path; default_log_path.data = (u_char *)NGX_HTTP_GROONGA_LOG_PATH; default_log_path.len = strlen(NGX_HTTP_GROONGA_LOG_PATH); @@ -1085,8 +1254,6 @@ ngx_http_groonga_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } } -#else - conf->log_file = NULL; #endif ngx_conf_merge_str_value(conf->query_log_path, prev->query_log_path, |