uclient-http.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include <unistd.h>
  4. #include <libubox/ustream.h>
  5. #include <libubox/ustream-ssl.h>
  6. #include <libubox/usock.h>
  7. #include <libubox/blobmsg.h>
  8. #include "uclient.h"
  9. #include "uclient-utils.h"
  10. #include "uclient-backend.h"
  11. static struct ustream_ssl_ctx *ssl_ctx;
  12. enum request_type {
  13. REQ_GET,
  14. REQ_HEAD,
  15. REQ_POST,
  16. __REQ_MAX
  17. };
  18. enum http_state {
  19. HTTP_STATE_INIT,
  20. HTTP_STATE_HEADERS_SENT,
  21. HTTP_STATE_REQUEST_DONE,
  22. HTTP_STATE_RECV_HEADERS,
  23. HTTP_STATE_RECV_DATA,
  24. HTTP_STATE_ERROR,
  25. };
  26. static const char * const request_types[__REQ_MAX] = {
  27. [REQ_GET] = "GET",
  28. [REQ_HEAD] = "HEAD",
  29. [REQ_POST] = "POST",
  30. };
  31. struct uclient_http {
  32. struct uclient uc;
  33. struct ustream *us;
  34. struct ustream_fd ufd;
  35. struct ustream_ssl ussl;
  36. bool ssl;
  37. enum request_type req_type;
  38. enum http_state state;
  39. unsigned int send_len;
  40. struct blob_buf headers;
  41. struct blob_buf meta;
  42. };
  43. enum {
  44. PREFIX_HTTP,
  45. PREFIX_HTTPS,
  46. __PREFIX_MAX,
  47. };
  48. static const char * const uclient_http_prefix[] = {
  49. [PREFIX_HTTP] = "http://",
  50. [PREFIX_HTTPS] = "https://",
  51. [__PREFIX_MAX] = NULL
  52. };
  53. static int uclient_do_connect(struct uclient_http *uh, const char *port)
  54. {
  55. int fd;
  56. if (uh->uc.url->port)
  57. port = uh->uc.url->port;
  58. fd = usock(USOCK_TCP | USOCK_NONBLOCK, uh->uc.url->host, port);
  59. if (fd < 0)
  60. return -1;
  61. ustream_fd_init(&uh->ufd, fd);
  62. return 0;
  63. }
  64. static void uclient_notify_eof(struct uclient_http *uh)
  65. {
  66. struct ustream *us = uh->us;
  67. if (!us->eof && !us->write_error)
  68. return;
  69. if (ustream_pending_data(us, false))
  70. return;
  71. uclient_backend_set_eof(&uh->uc);
  72. }
  73. static void uclient_parse_http_line(struct uclient_http *uh, char *data)
  74. {
  75. char *name;
  76. char *sep;
  77. if (uh->state == HTTP_STATE_REQUEST_DONE) {
  78. uh->state = HTTP_STATE_RECV_HEADERS;
  79. return;
  80. }
  81. if (!*data) {
  82. uh->state = HTTP_STATE_RECV_DATA;
  83. uh->uc.meta = uh->meta.head;
  84. if (uh->uc.cb->header_done)
  85. uh->uc.cb->header_done(&uh->uc);
  86. return;
  87. }
  88. sep = strchr(data, ':');
  89. if (!sep)
  90. return;
  91. *(sep++) = 0;
  92. for (name = data; *name; name++)
  93. *name = tolower(*name);
  94. name = data;
  95. while (isspace(*sep))
  96. sep++;
  97. blobmsg_add_string(&uh->meta, name, sep);
  98. }
  99. static void __uclient_notify_read(struct uclient_http *uh)
  100. {
  101. struct uclient *uc = &uh->uc;
  102. char *data;
  103. int len;
  104. if (uh->state < HTTP_STATE_REQUEST_DONE)
  105. return;
  106. data = ustream_get_read_buf(uh->us, &len);
  107. if (!data || !len)
  108. return;
  109. if (uh->state < HTTP_STATE_RECV_DATA) {
  110. char *sep;
  111. int cur_len;
  112. do {
  113. sep = strstr(data, "\r\n");
  114. if (!sep)
  115. break;
  116. /* Check for multi-line HTTP headers */
  117. if (sep > data) {
  118. if (!sep[2])
  119. return;
  120. if (isspace(sep[2]) && sep[2] != '\r') {
  121. sep[0] = ' ';
  122. sep[1] = ' ';
  123. continue;
  124. }
  125. }
  126. *sep = 0;
  127. cur_len = sep + 2 - data;
  128. uclient_parse_http_line(uh, data);
  129. ustream_consume(uh->us, cur_len);
  130. len -= cur_len;
  131. data = ustream_get_read_buf(uh->us, &len);
  132. } while (uh->state < HTTP_STATE_RECV_DATA);
  133. if (!len)
  134. return;
  135. }
  136. if (uh->state == HTTP_STATE_RECV_DATA && uc->cb->data_read)
  137. uc->cb->data_read(uc);
  138. }
  139. static void uclient_notify_read(struct ustream *us, int bytes)
  140. {
  141. struct uclient_http *uh = container_of(us, struct uclient_http, ufd.stream);
  142. __uclient_notify_read(uh);
  143. }
  144. static void uclient_notify_state(struct ustream *us)
  145. {
  146. struct uclient_http *uh = container_of(us, struct uclient_http, ufd.stream);
  147. uclient_notify_eof(uh);
  148. }
  149. static int uclient_setup_http(struct uclient_http *uh)
  150. {
  151. struct ustream *us = &uh->ufd.stream;
  152. int ret;
  153. uh->us = us;
  154. us->string_data = true;
  155. us->notify_state = uclient_notify_state;
  156. us->notify_read = uclient_notify_read;
  157. ret = uclient_do_connect(uh, "80");
  158. if (ret)
  159. return ret;
  160. return 0;
  161. }
  162. static void uclient_ssl_notify_read(struct ustream *us, int bytes)
  163. {
  164. struct uclient_http *uh = container_of(us, struct uclient_http, ussl.stream);
  165. __uclient_notify_read(uh);
  166. }
  167. static void uclient_ssl_notify_state(struct ustream *us)
  168. {
  169. struct uclient_http *uh = container_of(us, struct uclient_http, ussl.stream);
  170. uclient_notify_eof(uh);
  171. }
  172. static int uclient_setup_https(struct uclient_http *uh)
  173. {
  174. struct ustream *us = &uh->ussl.stream;
  175. int ret;
  176. uh->ssl = true;
  177. uh->us = us;
  178. ret = uclient_do_connect(uh, "443");
  179. if (ret)
  180. return ret;
  181. if (!ssl_ctx)
  182. ssl_ctx = ustream_ssl_context_new(false);
  183. us->string_data = true;
  184. us->notify_state = uclient_ssl_notify_state;
  185. us->notify_read = uclient_ssl_notify_read;
  186. ustream_ssl_init(&uh->ussl, &uh->ufd.stream, ssl_ctx, false);
  187. return 0;
  188. }
  189. static void uclient_http_disconnect(struct uclient_http *uh)
  190. {
  191. uclient_backend_reset_state(&uh->uc);
  192. if (!uh->us)
  193. return;
  194. if (uh->ssl)
  195. ustream_free(&uh->ussl.stream);
  196. ustream_free(&uh->ufd.stream);
  197. close(uh->ufd.fd.fd);
  198. uh->us = NULL;
  199. }
  200. static int uclient_http_connect(struct uclient *cl)
  201. {
  202. struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
  203. uclient_http_disconnect(uh);
  204. blob_buf_init(&uh->meta, 0);
  205. uh->ssl = cl->url->prefix == PREFIX_HTTPS;
  206. uh->state = HTTP_STATE_INIT;
  207. if (uh->ssl)
  208. return uclient_setup_https(uh);
  209. else
  210. return uclient_setup_http(uh);
  211. }
  212. static struct uclient *uclient_http_alloc(void)
  213. {
  214. struct uclient_http *uh;
  215. uh = calloc_a(sizeof(*uh));
  216. blob_buf_init(&uh->headers, 0);
  217. return &uh->uc;
  218. }
  219. static void uclient_http_free(struct uclient *cl)
  220. {
  221. struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
  222. uclient_http_disconnect(uh);
  223. blob_buf_free(&uh->headers);
  224. blob_buf_free(&uh->meta);
  225. free(uh);
  226. }
  227. int
  228. uclient_http_set_request_type(struct uclient *cl, const char *type)
  229. {
  230. struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
  231. int i;
  232. if (cl->backend != &uclient_backend_http)
  233. return -1;
  234. if (uh->state > HTTP_STATE_INIT)
  235. return -1;
  236. for (i = 0; i < ARRAY_SIZE(request_types); i++) {
  237. if (strcmp(request_types[i], type) != 0)
  238. continue;
  239. uh->req_type = i;
  240. return 0;
  241. }
  242. return -1;
  243. }
  244. int
  245. uclient_http_reset_headers(struct uclient *cl, const char *name, const char *value)
  246. {
  247. struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
  248. blob_buf_init(&uh->headers, 0);
  249. return 0;
  250. }
  251. int
  252. uclient_http_set_header(struct uclient *cl, const char *name, const char *value)
  253. {
  254. struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
  255. if (cl->backend != &uclient_backend_http)
  256. return -1;
  257. if (uh->state > HTTP_STATE_INIT)
  258. return -1;
  259. blobmsg_add_string(&uh->headers, name, value);
  260. return 0;
  261. }
  262. #define ustream_printf(us, ...) do { \
  263. fprintf(stderr, "send: " __VA_ARGS__); \
  264. ustream_printf(us, __VA_ARGS__); \
  265. } while (0)
  266. static void
  267. uclient_http_send_headers(struct uclient_http *uh)
  268. {
  269. struct uclient_url *url = uh->uc.url;
  270. struct blob_attr *cur;
  271. int rem;
  272. if (uh->state >= HTTP_STATE_HEADERS_SENT)
  273. return;
  274. ustream_printf(uh->us,
  275. "%s /%s HTTP/1.0\r\n"
  276. "Host: %s\r\n",
  277. request_types[uh->req_type],
  278. url->location, url->host);
  279. blobmsg_for_each_attr(cur, uh->headers.head, rem)
  280. ustream_printf(uh->us, "%s: %s\n", blobmsg_name(cur), (char *) blobmsg_data(cur));
  281. if (url->auth) {
  282. int auth_len = strlen(url->auth);
  283. char *auth_buf;
  284. if (auth_len > 512)
  285. return;
  286. auth_buf = alloca(base64_len(auth_len) + 1);
  287. base64_encode(url->auth, auth_len, auth_buf);
  288. ustream_printf(uh->us, "Authorization: Basic %s\r\n", auth_buf);
  289. }
  290. if (uh->send_len > 0)
  291. ustream_printf(uh->us, "Content-Length: %d", uh->send_len);
  292. ustream_printf(uh->us, "\r\n");
  293. }
  294. static int
  295. uclient_http_set_write_len(struct uclient *cl, unsigned int len)
  296. {
  297. struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
  298. if (uh->state >= HTTP_STATE_HEADERS_SENT)
  299. return -1;
  300. if (uh->req_type == REQ_GET || uh->req_type == REQ_HEAD) {
  301. fprintf(stderr, "Sending data is not supported for %s requests\n",
  302. request_types[uh->req_type]);
  303. return -1;
  304. }
  305. uh->send_len = len;
  306. return 0;
  307. }
  308. static int
  309. uclient_http_send_data(struct uclient *cl, char *buf, unsigned int len)
  310. {
  311. struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
  312. if (uh->state >= HTTP_STATE_REQUEST_DONE)
  313. return -1;
  314. uclient_http_send_headers(uh);
  315. if (len > uh->send_len) {
  316. fprintf(stderr, "%s: ignoring %d extra data bytes\n", __func__, uh->send_len - len);
  317. len = uh->send_len;
  318. }
  319. ustream_write(uh->us, buf, len, false);
  320. return len;
  321. }
  322. static int
  323. uclient_http_request_done(struct uclient *cl)
  324. {
  325. struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
  326. if (uh->state >= HTTP_STATE_REQUEST_DONE)
  327. return -1;
  328. if (uh->send_len > 0)
  329. fprintf(stderr, "%s: missing %d POST data bytes\n", __func__, uh->send_len);
  330. uclient_http_send_headers(uh);
  331. uh->state = HTTP_STATE_REQUEST_DONE;
  332. return 0;
  333. }
  334. static int
  335. uclient_http_read(struct uclient *cl, char *buf, unsigned int len)
  336. {
  337. struct uclient_http *uh = container_of(cl, struct uclient_http, uc);
  338. int data_len;
  339. char *data;
  340. if (uh->state < HTTP_STATE_RECV_DATA)
  341. return 0;
  342. data = ustream_get_read_buf(uh->us, &data_len);
  343. if (!data || !data_len)
  344. return 0;
  345. if (len > data_len)
  346. len = data_len;
  347. memcpy(buf, data, len);
  348. ustream_consume(uh->us, len);
  349. uclient_notify_eof(uh);
  350. return len;
  351. }
  352. const struct uclient_backend uclient_backend_http __hidden = {
  353. .prefix = uclient_http_prefix,
  354. .alloc = uclient_http_alloc,
  355. .free = uclient_http_free,
  356. .connect = uclient_http_connect,
  357. .read = uclient_http_read,
  358. .write = uclient_http_send_data,
  359. .request = uclient_http_request_done,
  360. .set_write_len = uclient_http_set_write_len,
  361. };