1 /*
2  * Redistribution and use in source and binary forms, with or
3  * without modification, are permitted provided that the following
4  * conditions are met:
5  *
6  * 1. Redistributions of source code must retain the above
7  *    copyright notice, this list of conditions and the
8  *    following disclaimer.
9  *
10  * 2. Redistributions in binary form must reproduce the above
11  *    copyright notice, this list of conditions and the following
12  *    disclaimer in the documentation and/or other materials
13  *    provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY AUTHORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
19  * AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * Copyright (C) 2015-2016 Tarantool AUTHORS:
30  * please see AUTHORS file.
31  */
32 
33 #ifndef NGX_HTTP_TNT_CREATE_REQUEST_H_INCLUDED
34 #define NGX_HTTP_TNT_CREATE_REQUEST_H_INCLUDED
35 
36 #include <ngx_core.h>
37 #include <ngx_http.h>
38 #include <tp_transcode.h>
39 
40 typedef enum ngx_tnt_conf_states {
41     NGX_TNT_CONF_ON         = 0x0001,
42     NGX_TNT_CONF_OFF        = 0x0002,
43     NGX_TNT_CONF_PARSE_ARGS = 0x0004
44 } ngx_tnt_conf_states_e;
45 
46 typedef struct {
47     ngx_http_upstream_conf_t upstream;
48     ngx_int_t                index;
49 
50     size_t                   in_multiplier;
51     size_t                   out_multiplier;
52 
53     /** Preset method name
54      *
55      * if method is set then tp_transcode use only this method name and
56      * ignore method name from json and uri
57      */
58     ngx_str_t                method;
59 
60     /** Max allowed size of query + headers in bytes
61      */
62     size_t                   pass_http_request_buffer_size;
63 
64     /** Pass query/headers to tarantool
65      *
66      *  If this is set, then Tarantool recv. query args as lua table, e.g.
67      *  /tnt_method?arg1=X&arg2=123
68      *
69      *  Tarantool
70      *  function tnt_method(http_req)
71      *  {
72      *    http_req['args']['arg1'] -- eq 'Y'
73      *    http_req['args']['arg2'] -- eq '123'
74      *  }
75      */
76     ngx_uint_t               pass_http_request;
77 
78     /** Http REST methods[default GET|PUT]
79      *
80      * if method in http_rest_methods, then tp_transcode expecting method name
81      * in url part, i.e. HOST/METHOD_NAME/TAIL?ARGS
82      *
83      * XXX Also see method
84      */
85     ngx_uint_t               http_rest_methods;
86 
87     /** Set of http methods[default POST|DELETE]
88      *
89      * If method in http_methods, then tp_transcode expecting method name in
90      * json protocol, i.e. {"method":STR}
91      *
92      * XXX Also see method
93      */
94     ngx_uint_t               http_methods;
95 
96     /** If is set to 'On', then the client will recv. pure result set, e.g.
97      * {}
98      * Otherwise
99      * {"result":[], "id": NUM}
100      */
101     ngx_uint_t               pure_result;
102 
103     /** Tarantool returns array of array as the result set of call,
104      * this option helps to avoid this behavior.
105      * For instance. If this option set to 2 then result will look
106      * alike result:{} instead of result:[[{}]]
107      */
108     ngx_uint_t               multireturn_skip_count;
109 
110     ngx_array_t                   *headers_source;
111 
112 } ngx_http_tnt_loc_conf_t;
113 
114 
115 /** Set of allowed rest methods
116  */
117 static const ngx_uint_t ngx_http_tnt_allowed_methods =
118     (NGX_HTTP_POST|NGX_HTTP_GET|NGX_HTTP_PUT|NGX_HTTP_DELETE);
119 
120 /** Current upstream state
121  */
122 enum ctx_state {
123     OK = 0,
124 
125     INPUT_JSON_PARSE_FAILED,
126     INPUT_TO_LARGE,
127     INPUT_EMPTY,
128 
129     READ_PAYLOAD,
130     READ_BODY,
131     SEND_REPLY
132 };
133 
134 typedef struct ngx_http_tnt_ctx {
135 
136     /** Reference to Tarantool payload e.g. size of TP message
137      */
138     struct {
139         u_char mem[6];
140         u_char *p, *e;
141     } payload;
142 
143     enum ctx_state     state;
144     /** in_err - error buffer
145      *  tp_cache - buffer for store parts of TP message
146      */
147     ngx_buf_t          *in_err, *tp_cache;
148 
149     /** rest - how many bytes until transcoding is end
150      *  payload_size - payload as int val
151      *  rest_batch_size - how many parts until batch is end
152      *  batch_size - number of parts in batch
153      */
154     ssize_t            rest, payload_size;
155     int                rest_batch_size, batch_size;
156 
157     /** Greeting from tarantool
158      */
159     ngx_int_t          greeting:1;
160 
161     /** preset method & len
162      */
163     u_char             preset_method[128];
164     u_char             preset_method_len;
165 } ngx_http_tnt_ctx_t;
166 
167 ngx_http_tnt_ctx_t * ngx_http_tnt_create_ctx(ngx_http_request_t *r);
168 void ngx_http_tnt_reset_ctx(ngx_http_tnt_ctx_t *ctx);
169 
170 ngx_int_t ngx_http_tnt_init_handlers(ngx_http_request_t *r,
171                                      ngx_http_upstream_t *u,
172                                      ngx_http_tnt_loc_conf_t *tlcf);
173 
174 /** create tarantool requests handlers [
175  */
176 ngx_int_t ngx_http_tnt_body_json_handler(ngx_http_request_t *r);
177 ngx_int_t ngx_http_tnt_query_handler(ngx_http_request_t *r);
178 /* ] */
179 
180 ngx_int_t ngx_http_tnt_reinit_request(ngx_http_request_t *r);
181 ngx_int_t ngx_http_tnt_process_header(ngx_http_request_t *r);
182 void ngx_http_tnt_abort_request(ngx_http_request_t *r);
183 void ngx_http_tnt_finalize_request(ngx_http_request_t *r, ngx_int_t rc);
184 
185 ngx_buf_t* ngx_http_tnt_set_err(ngx_http_request_t *r,
186                                 int errcode,
187                                 const u_char *msg,
188                                 size_t msglen);
189 
190 /** Rrror & error code holder, functions [[
191  */
192 typedef struct ngx_http_tnt_error {
193     const ngx_str_t msg;
194     int code;
195 } ngx_http_tnt_error_t;
196 
197 enum ngx_http_tnt_err_messages_idx {
198     REQUEST_TOO_LARGE   = 0,
199     UNKNOWN_PARSE_ERROR = 1,
200     HTTP_REQUEST_TOO_LARGE = 2
201 };
202 
203 const ngx_http_tnt_error_t *get_error_text(int type);
204 /** ]]
205  */
206 
207 /** Size of JSON proto overhead
208  */
209 static inline size_t
ngx_http_tnt_overhead(void)210 ngx_http_tnt_overhead(void)
211 {
212     return sizeof("[{"
213         "'error': {"
214             "'code':-XXXXX,"
215             "'message':''"
216         "},"
217         "[['result':{},"
218         "'id':4294967295]]"
219     "}");
220 }
221 
222 #endif
223