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.

489 lignes
12 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 char *
  123. strnl(char *str, int *nlsize)
  124. {
  125. char *nl = strchr(str, '\n');
  126. if (nl != NULL && nl > str && *(nl - 1) == '\r') {
  127. *nlsize = 2;
  128. return nl - 1;
  129. } else {
  130. *nlsize = 1;
  131. return nl;
  132. }
  133. }
  134. static int
  135. headers_parse(struct http_req *req, char *buf, char *end)
  136. {
  137. int code, majv, minv, nlsize;
  138. char *cur, *nl;
  139. char name[128], value[872];
  140. struct http_response res;
  141. req->chunked = 0;
  142. req->length = -1;
  143. if (sscanf(buf, "HTTP/%d.%d %d", &majv, &minv, &code) != 3)
  144. return 0;
  145. res.type = HTTP_T_CODE;
  146. res.v.code = code;
  147. req->cb(req, &res, req->arg);
  148. if (req->cancel)
  149. return 1;
  150. cur = strchr(buf, '\n') + 1;
  151. nl = strnl(cur, &nlsize);
  152. while (cur < end) {
  153. int i;
  154. char *colon = strchr(cur, ':');
  155. if (colon == NULL || colon > nl)
  156. return 0;
  157. snprintf(name, sizeof(name), "%.*s", (int)(colon - cur), cur);
  158. cur = colon + 1;
  159. i = 0;
  160. val_loop:
  161. while (isblank(*cur))
  162. cur++;
  163. while (cur < nl) {
  164. if (i < sizeof(value) - 1) {
  165. value[i] = *cur;
  166. i++;
  167. }
  168. cur++;
  169. }
  170. cur += nlsize;
  171. nl = strnl(cur, &nlsize);
  172. if (isblank(*cur)) {
  173. if (i < sizeof(value) - 1) {
  174. value[i] = ' ';
  175. i++;
  176. }
  177. cur++;
  178. goto val_loop;
  179. }
  180. value[i] = '\0';
  181. for (i--; i >= 0 && isblank(value[i]); i--)
  182. value[i] = '\0';
  183. res.type = HTTP_T_HEADER;
  184. res.v.header.n = name;
  185. res.v.header.v = value;
  186. req->cb(req, &res, req->arg);
  187. if (req->cancel)
  188. return 1;
  189. if ((!req->chunked
  190. && strcasecmp("Transfer-Encoding", name) == 0
  191. && strcasecmp("chunked", value) == 0))
  192. req->chunked = 1;
  193. if ((!req->chunked && req->length == -1
  194. && strcasecmp("Content-Length", name) == 0)) {
  195. errno = 0;
  196. req->length = strtol(value, NULL, 10);
  197. if (errno)
  198. req->length = -1;
  199. }
  200. }
  201. if (req->chunked)
  202. req->pstate = PS_CHUNK_SIZE;
  203. else
  204. req->pstate = PS_ID_DATA;
  205. return 1;
  206. }
  207. static int
  208. http_parse(struct http_req *req, int len)
  209. {
  210. char *end, *numend;
  211. size_t dlen;
  212. struct http_response res;
  213. again:
  214. switch (req->pstate) {
  215. case PS_HEAD:
  216. if (len == 0)
  217. goto error;
  218. if ((end = evbuffer_find(req->buf, "\r\n\r\n", 4)) != NULL)
  219. dlen = 4;
  220. else if ((end = evbuffer_find(req->buf, "\n\n", 2)) != NULL)
  221. dlen = 2;
  222. else {
  223. if (req->buf->off < (1 << 15))
  224. return 1;
  225. else
  226. goto error;
  227. }
  228. if (evbuffer_add(req->buf, "", 1) != 0)
  229. goto error;
  230. req->buf->off--;
  231. if (!headers_parse(req, req->buf->buffer, end))
  232. goto error;
  233. if (req->cancel)
  234. goto cancel;
  235. evbuffer_drain(req->buf, end - (char *)req->buf->buffer + dlen);
  236. goto again;
  237. case PS_CHUNK_SIZE:
  238. assert(req->chunked);
  239. if (len == 0)
  240. goto error;
  241. if ((end = evbuffer_find(req->buf, "\n", 1)) == NULL) {
  242. if (req->buf->off < 20)
  243. return 1;
  244. else
  245. goto error;
  246. }
  247. errno = 0;
  248. req->length = strtol(req->buf->buffer, &numend, 16);
  249. if (req->length < 0 || numend == (char *)req->buf->buffer || errno)
  250. goto error;
  251. if (req->length == 0)
  252. goto done;
  253. evbuffer_drain(req->buf, end - (char *)req->buf->buffer + 1);
  254. req->pstate = PS_CHUNK_DATA;
  255. goto again;
  256. case PS_CHUNK_DATA:
  257. if (len == 0)
  258. goto error;
  259. assert(req->length > 0);
  260. dlen = min(req->buf->off, req->length);
  261. if (dlen > 0) {
  262. res.type = HTTP_T_DATA;
  263. res.v.data.l = dlen;
  264. res.v.data.p = req->buf->buffer;
  265. req->cb(req, &res, req->arg);
  266. if (req->cancel)
  267. goto cancel;
  268. evbuffer_drain(req->buf, dlen);
  269. req->length -= dlen;
  270. if (req->length == 0) {
  271. req->pstate = PS_CHUNK_CRLF;
  272. goto again;
  273. }
  274. }
  275. return 1;
  276. case PS_CHUNK_CRLF:
  277. if (len == 0)
  278. goto error;
  279. assert(req->length == 0);
  280. if (req->buf->off < 2)
  281. return 1;
  282. if (req->buf->buffer[0] == '\r' && req->buf->buffer[1] == '\n')
  283. dlen = 2;
  284. else if (req->buf->buffer[0] == '\n')
  285. dlen = 1;
  286. else
  287. goto error;
  288. evbuffer_drain(req->buf, dlen);
  289. req->pstate = PS_CHUNK_SIZE;
  290. goto again;
  291. case PS_ID_DATA:
  292. if (len == 0 && req->length < 0)
  293. goto done;
  294. else if (len == 0)
  295. goto error;
  296. if (req->length < 0)
  297. dlen = req->buf->off;
  298. else
  299. dlen = min(req->buf->off, req->length);
  300. if (dlen > 0) {
  301. res.type = HTTP_T_DATA;
  302. res.v.data.p = req->buf->buffer;
  303. res.v.data.l = dlen;
  304. req->cb(req, &res, req->arg);
  305. if (req->cancel)
  306. goto cancel;
  307. evbuffer_drain(req->buf, dlen);
  308. if (req->length > 0) {
  309. req->length -= dlen;
  310. if (req->length == 0)
  311. goto done;
  312. }
  313. }
  314. return 1;
  315. default:
  316. abort();
  317. }
  318. error:
  319. http_error(req);
  320. return 0;
  321. done:
  322. res.type = HTTP_T_DONE;
  323. req->cb(req, &res, req->arg);
  324. cancel:
  325. http_free(req);
  326. return 0;
  327. }
  328. static void
  329. http_read_cb(int sd, short type, void *arg)
  330. {
  331. struct http_req *req = arg;
  332. if (type == EV_TIMEOUT) {
  333. http_error(req);
  334. return;
  335. }
  336. int nr = evbuffer_read(req->buf, sd, 1 << 14);
  337. if (nr < 0) {
  338. if (nr == EAGAIN)
  339. goto more;
  340. else {
  341. http_error(req);
  342. return;
  343. }
  344. }
  345. req->state = HTTP_PARSE;
  346. if (!http_parse(req, nr))
  347. return;
  348. req->state = HTTP_RECEIVE;
  349. more:
  350. if (event_add(&req->ev, TIMEOUT) != 0)
  351. http_error(req);
  352. }
  353. static void
  354. http_write_cb(int sd, short type, void *arg)
  355. {
  356. struct http_req *req = arg;
  357. if (type == EV_TIMEOUT) {
  358. http_error(req);
  359. return;
  360. }
  361. int nw = evbuffer_write(req->buf, sd);
  362. if (nw == -1) {
  363. if (errno == EAGAIN)
  364. goto out;
  365. else
  366. goto error;
  367. }
  368. out:
  369. if (req->buf->off != 0) {
  370. if (event_add(&req->ev, TIMEOUT) != 0)
  371. goto error;
  372. } else {
  373. req->state = HTTP_RECEIVE;
  374. event_set(&req->ev, req->sd, EV_READ, http_read_cb, req);
  375. if (event_add(&req->ev, TIMEOUT) != 0)
  376. goto error;
  377. }
  378. return;
  379. error:
  380. http_error(req);
  381. }
  382. static int
  383. http_connect(struct http_req *req, struct in_addr inaddr)
  384. {
  385. struct sockaddr_in addr;
  386. addr.sin_family = AF_INET;
  387. addr.sin_port = htons(req->url->port);
  388. addr.sin_addr = inaddr;
  389. req->state = HTTP_CONNECT;
  390. if ((req->sd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
  391. goto error;
  392. if (set_nonblocking(req->sd) != 0)
  393. goto error;
  394. if ((connect(req->sd, (struct sockaddr *)&addr, sizeof(addr)) != 0
  395. && errno != EINPROGRESS))
  396. goto error;
  397. event_set(&req->ev, req->sd, EV_WRITE, http_write_cb, req);
  398. if (event_add(&req->ev, TIMEOUT) != 0)
  399. goto error;
  400. return 1;
  401. error:
  402. return 0;
  403. }
  404. static void
  405. http_dnscb(int result, char type, int count, int ttl, void *addrs, void *arg)
  406. {
  407. struct http_req *req = arg;
  408. if (req->cancel)
  409. http_free(req);
  410. else if (result == DNS_ERR_NONE && type == DNS_IPv4_A && count > 0) {
  411. int addri = rand_between(0, count - 1);
  412. struct in_addr inaddr;
  413. bcopy(addrs + addri * sizeof(struct in_addr), &inaddr,
  414. sizeof(struct in_addr));
  415. if (!http_connect(req, inaddr))
  416. http_error(req);
  417. } else
  418. http_error(req);
  419. }
  420. int
  421. http_get(struct http_req **out, const char *url, const char *hdrs,
  422. http_cb_t cb, void *arg)
  423. {
  424. struct in_addr addr;
  425. struct http_req *req = calloc(1, sizeof(*req));
  426. if (req == NULL)
  427. return 0;
  428. req->sd = -1;
  429. req->cb = cb;
  430. req->arg = arg;
  431. req->url = http_url_parse(url);
  432. if (req->url == NULL)
  433. goto error;
  434. if ((req->buf = evbuffer_new()) == NULL)
  435. goto error;
  436. if (evbuffer_add_printf(req->buf, "GET %s HTTP/1.1\r\n"
  437. "Host: %s:%hu\r\n"
  438. "Accept-Encoding:\r\n"
  439. "Connection: close\r\n"
  440. "%s"
  441. "\r\n", req->url->uri, req->url->host, req->url->port, hdrs) == -1)
  442. goto error;
  443. if (inet_aton(req->url->host, &addr) == 1) {
  444. if (!http_connect(req, addr))
  445. goto error;
  446. } else if (evdns_resolve_ipv4(req->url->host, 0, http_dnscb, req) != 0)
  447. goto error;
  448. if (out != NULL)
  449. *out = req;
  450. return 1;
  451. error:
  452. http_free(req);
  453. return 0;
  454. }
  455. void
  456. http_cancel(struct http_req *req)
  457. {
  458. if (req->state == HTTP_RESOLVE || req->state == HTTP_PARSE)
  459. req->cancel = 1;
  460. else
  461. http_free(req);
  462. }