A clone of btpd with my configuration changes.
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

457 lines
11 KiB

  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <netinet/in.h>
  4. #include <arpa/inet.h>
  5. #include <sys/time.h>
  6. #include <assert.h>
  7. #include <ctype.h>
  8. #include <errno.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <unistd.h>
  13. #include <event.h>
  14. #include <evdns.h>
  15. #include "subr.h"
  16. #include "http_client.h"
  17. struct http_url *
  18. http_url_parse(const char *url)
  19. {
  20. size_t ulen = strlen(url);
  21. if (strncmp(url, "http://", 7) != 0)
  22. return NULL;
  23. const char *cur, *at, *uri = NULL, *uri_e = NULL;
  24. const char *host = NULL, *host_e = NULL;
  25. const char *port = NULL, *port_e = NULL;
  26. at = strchr(url + 7, '@');
  27. uri = strchr(url + 7, '/');
  28. cur = strchr(url + 7, '?');
  29. if (cur != NULL && (uri == NULL || cur < uri))
  30. uri = cur;
  31. if (uri == NULL)
  32. uri = url + ulen;
  33. if (at != NULL && at < uri)
  34. host = at + 1;
  35. else
  36. host = url + 7;
  37. cur = host;
  38. while (cur < uri && *cur != ':')
  39. cur++;
  40. host_e = cur;
  41. if (host_e == host)
  42. return NULL;
  43. if (*cur == ':') {
  44. cur++;
  45. port = cur;
  46. while (cur < uri && *cur >= '0' && *cur <= '9')
  47. cur++;
  48. if (cur == port || cur != uri)
  49. return NULL;
  50. port_e = cur;
  51. }
  52. while (*cur != '\0')
  53. cur++;
  54. uri_e = cur;
  55. struct http_url *res =
  56. malloc(sizeof(*res) + host_e - host + 1 + uri_e - uri + 2);
  57. if (res == NULL)
  58. return NULL;
  59. if (port != NULL)
  60. sscanf(port, "%hu", &res->port);
  61. else
  62. res->port = 80;
  63. res->host = (char *)(res + 1);
  64. res->uri = res->host + (host_e - host + 1);
  65. bcopy(host, res->host, host_e - host);
  66. res->host[host_e - host] = '\0';
  67. if (*uri != '/') {
  68. res->uri[0] = '/';
  69. bcopy(uri, res->uri + 1, uri_e - uri);
  70. res->uri[uri_e - uri + 1] = '\0';
  71. } else {
  72. bcopy(uri, res->uri, uri_e - uri);
  73. res->uri[uri_e - uri] = '\0';
  74. }
  75. return res;
  76. }
  77. void
  78. http_url_free(struct http_url *url)
  79. {
  80. free(url);
  81. }
  82. struct http_req {
  83. enum {
  84. HTTP_RESOLVE, HTTP_CONNECT, HTTP_WRITE, HTTP_RECEIVE, HTTP_PARSE
  85. } state;
  86. struct http_url *url;
  87. int sd;
  88. struct event ev;
  89. http_cb cb;
  90. void *arg;
  91. int cancel;
  92. int pstate, chunked;
  93. long length;
  94. struct evbuffer *buf;
  95. };
  96. static void
  97. http_free(struct http_req *req)
  98. {
  99. if (req->url != NULL)
  100. http_url_free(req->url);
  101. if (req->buf != NULL)
  102. evbuffer_free(req->buf);
  103. if (req->sd > 0) {
  104. event_del(&req->ev);
  105. close(req->sd);
  106. }
  107. free(req);
  108. }
  109. static void
  110. http_error(struct http_req *req)
  111. {
  112. struct http_response res;
  113. res.type = HTTP_T_ERR;
  114. res.v.error = 1;
  115. req->cb(req, &res, req->arg);
  116. http_free(req);
  117. }
  118. #define PS_HEAD 0
  119. #define PS_CHUNK_SIZE 1
  120. #define PS_CHUNK_DATA 2
  121. #define PS_CHUNK_CRLF 3
  122. #define PS_ID_DATA 4
  123. static int
  124. headers_parse(struct http_req *req, char *buf, char *end)
  125. {
  126. int code;
  127. char *cur, *crlf;
  128. char name[128], value[872];
  129. struct http_response res;
  130. req->chunked = 0;
  131. req->length = -1;
  132. if (sscanf(buf, "HTTP/1.1 %d", &code) == 0)
  133. return 0;
  134. res.type = HTTP_T_CODE;
  135. res.v.code = code;
  136. req->cb(req, &res, req->arg);
  137. if (req->cancel)
  138. return 1;
  139. cur = strstr(buf, "\r\n") + 2;
  140. crlf = strstr(cur, "\r\n");
  141. while (cur < end) {
  142. int i;
  143. char *colon = strchr(cur, ':');
  144. if (colon == NULL || colon > crlf)
  145. return 0;
  146. snprintf(name, sizeof(name), "%.*s", (int)(colon - cur), cur);
  147. cur = colon + 1;
  148. i = 0;
  149. val_loop:
  150. while (isblank(*cur))
  151. cur++;
  152. while (cur < crlf) {
  153. if (i < sizeof(value) - 1) {
  154. value[i] = *cur;
  155. i++;
  156. }
  157. cur++;
  158. }
  159. cur += 2;
  160. crlf = strstr(cur, "\r\n");
  161. if (isblank(*cur)) {
  162. if (i < sizeof(value) - 1) {
  163. value[i] = ' ';
  164. i++;
  165. }
  166. cur++;
  167. goto val_loop;
  168. }
  169. value[i] = '\0';
  170. for (i--; i >= 0 && isblank(value[i]); i--)
  171. value[i] = '\0';
  172. res.type = HTTP_T_HEADER;
  173. res.v.header.n = name;
  174. res.v.header.v = value;
  175. req->cb(req, &res, req->arg);
  176. if (req->cancel)
  177. return 1;
  178. if ((!req->chunked
  179. && strcasecmp("Transfer-Encoding", name) == 0
  180. && strcasecmp("chunked", value) == 0))
  181. req->chunked = 1;
  182. if ((!req->chunked && req->length == -1
  183. && strcasecmp("Content-Length", name) == 0)) {
  184. errno = 0;
  185. req->length = strtol(value, NULL, 10);
  186. if (errno)
  187. req->length = -1;
  188. }
  189. }
  190. if (req->chunked)
  191. req->pstate = PS_CHUNK_SIZE;
  192. else
  193. req->pstate = PS_ID_DATA;
  194. return 1;
  195. }
  196. static int
  197. http_parse(struct http_req *req, int len)
  198. {
  199. char *end, *numend;
  200. size_t dlen;
  201. struct http_response res;
  202. again:
  203. switch (req->pstate) {
  204. case PS_HEAD:
  205. if (len == 0)
  206. goto error;
  207. if ((end = evbuffer_find(req->buf, "\r\n\r\n", 4)) == NULL) {
  208. if (req->buf->off < (1 << 15))
  209. return 1;
  210. else
  211. goto error;
  212. }
  213. if (evbuffer_add(req->buf, "", 1) != 0)
  214. goto error;
  215. req->buf->off--;
  216. if (!headers_parse(req, req->buf->buffer, end))
  217. goto error;
  218. if (req->cancel)
  219. goto cancel;
  220. evbuffer_drain(req->buf, end - (char *)req->buf->buffer + 4);
  221. goto again;
  222. case PS_CHUNK_SIZE:
  223. assert(req->chunked);
  224. if (len == 0)
  225. goto error;
  226. if ((end = evbuffer_find(req->buf, "\r\n", 2)) == NULL) {
  227. if (req->buf->off < 20)
  228. return 1;
  229. else
  230. goto error;
  231. }
  232. errno = 0;
  233. req->length = strtol(req->buf->buffer, &numend, 16);
  234. if (req->length < 0 || numend == (char *)req->buf->buffer || errno)
  235. goto error;
  236. if (req->length == 0)
  237. goto done;
  238. evbuffer_drain(req->buf, end - (char *)req->buf->buffer + 2);
  239. req->pstate = PS_CHUNK_DATA;
  240. goto again;
  241. case PS_CHUNK_DATA:
  242. if (len == 0)
  243. goto error;
  244. assert(req->length > 0);
  245. dlen = min(req->buf->off, req->length);
  246. if (dlen > 0) {
  247. res.type = HTTP_T_DATA;
  248. res.v.data.l = dlen;
  249. res.v.data.p = req->buf->buffer;
  250. req->cb(req, &res, req->arg);
  251. if (req->cancel)
  252. goto cancel;
  253. evbuffer_drain(req->buf, dlen);
  254. req->length -= dlen;
  255. if (req->length == 0) {
  256. req->pstate = PS_CHUNK_CRLF;
  257. goto again;
  258. }
  259. }
  260. return 1;
  261. case PS_CHUNK_CRLF:
  262. if (len == 0)
  263. goto error;
  264. assert(req->length == 0);
  265. if (req->buf->off < 2)
  266. return 1;
  267. if (bcmp(req->buf->buffer, "\r\n", 2) != 0)
  268. goto error;
  269. evbuffer_drain(req->buf, 2);
  270. req->pstate = PS_CHUNK_SIZE;
  271. goto again;
  272. case PS_ID_DATA:
  273. if (len == 0 && req->length < 0)
  274. goto done;
  275. else if (len == 0)
  276. goto error;
  277. if (req->length < 0)
  278. dlen = req->buf->off;
  279. else
  280. dlen = min(req->buf->off, req->length);
  281. if (dlen > 0) {
  282. res.type = HTTP_T_DATA;
  283. res.v.data.p = req->buf->buffer;
  284. res.v.data.l = dlen;
  285. req->cb(req, &res, req->arg);
  286. if (req->cancel)
  287. goto cancel;
  288. evbuffer_drain(req->buf, dlen);
  289. if (req->length > 0) {
  290. req->length -= dlen;
  291. if (req->length == 0)
  292. goto done;
  293. }
  294. }
  295. return 1;
  296. default:
  297. abort();
  298. }
  299. error:
  300. http_error(req);
  301. return 0;
  302. done:
  303. res.type = HTTP_T_DONE;
  304. req->cb(req, &res, req->arg);
  305. cancel:
  306. http_free(req);
  307. return 0;
  308. }
  309. static void
  310. http_read_cb(int sd, short type, void *arg)
  311. {
  312. struct http_req *req = arg;
  313. if (type == EV_TIMEOUT) {
  314. http_error(req);
  315. return;
  316. }
  317. int nr = evbuffer_read(req->buf, sd, 1 << 14);
  318. if (nr < 0) {
  319. if (nr == EAGAIN)
  320. goto more;
  321. else {
  322. printf("read err\n");
  323. http_error(req);
  324. return;
  325. }
  326. }
  327. req->state = HTTP_PARSE;
  328. if (!http_parse(req, nr))
  329. return;
  330. req->state = HTTP_RECEIVE;
  331. more:
  332. if (event_add(&req->ev, NULL) != 0)
  333. http_error(req);
  334. }
  335. static void
  336. http_write_cb(int sd, short type, void *arg)
  337. {
  338. struct http_req *req = arg;
  339. if (type == EV_TIMEOUT) {
  340. http_error(req);
  341. return;
  342. }
  343. int nw = evbuffer_write(req->buf, sd);
  344. if (nw == -1) {
  345. if (errno == EAGAIN)
  346. goto out;
  347. else
  348. goto error;
  349. }
  350. out:
  351. if (req->buf->off != 0) {
  352. if (event_add(&req->ev, NULL) != 0)
  353. goto error;
  354. } else {
  355. req->state = HTTP_RECEIVE;
  356. event_set(&req->ev, req->sd, EV_READ, http_read_cb, req);
  357. if (event_add(&req->ev, NULL) != 0)
  358. goto error;
  359. }
  360. return;
  361. error:
  362. printf("http write err\n");
  363. http_error(req);
  364. }
  365. static void
  366. http_dnscb(int result, char type, int count, int ttl, void *addrs, void *arg)
  367. {
  368. struct http_req *req = arg;
  369. if (req->cancel)
  370. http_free(req);
  371. else if (result == 0 && type == 1 && count > 0) {
  372. int addri = rand_between(0, count - 1);
  373. struct sockaddr_in addr;
  374. addr.sin_family = AF_INET;
  375. addr.sin_port = htons(req->url->port);
  376. bcopy(addrs + addri * 4, &addr.sin_addr.s_addr, 4);
  377. req->state = HTTP_CONNECT;
  378. if ((req->sd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
  379. goto error;
  380. if (set_nonblocking(req->sd) != 0)
  381. goto error;
  382. if ((connect(req->sd, (struct sockaddr *)&addr, sizeof(addr)) != 0
  383. && errno != EINPROGRESS))
  384. goto error;
  385. event_set(&req->ev, req->sd, EV_WRITE, http_write_cb, req);
  386. if (event_add(&req->ev, NULL) != 0)
  387. goto error;
  388. } else
  389. goto error;
  390. return;
  391. error:
  392. http_error(req);
  393. }
  394. int
  395. http_get(struct http_req **out, const char *url, const char *hdrs, http_cb cb,
  396. void *arg)
  397. {
  398. struct http_req *req = calloc(1, sizeof(*req));
  399. if (req == NULL)
  400. return 0;
  401. req->sd = -1;
  402. req->cb = cb;
  403. req->arg = arg;
  404. req->url = http_url_parse(url);
  405. if (req->url == NULL)
  406. goto error;
  407. if ((req->buf = evbuffer_new()) == NULL)
  408. goto error;
  409. if (evbuffer_add_printf(req->buf, "GET %s HTTP/1.1\r\n"
  410. "Accept-Encoding:\r\n"
  411. "Connection: close\r\n"
  412. "Host: %s\r\n"
  413. "%s"
  414. "\r\n", req->url->uri, req->url->host, hdrs) == -1)
  415. goto error;
  416. if (evdns_resolve_ipv4(req->url->host, 0, http_dnscb, req) != 0)
  417. goto error;
  418. if (out != NULL)
  419. *out = req;
  420. return 1;
  421. error:
  422. http_free(req);
  423. return 0;
  424. }
  425. void
  426. http_cancel(struct http_req *req)
  427. {
  428. if (req->state == HTTP_RESOLVE || req->state == HTTP_PARSE)
  429. req->cancel = 1;
  430. else
  431. http_free(req);
  432. }