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