fix prefix id passing
[project/uclient.git] / uclient.c
1 #include <libubox/ustream-ssl.h>
2 #include "uclient.h"
3 #include "uclient-utils.h"
4 #include "uclient-backend.h"
5
6 struct uclient_url __hidden *
7 uclient_get_url(const char *url_str, const char *auth_str)
8 {
9         static const struct uclient_backend *backends[] = {
10                 &uclient_backend_http,
11         };
12
13         const struct uclient_backend *backend;
14         const char * const *prefix = NULL;
15         struct uclient_url *url;
16         const char *location;
17         char *host_buf, *uri_buf, *auth_buf, *next;
18         int i, host_len;
19
20         for (i = 0; i < ARRAY_SIZE(backends); i++) {
21                 int prefix_len = 0;
22
23                 for (prefix = backends[i]->prefix; *prefix; prefix++) {
24                         prefix_len = strlen(*prefix);
25
26                         if (!strncmp(url_str, *prefix, prefix_len))
27                                 break;
28                 }
29
30                 if (!*prefix)
31                         continue;
32
33                 url_str += prefix_len;
34                 backend = backends[i];
35                 break;
36         }
37
38         if (!*prefix)
39                 return NULL;
40
41         next = strchr(url_str, '/');
42         if (next) {
43                 location = next;
44                 host_len = next - url_str;
45         } else {
46                 location = "/";
47                 host_len = strlen(url_str);
48         }
49
50         url = calloc_a(sizeof(*url),
51                 &host_buf, host_len + 1,
52                 &uri_buf, strlen(location) + 1,
53                 &auth_buf, auth_str ? strlen(auth_str) + 1 : 0);
54
55         url->backend = backend;
56         url->location = strcpy(uri_buf, location);
57         url->prefix = prefix - backend->prefix;
58
59         url->host = strncpy(host_buf, url_str, host_len);
60
61         next = strchr(host_buf, '@');
62         if (next) {
63                 *next = 0;
64                 url->host = next + 1;
65
66                 if (uclient_urldecode(host_buf, host_buf, false) < 0)
67                         goto free;
68
69                 url->auth = host_buf;
70         }
71
72         if (!url->auth && auth_str)
73                 url->auth = strcpy(auth_buf, auth_str);
74
75         /* Literal IPv6 address */
76         if (*url->host == '[') {
77                 url->host++;
78                 next = strrchr(url->host, ']');
79                 if (!next)
80                         goto free;
81
82                 *(next++) = 0;
83                 if (*next == ':')
84                         url->port = next + 1;
85         } else {
86                 next = strrchr(url->host, ':');
87                 if (next)
88                         url->port = next + 1;
89         }
90
91         return url;
92
93 free:
94         free(url);
95         return NULL;
96 }
97
98 struct uclient *uclient_new(const char *url_str, const struct uclient_cb *cb)
99 {
100         struct uclient *cl;
101         struct uclient_url *url;
102
103         url = uclient_get_url(url_str, NULL);
104         if (!url)
105                 return NULL;
106
107         cl = url->backend->alloc();
108         if (!cl)
109                 return NULL;
110
111         cl->backend = url->backend;
112         cl->cb = cb;
113         cl->url = url;
114
115         return cl;
116 }
117
118 int uclient_connect_url(struct uclient *cl, const char *url_str)
119 {
120         struct uclient_url *url = cl->url;
121         const struct uclient_backend *backend = cl->backend;
122
123         if (url_str) {
124                 url = uclient_get_url(url_str, NULL);
125                 if (!url)
126                         return -1;
127
128                 if (url->backend != cl->backend)
129                         return -1;
130
131                 free(cl->url);
132                 cl->url = url;
133
134                 if (backend->update_url)
135                         backend->update_url(cl);
136         }
137
138         return backend->connect(cl);
139 }
140
141 void uclient_free(struct uclient *cl)
142 {
143         struct uclient_url *url = cl->url;
144
145         if (cl->backend->free)
146                 cl->backend->free(cl);
147         else
148                 free(cl);
149
150         free(url);
151 }
152
153 int uclient_write(struct uclient *cl, char *buf, int len)
154 {
155         if (!cl->backend->write)
156                 return -1;
157
158         return cl->backend->write(cl, buf, len);
159 }
160
161 int uclient_request(struct uclient *cl)
162 {
163         if (!cl->backend->request)
164                 return -1;
165
166         return cl->backend->request(cl);
167 }
168
169 int uclient_read(struct uclient *cl, char *buf, int len)
170 {
171         if (!cl->backend->read)
172                 return -1;
173
174         return cl->backend->read(cl, buf, len);
175 }
176
177 static void __uclient_backend_change_state(struct uloop_timeout *timeout)
178 {
179         struct uclient *cl = container_of(timeout, struct uclient, timeout);
180
181         if (cl->error && cl->cb->error)
182                 cl->cb->error(cl);
183         else if (cl->eof && cl->cb->data_eof)
184                 cl->cb->data_eof(cl);
185 }
186
187 static void uclient_backend_change_state(struct uclient *cl)
188 {
189         cl->timeout.cb = __uclient_backend_change_state;
190         uloop_timeout_set(&cl->timeout, 1);
191 }
192
193 void __hidden uclient_backend_set_error(struct uclient *cl)
194 {
195         if (cl->error)
196                 return;
197
198         cl->error = true;
199         uclient_backend_change_state(cl);
200 }
201
202 void __hidden uclient_backend_set_eof(struct uclient *cl)
203 {
204         if (cl->eof || cl->error)
205                 return;
206
207         cl->eof = true;
208         uclient_backend_change_state(cl);
209 }
210
211 void __hidden uclient_backend_reset_state(struct uclient *cl)
212 {
213         cl->error = false;
214         cl->eof = false;
215         uloop_timeout_cancel(&cl->timeout);
216 }