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.

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