xref: /unit/src/nxt_http_return.c (revision 2098:9a890f0c56aa)
1 
2 /*
3  * Copyright (C) NGINX, Inc.
4  */
5 
6 #include <nxt_router.h>
7 #include <nxt_http.h>
8 
9 
10 typedef struct {
11     nxt_http_status_t  status;
12     nxt_var_t          *location;
13     nxt_str_t          encoded;
14 } nxt_http_return_conf_t;
15 
16 
17 typedef struct {
18     nxt_str_t          location;
19     nxt_str_t          encoded;
20 } nxt_http_return_ctx_t;
21 
22 
23 static nxt_http_action_t *nxt_http_return(nxt_task_t *task,
24     nxt_http_request_t *r, nxt_http_action_t *action);
25 static nxt_int_t nxt_http_return_encode(nxt_mp_t *mp, nxt_str_t *encoded,
26     const nxt_str_t *location);
27 static void nxt_http_return_send_ready(nxt_task_t *task, void *obj, void *data);
28 static void nxt_http_return_var_error(nxt_task_t *task, void *obj, void *data);
29 
30 
31 static const nxt_http_request_state_t  nxt_http_return_send_state;
32 
33 
34 nxt_int_t
35 nxt_http_return_init(nxt_mp_t *mp, nxt_http_action_t *action,
36     nxt_http_action_conf_t *acf)
37 {
38     nxt_str_t               str;
39     nxt_http_return_conf_t  *conf;
40 
41     conf = nxt_mp_zget(mp, sizeof(nxt_http_return_conf_t));
42     if (nxt_slow_path(conf == NULL)) {
43         return NXT_ERROR;
44     }
45 
46     action->handler = nxt_http_return;
47     action->u.conf = conf;
48 
49     conf->status = nxt_conf_get_number(acf->ret);
50 
51     if (acf->location == NULL) {
52         return NXT_OK;
53     }
54 
55     nxt_conf_get_string(acf->location, &str);
56 
57     conf->location = nxt_var_compile(&str, mp, 0);
58     if (nxt_slow_path(conf->location == NULL)) {
59         return NXT_ERROR;
60     }
61 
62     if (nxt_var_is_const(conf->location)) {
63         nxt_var_raw(conf->location, &str);
64         return nxt_http_return_encode(mp, &conf->encoded, &str);
65     }
66 
67     return NXT_OK;
68 }
69 
70 
71 nxt_http_action_t *
72 nxt_http_return(nxt_task_t *task, nxt_http_request_t *r,
73     nxt_http_action_t *action)
74 {
75     nxt_int_t               ret;
76     nxt_str_t               loc;
77     nxt_http_return_ctx_t   *ctx;
78     nxt_http_return_conf_t  *conf;
79 
80     conf = action->u.conf;
81 
82     if (conf->location == NULL) {
83         nxt_str_null(&loc);
84 
85     } else {
86         nxt_var_raw(conf->location, &loc);
87     }
88 
89     nxt_debug(task, "http return: %d (loc: \"%V\")", conf->status, &loc);
90 
91     if (conf->status >= NXT_HTTP_BAD_REQUEST
92         && conf->status <= NXT_HTTP_SERVER_ERROR_MAX)
93     {
94         nxt_http_request_error(task, r, conf->status);
95         return NULL;
96     }
97 
98     if (conf->location == NULL) {
99         ctx = NULL;
100 
101     } else {
102         ctx = nxt_mp_zget(r->mem_pool, sizeof(nxt_http_return_ctx_t));
103         if (nxt_slow_path(ctx == NULL)) {
104             goto fail;
105         }
106     }
107 
108     r->status = conf->status;
109     r->resp.content_length_n = 0;
110 
111     if (ctx == NULL || nxt_var_is_const(conf->location)) {
112         if (ctx != NULL) {
113             ctx->encoded = conf->encoded;
114         }
115 
116         nxt_http_return_send_ready(task, r, ctx);
117 
118     } else {
119         ret = nxt_var_query_init(&r->var_query, r, r->mem_pool);
120         if (nxt_slow_path(ret != NXT_OK)) {
121             goto fail;
122         }
123 
124         nxt_var_query(task, r->var_query, conf->location, &ctx->location);
125 
126         nxt_var_query_resolve(task, r->var_query, ctx,
127                               nxt_http_return_send_ready,
128                               nxt_http_return_var_error);
129     }
130 
131     return NULL;
132 
133 fail:
134 
135     nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
136     return NULL;
137 }
138 
139 
140 static nxt_int_t
141 nxt_http_return_encode(nxt_mp_t *mp, nxt_str_t *encoded,
142     const nxt_str_t *location)
143 {
144     nxt_uint_t  encode;
145 
146     if (nxt_is_complex_uri_encoded(location->start, location->length)) {
147         *encoded = *location;
148 
149         return NXT_OK;
150     }
151 
152     encode = nxt_encode_complex_uri(NULL, location->start, location->length);
153     encoded->length = location->length + encode * 2;
154 
155     encoded->start = nxt_mp_nget(mp, encoded->length);
156     if (nxt_slow_path(encoded->start == NULL)) {
157         return NXT_ERROR;
158     }
159 
160     nxt_encode_complex_uri(encoded->start, location->start, location->length);
161 
162     return NXT_OK;
163 }
164 
165 
166 static void
167 nxt_http_return_send_ready(nxt_task_t *task, void *obj, void *data)
168 {
169     nxt_int_t               ret;
170     nxt_http_field_t        *field;
171     nxt_http_request_t      *r;
172     nxt_http_return_ctx_t   *ctx;
173 
174     r = obj;
175     ctx = data;
176 
177     if (ctx != NULL) {
178         if (ctx->location.length > 0) {
179             ret = nxt_http_return_encode(r->mem_pool, &ctx->encoded,
180                                          &ctx->location);
181             if (nxt_slow_path(ret == NXT_ERROR)) {
182                 goto fail;
183             }
184         }
185 
186         field = nxt_list_zero_add(r->resp.fields);
187         if (nxt_slow_path(field == NULL)) {
188             goto fail;
189         }
190 
191         nxt_http_field_name_set(field, "Location");
192 
193         field->value = ctx->encoded.start;
194         field->value_length = ctx->encoded.length;
195     }
196 
197     r->state = &nxt_http_return_send_state;
198 
199     nxt_http_request_header_send(task, r, NULL, NULL);
200 
201     return;
202 
203 fail:
204 
205     nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
206 }
207 
208 
209 static void
210 nxt_http_return_var_error(nxt_task_t *task, void *obj, void *data)
211 {
212     nxt_http_request_t  *r;
213 
214     r = obj;
215 
216     nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
217 }
218 
219 
220 static const nxt_http_request_state_t  nxt_http_return_send_state
221     nxt_aligned(64) =
222 {
223     .error_handler = nxt_http_request_error_handler,
224 };
225