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
nxt_http_return_init(nxt_mp_t * mp,nxt_http_action_t * action,nxt_http_action_conf_t * acf)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 *
nxt_http_return(nxt_task_t * task,nxt_http_request_t * r,nxt_http_action_t * action)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_http_return_ctx_t *ctx;
77 nxt_http_return_conf_t *conf;
78
79 conf = action->u.conf;
80
81 #if (NXT_DEBUG)
82 nxt_str_t loc;
83
84 if (conf->location == NULL) {
85 nxt_str_set(&loc, "");
86
87 } else {
88 nxt_var_raw(conf->location, &loc);
89 }
90
91 nxt_debug(task, "http return: %d (loc: \"%V\")", conf->status, &loc);
92 #endif
93
94 if (conf->status >= NXT_HTTP_BAD_REQUEST
95 && conf->status <= NXT_HTTP_SERVER_ERROR_MAX)
96 {
97 nxt_http_request_error(task, r, conf->status);
98 return NULL;
99 }
100
101 if (conf->location == NULL) {
102 ctx = NULL;
103
104 } else {
105 ctx = nxt_mp_zget(r->mem_pool, sizeof(nxt_http_return_ctx_t));
106 if (nxt_slow_path(ctx == NULL)) {
107 goto fail;
108 }
109 }
110
111 r->status = conf->status;
112 r->resp.content_length_n = 0;
113
114 if (ctx == NULL || nxt_var_is_const(conf->location)) {
115 if (ctx != NULL) {
116 ctx->encoded = conf->encoded;
117 }
118
119 nxt_http_return_send_ready(task, r, ctx);
120
121 } else {
122 ret = nxt_var_query_init(&r->var_query, r, r->mem_pool);
123 if (nxt_slow_path(ret != NXT_OK)) {
124 goto fail;
125 }
126
127 nxt_var_query(task, r->var_query, conf->location, &ctx->location);
128
129 nxt_var_query_resolve(task, r->var_query, ctx,
130 nxt_http_return_send_ready,
131 nxt_http_return_var_error);
132 }
133
134 return NULL;
135
136 fail:
137
138 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
139 return NULL;
140 }
141
142
143 static nxt_int_t
nxt_http_return_encode(nxt_mp_t * mp,nxt_str_t * encoded,const nxt_str_t * location)144 nxt_http_return_encode(nxt_mp_t *mp, nxt_str_t *encoded,
145 const nxt_str_t *location)
146 {
147 nxt_uint_t encode;
148
149 if (nxt_is_complex_uri_encoded(location->start, location->length)) {
150 *encoded = *location;
151
152 return NXT_OK;
153 }
154
155 encode = nxt_encode_complex_uri(NULL, location->start, location->length);
156 encoded->length = location->length + encode * 2;
157
158 encoded->start = nxt_mp_nget(mp, encoded->length);
159 if (nxt_slow_path(encoded->start == NULL)) {
160 return NXT_ERROR;
161 }
162
163 nxt_encode_complex_uri(encoded->start, location->start, location->length);
164
165 return NXT_OK;
166 }
167
168
169 static void
nxt_http_return_send_ready(nxt_task_t * task,void * obj,void * data)170 nxt_http_return_send_ready(nxt_task_t *task, void *obj, void *data)
171 {
172 nxt_int_t ret;
173 nxt_http_field_t *field;
174 nxt_http_request_t *r;
175 nxt_http_return_ctx_t *ctx;
176
177 r = obj;
178 ctx = data;
179
180 if (ctx != NULL) {
181 if (ctx->location.length > 0) {
182 ret = nxt_http_return_encode(r->mem_pool, &ctx->encoded,
183 &ctx->location);
184 if (nxt_slow_path(ret == NXT_ERROR)) {
185 goto fail;
186 }
187 }
188
189 field = nxt_list_zero_add(r->resp.fields);
190 if (nxt_slow_path(field == NULL)) {
191 goto fail;
192 }
193
194 nxt_http_field_name_set(field, "Location");
195
196 field->value = ctx->encoded.start;
197 field->value_length = ctx->encoded.length;
198 }
199
200 r->state = &nxt_http_return_send_state;
201
202 nxt_http_request_header_send(task, r, NULL, NULL);
203
204 return;
205
206 fail:
207
208 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
209 }
210
211
212 static void
nxt_http_return_var_error(nxt_task_t * task,void * obj,void * data)213 nxt_http_return_var_error(nxt_task_t *task, void *obj, void *data)
214 {
215 nxt_http_request_t *r;
216
217 r = obj;
218
219 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
220 }
221
222
223 static const nxt_http_request_state_t nxt_http_return_send_state
224 nxt_aligned(64) =
225 {
226 .error_handler = nxt_http_request_error_handler,
227 };
228