summaryrefslogtreecommitdiff
path: root/storage/mroonga/vendor/groonga/src/httpd/nginx-module/ngx_http_groonga_module.c
diff options
context:
space:
mode:
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.c277
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,