uclient.c 4.9 KB

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