2 * uclient - ustream based protocol client library
4 * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <libubox/ustream-ssl.h>
20 #include "uclient-utils.h"
21 #include "uclient-backend.h"
23 struct uclient_url __hidden
*
24 uclient_get_url(const char *url_str
, const char *auth_str
)
26 static const struct uclient_backend
*backends
[] = {
27 &uclient_backend_http
,
30 const struct uclient_backend
*backend
;
31 const char * const *prefix
= NULL
;
32 struct uclient_url
*url
;
34 char *host_buf
, *uri_buf
, *auth_buf
, *next
;
37 for (i
= 0; i
< ARRAY_SIZE(backends
); i
++) {
40 for (prefix
= backends
[i
]->prefix
; *prefix
; prefix
++) {
41 prefix_len
= strlen(*prefix
);
43 if (!strncmp(url_str
, *prefix
, prefix_len
))
50 url_str
+= prefix_len
;
51 backend
= backends
[i
];
58 next
= strchr(url_str
, '/');
61 host_len
= next
- url_str
;
64 host_len
= strlen(url_str
);
67 url
= calloc_a(sizeof(*url
),
68 &host_buf
, host_len
+ 1,
69 &uri_buf
, strlen(location
) + 1,
70 &auth_buf
, auth_str
? strlen(auth_str
) + 1 : 0);
72 url
->backend
= backend
;
73 url
->location
= strcpy(uri_buf
, location
);
74 url
->prefix
= prefix
- backend
->prefix
;
76 url
->host
= strncpy(host_buf
, url_str
, host_len
);
78 next
= strchr(host_buf
, '@');
83 if (uclient_urldecode(host_buf
, host_buf
, false) < 0)
89 if (!url
->auth
&& auth_str
)
90 url
->auth
= strcpy(auth_buf
, auth_str
);
92 /* Literal IPv6 address */
93 if (*url
->host
== '[') {
95 next
= strrchr(url
->host
, ']');
101 url
->port
= next
+ 1;
103 next
= strrchr(url
->host
, ':');
105 url
->port
= next
+ 1;
115 struct uclient
*uclient_new(const char *url_str
, const char *auth_str
, const struct uclient_cb
*cb
)
118 struct uclient_url
*url
;
120 url
= uclient_get_url(url_str
, auth_str
);
124 cl
= url
->backend
->alloc();
128 cl
->backend
= url
->backend
;
135 int uclient_set_url(struct uclient
*cl
, const char *url_str
)
137 const struct uclient_backend
*backend
= cl
->backend
;
138 struct uclient_url
*url
= cl
->url
;
140 url
= uclient_get_url(url_str
, NULL
);
144 if (url
->backend
!= cl
->backend
)
150 if (backend
->update_url
)
151 backend
->update_url(cl
);
156 int uclient_connect(struct uclient
*cl
)
158 return cl
->backend
->connect(cl
);
161 void uclient_free(struct uclient
*cl
)
163 struct uclient_url
*url
= cl
->url
;
165 if (cl
->backend
->free
)
166 cl
->backend
->free(cl
);
173 int uclient_write(struct uclient
*cl
, char *buf
, int len
)
175 if (!cl
->backend
->write
)
178 return cl
->backend
->write(cl
, buf
, len
);
181 int uclient_request(struct uclient
*cl
)
183 if (!cl
->backend
->request
)
186 return cl
->backend
->request(cl
);
189 int uclient_read(struct uclient
*cl
, char *buf
, int len
)
191 if (!cl
->backend
->read
)
194 return cl
->backend
->read(cl
, buf
, len
);
197 static void __uclient_backend_change_state(struct uloop_timeout
*timeout
)
199 struct uclient
*cl
= container_of(timeout
, struct uclient
, timeout
);
201 if (cl
->error_code
&& cl
->cb
->error
)
202 cl
->cb
->error(cl
, cl
->error_code
);
203 else if (cl
->eof
&& cl
->cb
->data_eof
)
204 cl
->cb
->data_eof(cl
);
207 static void uclient_backend_change_state(struct uclient
*cl
)
209 cl
->timeout
.cb
= __uclient_backend_change_state
;
210 uloop_timeout_set(&cl
->timeout
, 1);
213 void __hidden
uclient_backend_set_error(struct uclient
*cl
, int code
)
218 cl
->error_code
= code
;
219 uclient_backend_change_state(cl
);
222 void __hidden
uclient_backend_set_eof(struct uclient
*cl
)
224 if (cl
->eof
|| cl
->error_code
)
228 uclient_backend_change_state(cl
);
231 void __hidden
uclient_backend_reset_state(struct uclient
*cl
)
235 uloop_timeout_cancel(&cl
->timeout
);