Blame


1 ad3b5b58 2024-04-14 me /*
2 4c316997 2024-04-15 me * Copyright (c) 2024 Tobias Heider <me@tobhe.de>
3 ad3b5b58 2024-04-14 me * Copyright (c) 2022 Omar Polo <op@openbsd.org>
4 ad3b5b58 2024-04-14 me *
5 ad3b5b58 2024-04-14 me * Permission to use, copy, modify, and distribute this software for any
6 ad3b5b58 2024-04-14 me * purpose with or without fee is hereby granted, provided that the above
7 ad3b5b58 2024-04-14 me * copyright notice and this permission notice appear in all copies.
8 ad3b5b58 2024-04-14 me *
9 ad3b5b58 2024-04-14 me * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 ad3b5b58 2024-04-14 me * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 ad3b5b58 2024-04-14 me * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 ad3b5b58 2024-04-14 me * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 ad3b5b58 2024-04-14 me * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 ad3b5b58 2024-04-14 me * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 ad3b5b58 2024-04-14 me * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 ad3b5b58 2024-04-14 me */
17 ad3b5b58 2024-04-14 me
18 ad3b5b58 2024-04-14 me #include <sys/types.h>
19 60ac0535 2024-04-28 stsp #include <sys/queue.h>
20 ad3b5b58 2024-04-14 me #include <sys/socket.h>
21 ad3b5b58 2024-04-14 me
22 ad3b5b58 2024-04-14 me #include <err.h>
23 ad3b5b58 2024-04-14 me #include <errno.h>
24 ad3b5b58 2024-04-14 me #include <limits.h>
25 ad3b5b58 2024-04-14 me #include <netdb.h>
26 ad3b5b58 2024-04-14 me #include <poll.h>
27 ad3b5b58 2024-04-14 me #include <stdio.h>
28 ad3b5b58 2024-04-14 me #include <stdlib.h>
29 ad3b5b58 2024-04-14 me #include <string.h>
30 ad3b5b58 2024-04-14 me #include <tls.h>
31 ad3b5b58 2024-04-14 me #include <unistd.h>
32 ad3b5b58 2024-04-14 me
33 21679dc5 2024-04-22 me #include "got_error.h"
34 60ac0535 2024-04-28 stsp #include "got_path.h"
35 ad3b5b58 2024-04-14 me #include "got_version.h"
36 ad3b5b58 2024-04-14 me
37 18c37abb 2024-04-17 stsp #include "got_lib_pkt.h"
38 18c37abb 2024-04-17 stsp
39 4c316997 2024-04-15 me #include "bufio.h"
40 4c316997 2024-04-15 me
41 ad3b5b58 2024-04-14 me #define UPLOAD_PACK_ADV "application/x-git-upload-pack-advertisement"
42 ad3b5b58 2024-04-14 me #define UPLOAD_PACK_REQ "application/x-git-upload-pack-request"
43 ad3b5b58 2024-04-14 me #define UPLOAD_PACK_RES "application/x-git-upload-pack-result"
44 ad3b5b58 2024-04-14 me
45 ad3b5b58 2024-04-14 me #define GOT_USERAGENT "got/" GOT_VERSION_STR
46 ad3b5b58 2024-04-14 me #define MINIMUM(a, b) ((a) < (b) ? (a) : (b))
47 ad3b5b58 2024-04-14 me #define hasprfx(str, p) (strncasecmp(str, p, strlen(p)) == 0)
48 ad3b5b58 2024-04-14 me
49 ad3b5b58 2024-04-14 me FILE *tmp;
50 ad3b5b58 2024-04-14 me
51 ad3b5b58 2024-04-14 me static int verbose;
52 ad3b5b58 2024-04-14 me
53 4c316997 2024-04-15 me static char *
54 4c316997 2024-04-15 me bufio_getdelim_sync(struct bufio *bio, const char *nl, size_t *len)
55 4c316997 2024-04-15 me {
56 4c316997 2024-04-15 me int r;
57 4c316997 2024-04-15 me
58 4c316997 2024-04-15 me do {
59 4c316997 2024-04-15 me r = bufio_read(bio);
60 4c316997 2024-04-15 me if (r == -1 && errno != EAGAIN)
61 4c316997 2024-04-15 me errx(1, "bufio_read: %s", bufio_io_err(bio));
62 4c316997 2024-04-15 me } while (r == -1 && errno == EAGAIN);
63 4c316997 2024-04-15 me return buf_getdelim(&bio->rbuf, nl, len);
64 4c316997 2024-04-15 me }
65 4c316997 2024-04-15 me
66 4c316997 2024-04-15 me static size_t
67 4c316997 2024-04-15 me bufio_drain_sync(struct bufio *bio, void *d, size_t len)
68 4c316997 2024-04-15 me {
69 4c316997 2024-04-15 me int r;
70 4c316997 2024-04-15 me
71 4c316997 2024-04-15 me do {
72 4c316997 2024-04-15 me r = bufio_read(bio);
73 4c316997 2024-04-15 me if (r == -1 && errno != EAGAIN)
74 4c316997 2024-04-15 me errx(1, "bufio_read: %s", bufio_io_err(bio));
75 4c316997 2024-04-15 me } while (r == -1 && errno == EAGAIN);
76 4c316997 2024-04-15 me return bufio_drain(bio, d, len);
77 4c316997 2024-04-15 me }
78 4c316997 2024-04-15 me
79 4c316997 2024-04-15 me static void
80 4c316997 2024-04-15 me bufio_close_sync(struct bufio *bio)
81 4c316997 2024-04-15 me {
82 4c316997 2024-04-15 me int r;
83 4c316997 2024-04-15 me
84 4c316997 2024-04-15 me do {
85 4c316997 2024-04-15 me r = bufio_close(bio);
86 4c316997 2024-04-15 me if (r == -1 && errno == EAGAIN)
87 4c316997 2024-04-15 me errx(1, "bufio_read: %s", bufio_io_err(bio));
88 4c316997 2024-04-15 me } while (r == -1 && errno == EAGAIN);
89 4c316997 2024-04-15 me }
90 4c316997 2024-04-15 me
91 ad3b5b58 2024-04-14 me static long long
92 ad3b5b58 2024-04-14 me hexstrtonum(const char *str, long long min, long long max, const char **errstr)
93 ad3b5b58 2024-04-14 me {
94 ad3b5b58 2024-04-14 me long long lval;
95 ad3b5b58 2024-04-14 me char *cp;
96 ad3b5b58 2024-04-14 me
97 ad3b5b58 2024-04-14 me errno = 0;
98 ad3b5b58 2024-04-14 me lval = strtoll(str, &cp, 16);
99 ad3b5b58 2024-04-14 me if (*str == '\0' || *cp != '\0') {
100 ad3b5b58 2024-04-14 me *errstr = "not a number";
101 ad3b5b58 2024-04-14 me return 0;
102 ad3b5b58 2024-04-14 me }
103 ad3b5b58 2024-04-14 me if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) ||
104 ad3b5b58 2024-04-14 me lval < min || lval > max) {
105 ad3b5b58 2024-04-14 me *errstr = "out of range";
106 ad3b5b58 2024-04-14 me return 0;
107 ad3b5b58 2024-04-14 me }
108 ad3b5b58 2024-04-14 me
109 ad3b5b58 2024-04-14 me *errstr = NULL;
110 ad3b5b58 2024-04-14 me return lval;
111 ad3b5b58 2024-04-14 me }
112 ad3b5b58 2024-04-14 me
113 ad3b5b58 2024-04-14 me static int
114 ad3b5b58 2024-04-14 me dial(int https, const char *host, const char *port)
115 ad3b5b58 2024-04-14 me {
116 ad3b5b58 2024-04-14 me struct addrinfo hints, *res, *res0;
117 4c316997 2024-04-15 me int error, saved_errno, fd = -1;
118 ad3b5b58 2024-04-14 me const char *cause = NULL;
119 ad3b5b58 2024-04-14 me
120 ad3b5b58 2024-04-14 me memset(&hints, 0, sizeof(hints));
121 ad3b5b58 2024-04-14 me hints.ai_family = AF_UNSPEC;
122 ad3b5b58 2024-04-14 me hints.ai_socktype = SOCK_STREAM;
123 ad3b5b58 2024-04-14 me error = getaddrinfo(host, port, &hints, &res0);
124 ad3b5b58 2024-04-14 me if (error) {
125 ad3b5b58 2024-04-14 me warnx("%s", gai_strerror(error));
126 4c316997 2024-04-15 me return -1;
127 ad3b5b58 2024-04-14 me }
128 ad3b5b58 2024-04-14 me
129 ad3b5b58 2024-04-14 me for (res = res0; res; res = res->ai_next) {
130 ad3b5b58 2024-04-14 me fd = socket(res->ai_family, res->ai_socktype,
131 ad3b5b58 2024-04-14 me res->ai_protocol);
132 ad3b5b58 2024-04-14 me if (fd == -1) {
133 ad3b5b58 2024-04-14 me cause = "socket";
134 ad3b5b58 2024-04-14 me continue;
135 ad3b5b58 2024-04-14 me }
136 ad3b5b58 2024-04-14 me
137 ad3b5b58 2024-04-14 me if (connect(fd, res->ai_addr, res->ai_addrlen) == 0)
138 ad3b5b58 2024-04-14 me break;
139 ad3b5b58 2024-04-14 me
140 ad3b5b58 2024-04-14 me cause = "connect";
141 ad3b5b58 2024-04-14 me saved_errno = errno;
142 ad3b5b58 2024-04-14 me close(fd);
143 ad3b5b58 2024-04-14 me fd = -1;
144 ad3b5b58 2024-04-14 me errno = saved_errno;
145 ad3b5b58 2024-04-14 me }
146 ad3b5b58 2024-04-14 me freeaddrinfo(res0);
147 ad3b5b58 2024-04-14 me
148 ad3b5b58 2024-04-14 me if (fd == -1) {
149 ad3b5b58 2024-04-14 me warn("%s", cause);
150 4c316997 2024-04-15 me return -1;
151 ad3b5b58 2024-04-14 me }
152 ad3b5b58 2024-04-14 me
153 4c316997 2024-04-15 me return fd;
154 ad3b5b58 2024-04-14 me }
155 ad3b5b58 2024-04-14 me
156 4c316997 2024-04-15 me static int
157 4c316997 2024-04-15 me http_open(struct bufio *bio, int https, const char *method, const char *host, const char *port,
158 4c316997 2024-04-15 me const char *path, const char *path_sufx, const char *query, const char *ctype)
159 ad3b5b58 2024-04-14 me {
160 ad3b5b58 2024-04-14 me const char *chdr = NULL, *te = "";
161 ad3b5b58 2024-04-14 me char *p, *req;
162 ad3b5b58 2024-04-14 me int r;
163 4c316997 2024-04-15 me
164 ad3b5b58 2024-04-14 me if (strcmp(method, "POST") == 0)
165 ad3b5b58 2024-04-14 me te = "\r\nTransfer-Encoding: chunked\r\n";
166 ad3b5b58 2024-04-14 me
167 ad3b5b58 2024-04-14 me if (ctype)
168 ad3b5b58 2024-04-14 me chdr = "Content-Type: ";
169 ad3b5b58 2024-04-14 me
170 60ac0535 2024-04-28 stsp r = asprintf(&p, "%s%s/%s%s%s", got_path_is_absolute(path) ? "" :"/",
171 60ac0535 2024-04-28 stsp path, path_sufx, query ? "?" : "", query ? query : "");
172 ad3b5b58 2024-04-14 me if (r == -1)
173 ad3b5b58 2024-04-14 me err(1, "asprintf");
174 ad3b5b58 2024-04-14 me
175 ad3b5b58 2024-04-14 me r = asprintf(&req, "%s %s HTTP/1.1\r\n"
176 ad3b5b58 2024-04-14 me "Host: %s\r\n"
177 ad3b5b58 2024-04-14 me "Connection: close\r\n"
178 ad3b5b58 2024-04-14 me "User-agent: %s\r\n"
179 ad3b5b58 2024-04-14 me "%s%s%s\r\n",
180 ad3b5b58 2024-04-14 me method, p, host, GOT_USERAGENT,
181 ad3b5b58 2024-04-14 me chdr ? chdr : "", ctype ? ctype : "", te);
182 ad3b5b58 2024-04-14 me if (r == -1)
183 ad3b5b58 2024-04-14 me err(1, "asprintf");
184 4c316997 2024-04-15 me free(p);
185 ad3b5b58 2024-04-14 me
186 ad3b5b58 2024-04-14 me if (verbose > 0)
187 4c094842 2024-04-17 stsp fprintf(stderr, "%s: request: %s\n", getprogname(), req);
188 4c316997 2024-04-15 me
189 ad3b5b58 2024-04-14 me
190 4c316997 2024-04-15 me r = bufio_compose(bio, req, r);
191 4c316997 2024-04-15 me if (r == -1)
192 4c316997 2024-04-15 me err(1, "bufio_compose_fmt");
193 ad3b5b58 2024-04-14 me free(req);
194 ad3b5b58 2024-04-14 me
195 4c316997 2024-04-15 me do {
196 4c316997 2024-04-15 me r = bufio_write(bio);
197 4c316997 2024-04-15 me if (r == -1 && errno != EAGAIN)
198 4c316997 2024-04-15 me errx(1, "bufio_read: %s", bufio_io_err(bio));
199 4c316997 2024-04-15 me } while (bio->wbuf.len != 0);
200 4c316997 2024-04-15 me
201 4c316997 2024-04-15 me return 0;
202 ad3b5b58 2024-04-14 me }
203 ad3b5b58 2024-04-14 me
204 ad3b5b58 2024-04-14 me static int
205 4c316997 2024-04-15 me http_parse_reply(struct bufio *bio, int *chunked, const char *expected_ctype)
206 ad3b5b58 2024-04-14 me {
207 4c316997 2024-04-15 me char *cp, *line;
208 4c316997 2024-04-15 me size_t linelen;
209 ad3b5b58 2024-04-14 me
210 ad3b5b58 2024-04-14 me *chunked = 0;
211 ad3b5b58 2024-04-14 me
212 4c316997 2024-04-15 me line = bufio_getdelim_sync(bio, "\r\n", &linelen);
213 4c316997 2024-04-15 me if (line == NULL) {
214 4c316997 2024-04-15 me warnx("%s: bufio_getdelim_sync()", __func__);
215 ad3b5b58 2024-04-14 me return -1;
216 ad3b5b58 2024-04-14 me }
217 ad3b5b58 2024-04-14 me
218 fe24f0a3 2024-04-14 stsp if (verbose > 0)
219 4c094842 2024-04-17 stsp fprintf(stderr, "%s: response: %s\n", getprogname(), line);
220 fe24f0a3 2024-04-14 stsp
221 ad3b5b58 2024-04-14 me if ((cp = strchr(line, ' ')) == NULL) {
222 ad3b5b58 2024-04-14 me warnx("malformed HTTP response");
223 4c316997 2024-04-15 me return -1;
224 ad3b5b58 2024-04-14 me }
225 ad3b5b58 2024-04-14 me cp++;
226 ad3b5b58 2024-04-14 me
227 ad3b5b58 2024-04-14 me if (strncmp(cp, "200 ", 4) != 0) {
228 ad3b5b58 2024-04-14 me warnx("malformed HTTP response");
229 4c316997 2024-04-15 me return -1;
230 ad3b5b58 2024-04-14 me }
231 4c316997 2024-04-15 me buf_drain(&bio->rbuf, linelen);
232 ad3b5b58 2024-04-14 me
233 4c316997 2024-04-15 me while(1) {
234 4c316997 2024-04-15 me line = bufio_getdelim_sync(bio, "\r\n", &linelen);
235 4c316997 2024-04-15 me if (line == NULL) {
236 4c316997 2024-04-15 me warnx("%s: bufio_getdelim_sync()", __func__);
237 4c316997 2024-04-15 me return -1;
238 4c316997 2024-04-15 me }
239 4c316997 2024-04-15 me if (*line == '\0') {
240 4c316997 2024-04-15 me buf_drain(&bio->rbuf, linelen);
241 ad3b5b58 2024-04-14 me break;
242 4c316997 2024-04-15 me }
243 ad3b5b58 2024-04-14 me
244 ad3b5b58 2024-04-14 me if (hasprfx(line, "content-type:")) {
245 ad3b5b58 2024-04-14 me cp = strchr(line, ':') + 1;
246 ad3b5b58 2024-04-14 me cp += strspn(cp, " \t");
247 ad3b5b58 2024-04-14 me cp[strcspn(cp, " \t")] = '\0';
248 ad3b5b58 2024-04-14 me if (strcmp(cp, expected_ctype) != 0) {
249 ad3b5b58 2024-04-14 me warnx("server not using the \"smart\" "
250 ad3b5b58 2024-04-14 me "HTTP protocol.");
251 4c316997 2024-04-15 me return -1;
252 ad3b5b58 2024-04-14 me }
253 ad3b5b58 2024-04-14 me }
254 ad3b5b58 2024-04-14 me if (hasprfx(line, "transfer-encoding:")) {
255 ad3b5b58 2024-04-14 me cp = strchr(line, ':') + 1;
256 ad3b5b58 2024-04-14 me cp += strspn(cp, " \t");
257 ad3b5b58 2024-04-14 me cp[strcspn(cp, " \t")] = '\0';
258 ad3b5b58 2024-04-14 me if (strcmp(cp, "chunked") != 0) {
259 ad3b5b58 2024-04-14 me warnx("unknown transfer-encoding");
260 4c316997 2024-04-15 me return -1;
261 ad3b5b58 2024-04-14 me }
262 ad3b5b58 2024-04-14 me *chunked = 1;
263 ad3b5b58 2024-04-14 me }
264 4c316997 2024-04-15 me buf_drain(&bio->rbuf, linelen);
265 ad3b5b58 2024-04-14 me }
266 ad3b5b58 2024-04-14 me
267 ad3b5b58 2024-04-14 me return 0;
268 ad3b5b58 2024-04-14 me }
269 ad3b5b58 2024-04-14 me
270 ad3b5b58 2024-04-14 me static ssize_t
271 4c316997 2024-04-15 me http_read(struct bufio *bio, int chunked, size_t *chunksz, char *buf, size_t bufsz)
272 ad3b5b58 2024-04-14 me {
273 ad3b5b58 2024-04-14 me const char *errstr;
274 4c316997 2024-04-15 me char *line = NULL;
275 4c316997 2024-04-15 me size_t r;
276 ad3b5b58 2024-04-14 me ssize_t ret = 0, linelen;
277 ad3b5b58 2024-04-14 me
278 a0769bb1 2024-04-25 stsp if (!chunked)
279 a0769bb1 2024-04-25 stsp return bufio_drain_sync(bio, buf, bufsz);
280 ad3b5b58 2024-04-14 me
281 ad3b5b58 2024-04-14 me while (bufsz > 0) {
282 ad3b5b58 2024-04-14 me if (*chunksz == 0) {
283 ad3b5b58 2024-04-14 me again:
284 4c316997 2024-04-15 me line = bufio_getdelim_sync(bio, "\r\n", &linelen);
285 4c316997 2024-04-15 me if (line == NULL) {
286 4c316997 2024-04-15 me buf_drain(&bio->rbuf, linelen);
287 ad3b5b58 2024-04-14 me break;
288 ad3b5b58 2024-04-14 me }
289 4c316997 2024-04-15 me if (*line == '\0') {
290 4c316997 2024-04-15 me buf_drain(&bio->rbuf, linelen);
291 4c316997 2024-04-15 me goto again; /* was the CRLF after the chunk */
292 ad3b5b58 2024-04-14 me }
293 ad3b5b58 2024-04-14 me
294 ad3b5b58 2024-04-14 me *chunksz = hexstrtonum(line, 0, INT_MAX, &errstr);
295 ad3b5b58 2024-04-14 me if (errstr != NULL) {
296 ad3b5b58 2024-04-14 me warnx("invalid HTTP chunk: size is %s (%s)",
297 ad3b5b58 2024-04-14 me errstr, line);
298 ad3b5b58 2024-04-14 me ret = -1;
299 ad3b5b58 2024-04-14 me break;
300 ad3b5b58 2024-04-14 me }
301 ad3b5b58 2024-04-14 me
302 4c316997 2024-04-15 me if (*chunksz == 0) {
303 4c316997 2024-04-15 me buf_drain(&bio->rbuf, linelen);
304 ad3b5b58 2024-04-14 me break;
305 4c316997 2024-04-15 me }
306 4c316997 2024-04-15 me buf_drain(&bio->rbuf, linelen);
307 ad3b5b58 2024-04-14 me }
308 ad3b5b58 2024-04-14 me
309 4c316997 2024-04-15 me r = bufio_drain_sync(bio, buf, MINIMUM(*chunksz, bufsz));
310 ad3b5b58 2024-04-14 me if (r == 0) {
311 ad3b5b58 2024-04-14 me break;
312 ad3b5b58 2024-04-14 me }
313 ad3b5b58 2024-04-14 me
314 ad3b5b58 2024-04-14 me ret += r;
315 ad3b5b58 2024-04-14 me buf += r;
316 ad3b5b58 2024-04-14 me bufsz -= r;
317 ad3b5b58 2024-04-14 me *chunksz -= r;
318 ad3b5b58 2024-04-14 me }
319 ad3b5b58 2024-04-14 me
320 ad3b5b58 2024-04-14 me return ret;
321 ad3b5b58 2024-04-14 me }
322 ad3b5b58 2024-04-14 me
323 4c316997 2024-04-15 me static int
324 4c316997 2024-04-15 me http_chunk(struct bufio *bio, const void *buf, size_t len)
325 ad3b5b58 2024-04-14 me {
326 4c316997 2024-04-15 me int r;
327 ad3b5b58 2024-04-14 me
328 4c316997 2024-04-15 me if (bufio_compose_fmt(bio, "%zx\r\n", len) ||
329 4c316997 2024-04-15 me bufio_compose(bio, buf, len) ||
330 4c316997 2024-04-15 me bufio_compose(bio, "\r\n", 2))
331 4c316997 2024-04-15 me return 1;
332 4c316997 2024-04-15 me
333 4c316997 2024-04-15 me do {
334 4c316997 2024-04-15 me r = bufio_write(bio);
335 4c316997 2024-04-15 me if (r == -1 && errno != EAGAIN)
336 4c316997 2024-04-15 me errx(1, "bufio_read: %s", bufio_io_err(bio));
337 4c316997 2024-04-15 me } while (bio->wbuf.len != 0);
338 4c316997 2024-04-15 me
339 4c316997 2024-04-15 me return 0;
340 ad3b5b58 2024-04-14 me }
341 ad3b5b58 2024-04-14 me
342 ad3b5b58 2024-04-14 me static int
343 ad3b5b58 2024-04-14 me get_refs(int https, const char *host, const char *port, const char *path)
344 ad3b5b58 2024-04-14 me {
345 21679dc5 2024-04-22 me struct bufio bio;
346 21679dc5 2024-04-22 me char buf[GOT_PKT_MAX];
347 21679dc5 2024-04-22 me const struct got_error *e;
348 21679dc5 2024-04-22 me size_t chunksz = 0;
349 21679dc5 2024-04-22 me ssize_t r;
350 21679dc5 2024-04-22 me int skip;
351 21679dc5 2024-04-22 me int chunked;
352 21679dc5 2024-04-22 me int sock;
353 21679dc5 2024-04-22 me int ret = -1;
354 ad3b5b58 2024-04-14 me
355 4c316997 2024-04-15 me if ((sock = dial(https, host, port)) == -1)
356 ad3b5b58 2024-04-14 me return -1;
357 ad3b5b58 2024-04-14 me
358 4c316997 2024-04-15 me if (bufio_init(&bio)) {
359 4c316997 2024-04-15 me warnx("bufio_init");
360 4c316997 2024-04-15 me goto err;
361 4c316997 2024-04-15 me }
362 4c316997 2024-04-15 me bufio_set_fd(&bio, sock);
363 4c316997 2024-04-15 me if (https && bufio_starttls(&bio, host, 0, NULL, 0, NULL, 0) == -1) {
364 4c316997 2024-04-15 me warnx("bufio_starttls");
365 4c316997 2024-04-15 me goto err;
366 ad3b5b58 2024-04-14 me }
367 ad3b5b58 2024-04-14 me
368 60ac0535 2024-04-28 stsp if (http_open(&bio, https, "GET", host, port, path, "info/refs",
369 4c316997 2024-04-15 me "service=git-upload-pack", NULL) == -1)
370 4c316997 2024-04-15 me goto err;
371 4c316997 2024-04-15 me
372 b1ebf3b3 2024-04-16 stsp /* Fetch the initial reference announcement from the server. */
373 4c316997 2024-04-15 me if (http_parse_reply(&bio, &chunked, UPLOAD_PACK_ADV) == -1)
374 4c316997 2024-04-15 me goto err;
375 4c316997 2024-04-15 me
376 ad3b5b58 2024-04-14 me /* skip first pack; why git over http is like this? */
377 4c316997 2024-04-15 me r = http_read(&bio, chunked, &chunksz, buf, 4);
378 4c316997 2024-04-15 me if (r <= 0)
379 4c316997 2024-04-15 me goto err;
380 21679dc5 2024-04-22 me
381 21679dc5 2024-04-22 me e = got_pkt_readlen(&skip, buf, verbose);
382 21679dc5 2024-04-22 me if (e) {
383 21679dc5 2024-04-22 me warnx("%s", e->msg);
384 4c316997 2024-04-15 me goto err;
385 ad3b5b58 2024-04-14 me }
386 ad3b5b58 2024-04-14 me
387 ad3b5b58 2024-04-14 me /* TODO: validate it's # service=git-upload-pack\n */
388 ad3b5b58 2024-04-14 me while (skip > 0) {
389 4c316997 2024-04-15 me r = http_read(&bio, chunked, &chunksz, buf,
390 ad3b5b58 2024-04-14 me MINIMUM(skip, sizeof(buf)));
391 4c316997 2024-04-15 me if (r <= 0)
392 4c316997 2024-04-15 me goto err;
393 ad3b5b58 2024-04-14 me skip -= r;
394 ad3b5b58 2024-04-14 me }
395 ad3b5b58 2024-04-14 me
396 ad3b5b58 2024-04-14 me for (;;) {
397 4c316997 2024-04-15 me r = http_read(&bio, chunked, &chunksz, buf, sizeof(buf));
398 4c316997 2024-04-15 me if (r == -1)
399 4c316997 2024-04-15 me goto err;
400 ad3b5b58 2024-04-14 me
401 ad3b5b58 2024-04-14 me if (r == 0)
402 ad3b5b58 2024-04-14 me break;
403 ad3b5b58 2024-04-14 me
404 ad3b5b58 2024-04-14 me fwrite(buf, 1, r, stdout);
405 ad3b5b58 2024-04-14 me }
406 ad3b5b58 2024-04-14 me
407 ad3b5b58 2024-04-14 me fflush(stdout);
408 4c316997 2024-04-15 me ret = 0;
409 4c316997 2024-04-15 me err:
410 4c316997 2024-04-15 me bufio_close_sync(&bio);
411 4c316997 2024-04-15 me bufio_free(&bio);
412 4c316997 2024-04-15 me return ret;
413 ad3b5b58 2024-04-14 me }
414 ad3b5b58 2024-04-14 me
415 ad3b5b58 2024-04-14 me static int
416 ad3b5b58 2024-04-14 me upload_request(int https, const char *host, const char *port, const char *path,
417 ad3b5b58 2024-04-14 me FILE *in)
418 ad3b5b58 2024-04-14 me {
419 21679dc5 2024-04-22 me struct bufio bio;
420 21679dc5 2024-04-22 me char buf[GOT_PKT_MAX];
421 21679dc5 2024-04-22 me const struct got_error *e;
422 21679dc5 2024-04-22 me ssize_t r;
423 21679dc5 2024-04-22 me size_t chunksz = 0;
424 21679dc5 2024-04-22 me int t;
425 21679dc5 2024-04-22 me int chunked;
426 21679dc5 2024-04-22 me int sock;
427 21679dc5 2024-04-22 me int ret = -1;
428 ad3b5b58 2024-04-14 me
429 4c316997 2024-04-15 me if ((sock = dial(https, host, port)) == -1)
430 ad3b5b58 2024-04-14 me return -1;
431 44740114 2024-04-17 stsp
432 4c316997 2024-04-15 me if (bufio_init(&bio)) {
433 4c316997 2024-04-15 me warnx("bufio_init");
434 4c316997 2024-04-15 me goto err;
435 4c316997 2024-04-15 me }
436 4c316997 2024-04-15 me bufio_set_fd(&bio, sock);
437 4c316997 2024-04-15 me if (https && bufio_starttls(&bio, host, 0, NULL, 0, NULL, 0) == -1) {
438 4c316997 2024-04-15 me warnx("bufio_starttls");
439 4c316997 2024-04-15 me goto err;
440 4c316997 2024-04-15 me }
441 44740114 2024-04-17 stsp #ifndef PROFILE
442 44740114 2024-04-17 stsp /* TODO: can we push this upwards such that get_refs() is covered? */
443 44740114 2024-04-17 stsp if (pledge("stdio", NULL) == -1)
444 44740114 2024-04-17 stsp err(1, "pledge");
445 44740114 2024-04-17 stsp #endif
446 60ac0535 2024-04-28 stsp if (http_open(&bio, https, "POST", host, port, path, "git-upload-pack",
447 4c316997 2024-04-15 me NULL, UPLOAD_PACK_REQ) == -1)
448 4c316997 2024-04-15 me goto err;
449 4c316997 2024-04-15 me
450 b1ebf3b3 2024-04-16 stsp /*
451 b1ebf3b3 2024-04-16 stsp * Read have/want lines generated by got-fetch-pack and forward
452 b1ebf3b3 2024-04-16 stsp * them to the server in the POST request body.
453 b1ebf3b3 2024-04-16 stsp */
454 ad3b5b58 2024-04-14 me for (;;) {
455 ad3b5b58 2024-04-14 me r = fread(buf, 1, 4, in);
456 ad3b5b58 2024-04-14 me if (r != 4)
457 ad3b5b58 2024-04-14 me goto err;
458 ad3b5b58 2024-04-14 me
459 21679dc5 2024-04-22 me e = got_pkt_readlen(&t, buf, verbose);
460 21679dc5 2024-04-22 me if (e) {
461 21679dc5 2024-04-22 me warnx("%s", e->msg);
462 ad3b5b58 2024-04-14 me goto err;
463 ad3b5b58 2024-04-14 me }
464 ad3b5b58 2024-04-14 me
465 ad3b5b58 2024-04-14 me if (t == 0) {
466 d7988696 2024-04-19 stsp const char *flushpkt = "0000";
467 d7988696 2024-04-19 stsp if (http_chunk(&bio, flushpkt, strlen(flushpkt)))
468 4c316997 2024-04-15 me goto err;
469 d7988696 2024-04-19 stsp continue; /* got-fetch-pack will send "done" */
470 ad3b5b58 2024-04-14 me }
471 ad3b5b58 2024-04-14 me
472 ad3b5b58 2024-04-14 me if (t < 6) {
473 ad3b5b58 2024-04-14 me warnx("pktline len is too small");
474 ad3b5b58 2024-04-14 me goto err;
475 ad3b5b58 2024-04-14 me }
476 ad3b5b58 2024-04-14 me
477 ad3b5b58 2024-04-14 me r = fread(buf + 4, 1, t - 4, in);
478 ad3b5b58 2024-04-14 me if (r != t - 4)
479 ad3b5b58 2024-04-14 me goto err;
480 ad3b5b58 2024-04-14 me
481 4c316997 2024-04-15 me if (http_chunk(&bio, buf, t))
482 4c316997 2024-04-15 me goto err;
483 d7988696 2024-04-19 stsp
484 d7988696 2024-04-19 stsp /*
485 d7988696 2024-04-19 stsp * Once got-fetch-pack is done the server will
486 d7988696 2024-04-19 stsp * send pack file data.
487 d7988696 2024-04-19 stsp */
488 d7988696 2024-04-19 stsp if (t == 9 && strncmp(buf + 4, "done\n", 5) == 0) {
489 d7988696 2024-04-19 stsp if (http_chunk(&bio, NULL, 0))
490 d7988696 2024-04-19 stsp goto err;
491 d7988696 2024-04-19 stsp break;
492 d7988696 2024-04-19 stsp }
493 ad3b5b58 2024-04-14 me }
494 ad3b5b58 2024-04-14 me
495 4c316997 2024-04-15 me if (http_parse_reply(&bio, &chunked, UPLOAD_PACK_RES) == -1)
496 ad3b5b58 2024-04-14 me goto err;
497 ad3b5b58 2024-04-14 me
498 b1ebf3b3 2024-04-16 stsp /* Fetch pack file data from server. */
499 ad3b5b58 2024-04-14 me for (;;) {
500 4c316997 2024-04-15 me r = http_read(&bio, chunked, &chunksz, buf, sizeof(buf));
501 4c316997 2024-04-15 me if (r == -1)
502 4c316997 2024-04-15 me goto err;
503 ad3b5b58 2024-04-14 me
504 ad3b5b58 2024-04-14 me if (r == 0)
505 ad3b5b58 2024-04-14 me break;
506 ad3b5b58 2024-04-14 me
507 ad3b5b58 2024-04-14 me fwrite(buf, 1, r, stdout);
508 ad3b5b58 2024-04-14 me }
509 ad3b5b58 2024-04-14 me
510 4c316997 2024-04-15 me ret = 0;
511 ad3b5b58 2024-04-14 me err:
512 4c316997 2024-04-15 me bufio_close_sync(&bio);
513 4c316997 2024-04-15 me bufio_free(&bio);
514 4c316997 2024-04-15 me return ret;
515 ad3b5b58 2024-04-14 me }
516 ad3b5b58 2024-04-14 me
517 ad3b5b58 2024-04-14 me static __dead void
518 ad3b5b58 2024-04-14 me usage(void)
519 ad3b5b58 2024-04-14 me {
520 ad3b5b58 2024-04-14 me fprintf(stderr, "usage: %s [-qv] proto host port path\n",
521 ad3b5b58 2024-04-14 me getprogname());
522 ad3b5b58 2024-04-14 me exit(1);
523 ad3b5b58 2024-04-14 me }
524 ad3b5b58 2024-04-14 me
525 ad3b5b58 2024-04-14 me int
526 ad3b5b58 2024-04-14 me main(int argc, char **argv)
527 ad3b5b58 2024-04-14 me {
528 ad3b5b58 2024-04-14 me struct pollfd pfd;
529 60ac0535 2024-04-28 stsp const char *host, *port;
530 60ac0535 2024-04-28 stsp char *path;
531 ad3b5b58 2024-04-14 me int https = 0;
532 ad3b5b58 2024-04-14 me int ch;
533 ad3b5b58 2024-04-14 me
534 c4caaee8 2024-04-17 stsp #ifndef PROFILE
535 e8452664 2024-04-17 stsp if (pledge("stdio rpath inet dns unveil", NULL) == -1)
536 ad3b5b58 2024-04-14 me err(1, "pledge");
537 ad3b5b58 2024-04-14 me #endif
538 ad3b5b58 2024-04-14 me
539 ad3b5b58 2024-04-14 me while ((ch = getopt(argc, argv, "qv")) != -1) {
540 ad3b5b58 2024-04-14 me switch (ch) {
541 ad3b5b58 2024-04-14 me case 'q':
542 ad3b5b58 2024-04-14 me verbose = -1;
543 ad3b5b58 2024-04-14 me break;
544 ad3b5b58 2024-04-14 me case 'v':
545 ad3b5b58 2024-04-14 me verbose++;
546 ad3b5b58 2024-04-14 me break;
547 ad3b5b58 2024-04-14 me default:
548 ad3b5b58 2024-04-14 me usage();
549 ad3b5b58 2024-04-14 me }
550 ad3b5b58 2024-04-14 me }
551 ad3b5b58 2024-04-14 me argc -= optind;
552 ad3b5b58 2024-04-14 me argv += optind;
553 ad3b5b58 2024-04-14 me
554 ad3b5b58 2024-04-14 me if (argc != 4)
555 ad3b5b58 2024-04-14 me usage();
556 ad3b5b58 2024-04-14 me
557 ad3b5b58 2024-04-14 me https = strcmp(argv[0], "https") == 0;
558 625c83c9 2024-04-17 stsp #ifndef PROFILE
559 e8452664 2024-04-17 stsp if (https) {
560 e8452664 2024-04-17 stsp if (unveil("/etc/ssl/cert.pem", "r") == -1)
561 e8452664 2024-04-17 stsp err(1, "unveil /etc/ssl/cert.pem");
562 e8452664 2024-04-17 stsp } else {
563 625c83c9 2024-04-17 stsp /* drop "rpath" */
564 e8452664 2024-04-17 stsp if (pledge("stdio inet dns unveil", NULL) == -1)
565 625c83c9 2024-04-17 stsp err(1, "pledge");
566 625c83c9 2024-04-17 stsp }
567 e8452664 2024-04-17 stsp #else
568 e8452664 2024-04-17 stsp if (unveil("gmon.out", "rwc") != 0)
569 e8452664 2024-04-17 stsp err(1, "unveil gmon.out");
570 625c83c9 2024-04-17 stsp #endif
571 e8452664 2024-04-17 stsp if (unveil(NULL, NULL) == -1)
572 e8452664 2024-04-17 stsp err(1, "unveil NULL");
573 e8452664 2024-04-17 stsp
574 ad3b5b58 2024-04-14 me host = argv[1];
575 ad3b5b58 2024-04-14 me port = argv[2];
576 ad3b5b58 2024-04-14 me path = argv[3];
577 60ac0535 2024-04-28 stsp got_path_strip_trailing_slashes(path);
578 ad3b5b58 2024-04-14 me
579 ad3b5b58 2024-04-14 me if (get_refs(https, host, port, path) == -1)
580 ad3b5b58 2024-04-14 me errx(1, "failed to get refs");
581 ad3b5b58 2024-04-14 me
582 ad3b5b58 2024-04-14 me pfd.fd = 0;
583 ad3b5b58 2024-04-14 me pfd.events = POLLIN;
584 ad3b5b58 2024-04-14 me if (poll(&pfd, 1, INFTIM) == -1)
585 ad3b5b58 2024-04-14 me err(1, "poll");
586 ad3b5b58 2024-04-14 me
587 ad3b5b58 2024-04-14 me if ((ch = fgetc(stdin)) == EOF)
588 ad3b5b58 2024-04-14 me return 0;
589 ad3b5b58 2024-04-14 me
590 ad3b5b58 2024-04-14 me ungetc(ch, stdin);
591 ad3b5b58 2024-04-14 me if (upload_request(https, host, port, path, stdin) == -1) {
592 ad3b5b58 2024-04-14 me fflush(tmp);
593 ad3b5b58 2024-04-14 me errx(1, "failed to upload request");
594 ad3b5b58 2024-04-14 me }
595 ad3b5b58 2024-04-14 me
596 ad3b5b58 2024-04-14 me return 0;
597 ad3b5b58 2024-04-14 me }