A clone of btpd with my configuration changes.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

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