A clone of btpd with my configuration changes.
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

489 lines
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. }