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