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.

457 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. 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. }