1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) NGINX, Inc.
5  */
6 
7 #include <nxt_router.h>
8 #include <nxt_http.h>
9 #include <nxt_upstream.h>
10 
11 
12 static nxt_http_action_t *nxt_upstream_handler(nxt_task_t *task,
13     nxt_http_request_t *r, nxt_http_action_t *action);
14 
15 
16 nxt_int_t
nxt_upstreams_create(nxt_task_t * task,nxt_router_temp_conf_t * tmcf,nxt_conf_value_t * conf)17 nxt_upstreams_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
18     nxt_conf_value_t *conf)
19 {
20     size_t            size;
21     uint32_t          i, n, next;
22     nxt_mp_t          *mp;
23     nxt_int_t         ret;
24     nxt_str_t         name, *string;
25     nxt_upstreams_t   *upstreams;
26     nxt_conf_value_t  *upstreams_conf, *upcf;
27 
28     static nxt_str_t  upstreams_name = nxt_string("upstreams");
29 
30     upstreams_conf = nxt_conf_get_object_member(conf, &upstreams_name, NULL);
31 
32     if (upstreams_conf == NULL) {
33         return NXT_OK;
34     }
35 
36     n = nxt_conf_object_members_count(upstreams_conf);
37 
38     if (n == 0) {
39         return NXT_OK;
40     }
41 
42     mp = tmcf->router_conf->mem_pool;
43     size = sizeof(nxt_upstreams_t) + n * sizeof(nxt_upstream_t);
44 
45     upstreams = nxt_mp_zalloc(mp, size);
46     if (nxt_slow_path(upstreams == NULL)) {
47         return NXT_ERROR;
48     }
49 
50     upstreams->items = n;
51     next = 0;
52 
53     for (i = 0; i < n; i++) {
54         upcf = nxt_conf_next_object_member(upstreams_conf, &name, &next);
55 
56         string = nxt_str_dup(mp, &upstreams->upstream[i].name, &name);
57         if (nxt_slow_path(string == NULL)) {
58             return NXT_ERROR;
59         }
60 
61         ret = nxt_upstream_round_robin_create(task, tmcf, upcf,
62                                               &upstreams->upstream[i]);
63         if (nxt_slow_path(ret != NXT_OK)) {
64             return NXT_ERROR;
65         }
66     }
67 
68     tmcf->router_conf->upstreams = upstreams;
69 
70     return NXT_OK;
71 }
72 
73 
74 nxt_int_t
nxt_upstream_find(nxt_upstreams_t * upstreams,nxt_str_t * name,nxt_http_action_t * action)75 nxt_upstream_find(nxt_upstreams_t *upstreams, nxt_str_t *name,
76     nxt_http_action_t *action)
77 {
78     uint32_t        i, n;
79     nxt_upstream_t  *upstream;
80 
81     if (upstreams == NULL) {
82         return NXT_DECLINED;
83     }
84 
85     upstream = &upstreams->upstream[0];
86     n = upstreams->items;
87 
88     for (i = 0; i < n; i++) {
89         if (nxt_strstr_eq(&upstream[i].name, name)) {
90             action->u.upstream_number = i;
91             action->handler = nxt_upstream_handler;
92 
93             return NXT_OK;
94         }
95     }
96 
97     return NXT_DECLINED;
98 }
99 
100 
101 nxt_int_t
nxt_upstreams_joint_create(nxt_router_temp_conf_t * tmcf,nxt_upstream_t *** upstream_joint)102 nxt_upstreams_joint_create(nxt_router_temp_conf_t *tmcf,
103     nxt_upstream_t ***upstream_joint)
104 {
105     uint32_t           i, n;
106     nxt_upstream_t     *u, **up;
107     nxt_upstreams_t    *upstreams;
108     nxt_router_conf_t  *router_conf;
109 
110     router_conf = tmcf->router_conf;
111     upstreams = router_conf->upstreams;
112 
113     if (upstreams == NULL) {
114         *upstream_joint = NULL;
115         return NXT_OK;
116     }
117 
118     n = upstreams->items;
119 
120     up = nxt_mp_zalloc(router_conf->mem_pool, n * sizeof(nxt_upstream_t *));
121     if (nxt_slow_path(up == NULL)) {
122         return NXT_ERROR;
123     }
124 
125     u = &upstreams->upstream[0];
126 
127     for (i = 0; i < n; i++) {
128         up[i] = u[i].proto->joint_create(tmcf, &u[i]);
129         if (nxt_slow_path(up[i] == NULL)) {
130             return NXT_ERROR;
131         }
132     }
133 
134     *upstream_joint = up;
135 
136     return NXT_OK;
137 }
138 
139 
140 static nxt_http_action_t *
nxt_upstream_handler(nxt_task_t * task,nxt_http_request_t * r,nxt_http_action_t * action)141 nxt_upstream_handler(nxt_task_t *task, nxt_http_request_t *r,
142     nxt_http_action_t *action)
143 {
144     nxt_upstream_t  *u;
145 
146     u = r->conf->upstreams[action->u.upstream_number];
147 
148     nxt_debug(task, "upstream handler: \"%V\"", &u->name);
149 
150     return nxt_upstream_proxy_handler(task, r, u);
151 }
152