1e3a286deSclaudio #include <sys/queue.h> 2e3a286deSclaudio #include <sys/socket.h> 3e3a286deSclaudio #include <err.h> 4e3a286deSclaudio #include <errno.h> 5e3a286deSclaudio #include <fcntl.h> 6e3a286deSclaudio #include <limits.h> 7e3a286deSclaudio #include <stdarg.h> 8e3a286deSclaudio #include <stdlib.h> 9e3a286deSclaudio #include <string.h> 10e3a286deSclaudio #include <unistd.h> 11e3a286deSclaudio 12e3a286deSclaudio #include <imsg.h> 13e3a286deSclaudio 14e3a286deSclaudio #include "extern.h" 15e3a286deSclaudio 1639e1fbecSclaudio static struct msgbuf *httpq; 17e3a286deSclaudio 18e3a286deSclaudio void 19e3a286deSclaudio logx(const char *fmt, ...) 20e3a286deSclaudio { 21e3a286deSclaudio va_list ap; 22e3a286deSclaudio 23e3a286deSclaudio va_start(ap, fmt); 24e3a286deSclaudio vwarnx(fmt, ap); 25e3a286deSclaudio va_end(ap); 26e3a286deSclaudio } 27e3a286deSclaudio 28bfaf3eaaSclaudio time_t 29bfaf3eaaSclaudio getmonotime(void) 30bfaf3eaaSclaudio { 31bfaf3eaaSclaudio struct timespec ts; 32bfaf3eaaSclaudio 33bfaf3eaaSclaudio if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) 34bfaf3eaaSclaudio err(1, "clock_gettime"); 35bfaf3eaaSclaudio return (ts.tv_sec); 36bfaf3eaaSclaudio } 37bfaf3eaaSclaudio 387639492aSjob int 397639492aSjob valid_origin(const char *uri, const char *proto) 407639492aSjob { 417639492aSjob const char *to; 427639492aSjob 437639492aSjob /* extract end of host from proto URI */ 447639492aSjob to = strstr(proto, "://"); 457639492aSjob if (to == NULL) 467639492aSjob return 0; 477639492aSjob to += strlen("://"); 487639492aSjob if ((to = strchr(to, '/')) == NULL) 497639492aSjob return 0; 507639492aSjob 517639492aSjob /* compare hosts including the / for the start of the path section */ 527639492aSjob if (strncasecmp(uri, proto, to - proto + 1) != 0) 537639492aSjob return 0; 547639492aSjob 557639492aSjob return 1; 567639492aSjob } 577639492aSjob 58e3a286deSclaudio static void 59f4525c43Sclaudio http_request(unsigned int id, const char *uri, const char *last_mod, int fd) 60e3a286deSclaudio { 61e3a286deSclaudio struct ibuf *b; 62e3a286deSclaudio 636012c245Sclaudio b = io_new_buffer(); 64e3a286deSclaudio io_simple_buffer(b, &id, sizeof(id)); 65e3a286deSclaudio io_str_buffer(b, uri); 66e3a286deSclaudio io_str_buffer(b, last_mod); 67e3a286deSclaudio /* pass file as fd */ 68e3a286deSclaudio b->fd = fd; 6939e1fbecSclaudio io_close_buffer(httpq, b); 70e3a286deSclaudio } 71e3a286deSclaudio 72e3a286deSclaudio static const char * 73e3a286deSclaudio http_result(enum http_result res) 74e3a286deSclaudio { 75e3a286deSclaudio switch (res) { 76e3a286deSclaudio case HTTP_OK: 77e3a286deSclaudio return "OK"; 78e3a286deSclaudio case HTTP_NOT_MOD: 79e3a286deSclaudio return "not modified"; 80e3a286deSclaudio case HTTP_FAILED: 81e3a286deSclaudio return "failed"; 82e3a286deSclaudio default: 83e3a286deSclaudio errx(1, "unknown http result: %d", res); 84e3a286deSclaudio } 85e3a286deSclaudio } 86e3a286deSclaudio 87b6911e0dSanton static int 88e3a286deSclaudio http_response(int fd) 89e3a286deSclaudio { 90*268bb8d7Sclaudio struct ibuf *b; 91f4525c43Sclaudio unsigned int id; 92e3a286deSclaudio enum http_result res; 93e3a286deSclaudio char *lastmod; 94e3a286deSclaudio 95*268bb8d7Sclaudio while (1) { 96*268bb8d7Sclaudio switch (msgbuf_read(fd, httpq)) { 97*268bb8d7Sclaudio case -1: 98*268bb8d7Sclaudio err(1, "msgbuf_read"); 99*268bb8d7Sclaudio case 0: 100*268bb8d7Sclaudio errx(1, "msgbuf_read: connection closed"); 101*268bb8d7Sclaudio } 102*268bb8d7Sclaudio if ((b = io_buf_get(httpq)) != NULL) 103*268bb8d7Sclaudio break; 104*268bb8d7Sclaudio } 10573cfe019Sclaudio 10673cfe019Sclaudio io_read_buf(b, &id, sizeof(id)); 10773cfe019Sclaudio io_read_buf(b, &res, sizeof(res)); 10873cfe019Sclaudio io_read_str(b, &lastmod); 10973cfe019Sclaudio ibuf_free(b); 110e3a286deSclaudio 111e3a286deSclaudio printf("transfer %s", http_result(res)); 112e3a286deSclaudio if (lastmod) 113e3a286deSclaudio printf(", last-modified: %s" , lastmod); 114e3a286deSclaudio printf("\n"); 115b6911e0dSanton return res == HTTP_FAILED; 116e3a286deSclaudio } 117e3a286deSclaudio 118e3a286deSclaudio int 119e3a286deSclaudio main(int argc, char **argv) 120e3a286deSclaudio { 121e3a286deSclaudio pid_t httppid; 12239e1fbecSclaudio int error, fd[2], outfd, httpfd; 123e3a286deSclaudio int fl = SOCK_STREAM | SOCK_CLOEXEC; 124e3a286deSclaudio char *uri, *file, *mod; 125f4525c43Sclaudio unsigned int req = 0; 126e3a286deSclaudio 127e3a286deSclaudio if (argc != 3 && argc != 4) { 128e3a286deSclaudio fprintf(stderr, "usage: test-http uri file [last-modified]\n"); 129e3a286deSclaudio return 1; 130e3a286deSclaudio } 131e3a286deSclaudio uri = argv[1]; 132e3a286deSclaudio file = argv[2]; 133e3a286deSclaudio mod = argv[3]; 134e3a286deSclaudio 135e3a286deSclaudio if (socketpair(AF_UNIX, fl, 0, fd) == -1) 136e3a286deSclaudio err(1, "socketpair"); 137e3a286deSclaudio 138e3a286deSclaudio if ((httppid = fork()) == -1) 139e3a286deSclaudio err(1, "fork"); 140e3a286deSclaudio 141e3a286deSclaudio if (httppid == 0) { 142e3a286deSclaudio close(fd[1]); 143e3a286deSclaudio 144e3a286deSclaudio if (pledge("stdio rpath inet dns recvfd", NULL) == -1) 145e3a286deSclaudio err(1, "pledge"); 146e3a286deSclaudio 147e3a286deSclaudio proc_http(NULL, fd[0]); 148e3a286deSclaudio errx(1, "http process returned"); 149e3a286deSclaudio } 150e3a286deSclaudio 151e3a286deSclaudio close(fd[0]); 15239e1fbecSclaudio httpfd = fd[1]; 153*268bb8d7Sclaudio if ((httpq = msgbuf_new_reader(sizeof(size_t), io_parse_hdr, NULL)) == 154*268bb8d7Sclaudio NULL) 15539e1fbecSclaudio err(1, NULL); 156e3a286deSclaudio 157e3a286deSclaudio if ((outfd = open(file, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1) 158e3a286deSclaudio err(1, "open %s", file); 159e3a286deSclaudio 160e3a286deSclaudio http_request(req++, uri, mod, outfd); 16139e1fbecSclaudio if (msgbuf_write(httpfd, httpq) == -1) 162e3a286deSclaudio err(1, "write"); 16339e1fbecSclaudio error = http_response(httpfd); 164b6911e0dSanton return error; 165e3a286deSclaudio } 166