xref: /unit/src/nxt_http_return.c (revision 2247:baa6b9879267)
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_tstr_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_send_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_router_conf_t * rtcf,nxt_http_action_t * action,nxt_http_action_conf_t * acf)35 nxt_http_return_init(nxt_router_conf_t *rtcf, nxt_http_action_t *action,
36     nxt_http_action_conf_t *acf)
37 {
38     nxt_mp_t                *mp;
39     nxt_str_t               str;
40     nxt_http_return_conf_t  *conf;
41 
42     mp = rtcf->mem_pool;
43 
44     conf = nxt_mp_zget(mp, sizeof(nxt_http_return_conf_t));
45     if (nxt_slow_path(conf == NULL)) {
46         return NXT_ERROR;
47     }
48 
49     action->handler = nxt_http_return;
50     action->u.conf = conf;
51 
52     conf->status = nxt_conf_get_number(acf->ret);
53 
54     if (acf->location == NULL) {
55         return NXT_OK;
56     }
57 
58     nxt_conf_get_string(acf->location, &str);
59 
60     conf->location = nxt_tstr_compile(rtcf->tstr_state, &str, 0);
61     if (nxt_slow_path(conf->location == NULL)) {
62         return NXT_ERROR;
63     }
64 
65     if (nxt_tstr_is_const(conf->location)) {
66         nxt_tstr_str(conf->location, &str);
67         return nxt_http_return_encode(mp, &conf->encoded, &str);
68     }
69 
70     return NXT_OK;
71 }
72 
73 
74 nxt_http_action_t *
nxt_http_return(nxt_task_t * task,nxt_http_request_t * r,nxt_http_action_t * action)75 nxt_http_return(nxt_task_t *task, nxt_http_request_t *r,
76     nxt_http_action_t *action)
77 {
78     nxt_int_t               ret;
79     nxt_router_conf_t       *rtcf;
80     nxt_http_return_ctx_t   *ctx;
81     nxt_http_return_conf_t  *conf;
82 
83     conf = action->u.conf;
84 
85 #if (NXT_DEBUG)
86     nxt_str_t  loc;
87 
88     if (conf->location == NULL) {
89         nxt_str_set(&loc, "");
90 
91     } else {
92         nxt_tstr_str(conf->location, &loc);
93     }
94 
95     nxt_debug(task, "http return: %d (loc: \"%V\")", conf->status, &loc);
96 #endif
97 
98     if (conf->status >= NXT_HTTP_BAD_REQUEST
99         && conf->status <= NXT_HTTP_SERVER_ERROR_MAX)
100     {
101         nxt_http_request_error(task, r, conf->status);
102         return NULL;
103     }
104 
105     if (conf->location == NULL) {
106         ctx = NULL;
107 
108     } else {
109         ctx = nxt_mp_zget(r->mem_pool, sizeof(nxt_http_return_ctx_t));
110         if (nxt_slow_path(ctx == NULL)) {
111             goto fail;
112         }
113     }
114 
115     r->status = conf->status;
116     r->resp.content_length_n = 0;
117 
118     if (ctx == NULL || nxt_tstr_is_const(conf->location)) {
119         if (ctx != NULL) {
120             ctx->encoded = conf->encoded;
121         }
122 
123         nxt_http_return_send_ready(task, r, ctx);
124 
125     } else {
126         rtcf = r->conf->socket_conf->router_conf;
127 
128         ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state,
129                                   &r->tstr_cache, r, r->mem_pool);
130         if (nxt_slow_path(ret != NXT_OK)) {
131             goto fail;
132         }
133 
134         nxt_tstr_query(task, r->tstr_query, conf->location, &ctx->location);
135 
136         nxt_tstr_query_resolve(task, r->tstr_query, ctx,
137                                nxt_http_return_send_ready,
138                                nxt_http_return_send_error);
139     }
140 
141     return NULL;
142 
143 fail:
144 
145     nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
146     return NULL;
147 }
148 
149 
150 static nxt_int_t
nxt_http_return_encode(nxt_mp_t * mp,nxt_str_t * encoded,const nxt_str_t * location)151 nxt_http_return_encode(nxt_mp_t *mp, nxt_str_t *encoded,
152     const nxt_str_t *location)
153 {
154     nxt_uint_t  encode;
155 
156     if (nxt_is_complex_uri_encoded(location->start, location->length)) {
157         *encoded = *location;
158 
159         return NXT_OK;
160     }
161 
162     encode = nxt_encode_complex_uri(NULL, location->start, location->length);
163     encoded->length = location->length + encode * 2;
164 
165     encoded->start = nxt_mp_nget(mp, encoded->length);
166     if (nxt_slow_path(encoded->start == NULL)) {
167         return NXT_ERROR;
168     }
169 
170     nxt_encode_complex_uri(encoded->start, location->start, location->length);
171 
172     return NXT_OK;
173 }
174 
175 
176 static void
nxt_http_return_send_ready(nxt_task_t * task,void * obj,void * data)177 nxt_http_return_send_ready(nxt_task_t *task, void *obj, void *data)
178 {
179     nxt_int_t               ret;
180     nxt_http_field_t        *field;
181     nxt_http_request_t      *r;
182     nxt_http_return_ctx_t   *ctx;
183 
184     r = obj;
185     ctx = data;
186 
187     if (ctx != NULL) {
188         if (ctx->location.length > 0) {
189             ret = nxt_http_return_encode(r->mem_pool, &ctx->encoded,
190                                          &ctx->location);
191             if (nxt_slow_path(ret == NXT_ERROR)) {
192                 goto fail;
193             }
194         }
195 
196         field = nxt_list_zero_add(r->resp.fields);
197         if (nxt_slow_path(field == NULL)) {
198             goto fail;
199         }
200 
201         nxt_http_field_name_set(field, "Location");
202 
203         field->value = ctx->encoded.start;
204         field->value_length = ctx->encoded.length;
205     }
206 
207     r->state = &nxt_http_return_send_state;
208 
209     nxt_http_request_header_send(task, r, NULL, NULL);
210 
211     return;
212 
213 fail:
214 
215     nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
216 }
217 
218 
219 static void
nxt_http_return_send_error(nxt_task_t * task,void * obj,void * data)220 nxt_http_return_send_error(nxt_task_t *task, void *obj, void *data)
221 {
222     nxt_http_request_t  *r;
223 
224     r = obj;
225 
226     nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
227 }
228 
229 
230 static const nxt_http_request_state_t  nxt_http_return_send_state
231     nxt_aligned(64) =
232 {
233     .error_handler = nxt_http_request_error_handler,
234 };
235