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 static void
39 http_request(size_t id, const char *uri, const char *last_mod, int fd)
40 {
41 	struct ibuf     *b;
42 
43 	b = io_new_buffer();
44 	io_simple_buffer(b, &id, sizeof(id));
45 	io_str_buffer(b, uri);
46 	io_str_buffer(b, last_mod);
47 	/* pass file as fd */
48 	b->fd = fd;
49 	io_close_buffer(&httpq, b);
50 }
51 
52 static const char *
53 http_result(enum http_result res)
54 {
55 	switch (res) {
56 	case HTTP_OK:
57 		return "OK";
58 	case HTTP_NOT_MOD:
59 		return "not modified";
60 	case HTTP_FAILED:
61 		return "failed";
62 	default:
63 		errx(1, "unknown http result: %d", res);
64 	}
65 }
66 
67 static int
68 http_response(int fd)
69 {
70 	struct ibuf *b, *httpbuf = NULL;
71 	size_t id;
72 	enum http_result res;
73 	char *lastmod;
74 
75 	while ((b = io_buf_read(fd, &httpbuf)) == NULL)
76 		/* nothing */ ;
77 
78 	io_read_buf(b, &id, sizeof(id));
79 	io_read_buf(b, &res, sizeof(res));
80 	io_read_str(b, &lastmod);
81 	ibuf_free(b);
82 
83 	printf("transfer %s", http_result(res));
84 	if (lastmod)
85 		printf(", last-modified: %s" , lastmod);
86 	printf("\n");
87 	return res == HTTP_FAILED;
88 }
89 
90 int
91 main(int argc, char **argv)
92 {
93 	pid_t httppid;
94 	int error, fd[2], outfd, http;
95 	int fl = SOCK_STREAM | SOCK_CLOEXEC;
96 	char *uri, *file, *mod;
97 	size_t req = 0;
98 
99 	if (argc != 3 && argc != 4) {
100 		fprintf(stderr, "usage: test-http uri file [last-modified]\n");
101 		return 1;
102 	}
103 	uri = argv[1];
104 	file = argv[2];
105 	mod = argv[3];
106 
107 	if (socketpair(AF_UNIX, fl, 0, fd) == -1)
108 		err(1, "socketpair");
109 
110 	if ((httppid = fork()) == -1)
111 		err(1, "fork");
112 
113 	if (httppid == 0) {
114 		close(fd[1]);
115 
116 		if (pledge("stdio rpath inet dns recvfd", NULL) == -1)
117 			err(1, "pledge");
118 
119 		proc_http(NULL, fd[0]);
120 		errx(1, "http process returned");
121 	}
122 
123 	close(fd[0]);
124 	http = fd[1];
125 	msgbuf_init(&httpq);
126 	httpq.fd = http;
127 
128 	if ((outfd = open(file, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1)
129 		err(1, "open %s", file);
130 
131 	http_request(req++, uri, mod, outfd);
132 	switch (msgbuf_write(&httpq)) {
133 	case 0:
134 		errx(1, "write: connection closed");
135 	case -1:
136 		err(1, "write");
137 	}
138 	error = http_response(http);
139 	return error;
140 }
141