http.c (169386) | http.c (174588) |
---|---|
1/*- 2 * Copyright (c) 2000-2004 Dag-Erling Co�dan Sm�rgrav 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 13 unchanged lines hidden (view full) --- 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 2000-2004 Dag-Erling Co�dan Sm�rgrav 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 13 unchanged lines hidden (view full) --- 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> |
30__FBSDID("$FreeBSD: head/lib/libfetch/http.c 169386 2007-05-08 19:28:03Z des $"); | 30__FBSDID("$FreeBSD: head/lib/libfetch/http.c 174588 2007-12-14 10:26:58Z des $"); |
31 32/* 33 * The following copyright applies to the base64 code: 34 * 35 *- 36 * Copyright 1997 Massachusetts Institute of Technology 37 * 38 * Permission to use, copy, modify, and distribute this software and --- 86 unchanged lines hidden (view full) --- 125 size_t total; 126#endif 127}; 128 129/* 130 * Get next chunk header 131 */ 132static int | 31 32/* 33 * The following copyright applies to the base64 code: 34 * 35 *- 36 * Copyright 1997 Massachusetts Institute of Technology 37 * 38 * Permission to use, copy, modify, and distribute this software and --- 86 unchanged lines hidden (view full) --- 125 size_t total; 126#endif 127}; 128 129/* 130 * Get next chunk header 131 */ 132static int |
133_http_new_chunk(struct httpio *io) | 133http_new_chunk(struct httpio *io) |
134{ 135 char *p; 136 | 134{ 135 char *p; 136 |
137 if (_fetch_getln(io->conn) == -1) | 137 if (fetch_getln(io->conn) == -1) |
138 return (-1); 139 140 if (io->conn->buflen < 2 || !ishexnumber(*io->conn->buf)) 141 return (-1); 142 143 for (p = io->conn->buf; *p && !isspace(*p); ++p) { 144 if (*p == ';') 145 break; --- 22 unchanged lines hidden (view full) --- 168 169 return (io->chunksize); 170} 171 172/* 173 * Grow the input buffer to at least len bytes 174 */ 175static inline int | 138 return (-1); 139 140 if (io->conn->buflen < 2 || !ishexnumber(*io->conn->buf)) 141 return (-1); 142 143 for (p = io->conn->buf; *p && !isspace(*p); ++p) { 144 if (*p == ';') 145 break; --- 22 unchanged lines hidden (view full) --- 168 169 return (io->chunksize); 170} 171 172/* 173 * Grow the input buffer to at least len bytes 174 */ 175static inline int |
176_http_growbuf(struct httpio *io, size_t len) | 176http_growbuf(struct httpio *io, size_t len) |
177{ 178 char *tmp; 179 180 if (io->bufsize >= len) 181 return (0); 182 183 if ((tmp = realloc(io->buf, len)) == NULL) 184 return (-1); 185 io->buf = tmp; 186 io->bufsize = len; 187 return (0); 188} 189 190/* 191 * Fill the input buffer, do chunk decoding on the fly 192 */ 193static int | 177{ 178 char *tmp; 179 180 if (io->bufsize >= len) 181 return (0); 182 183 if ((tmp = realloc(io->buf, len)) == NULL) 184 return (-1); 185 io->buf = tmp; 186 io->bufsize = len; 187 return (0); 188} 189 190/* 191 * Fill the input buffer, do chunk decoding on the fly 192 */ 193static int |
194_http_fillbuf(struct httpio *io, size_t len) | 194http_fillbuf(struct httpio *io, size_t len) |
195{ 196 if (io->error) 197 return (-1); 198 if (io->eof) 199 return (0); 200 201 if (io->chunked == 0) { | 195{ 196 if (io->error) 197 return (-1); 198 if (io->eof) 199 return (0); 200 201 if (io->chunked == 0) { |
202 if (_http_growbuf(io, len) == -1) | 202 if (http_growbuf(io, len) == -1) |
203 return (-1); | 203 return (-1); |
204 if ((io->buflen = _fetch_read(io->conn, io->buf, len)) == -1) { | 204 if ((io->buflen = fetch_read(io->conn, io->buf, len)) == -1) { |
205 io->error = 1; 206 return (-1); 207 } 208 io->bufpos = 0; 209 return (io->buflen); 210 } 211 212 if (io->chunksize == 0) { | 205 io->error = 1; 206 return (-1); 207 } 208 io->bufpos = 0; 209 return (io->buflen); 210 } 211 212 if (io->chunksize == 0) { |
213 switch (_http_new_chunk(io)) { | 213 switch (http_new_chunk(io)) { |
214 case -1: 215 io->error = 1; 216 return (-1); 217 case 0: 218 io->eof = 1; 219 return (0); 220 } 221 } 222 223 if (len > io->chunksize) 224 len = io->chunksize; | 214 case -1: 215 io->error = 1; 216 return (-1); 217 case 0: 218 io->eof = 1; 219 return (0); 220 } 221 } 222 223 if (len > io->chunksize) 224 len = io->chunksize; |
225 if (_http_growbuf(io, len) == -1) | 225 if (http_growbuf(io, len) == -1) |
226 return (-1); | 226 return (-1); |
227 if ((io->buflen = _fetch_read(io->conn, io->buf, len)) == -1) { | 227 if ((io->buflen = fetch_read(io->conn, io->buf, len)) == -1) { |
228 io->error = 1; 229 return (-1); 230 } 231 io->chunksize -= io->buflen; 232 233 if (io->chunksize == 0) { 234 char endl[2]; 235 | 228 io->error = 1; 229 return (-1); 230 } 231 io->chunksize -= io->buflen; 232 233 if (io->chunksize == 0) { 234 char endl[2]; 235 |
236 if (_fetch_read(io->conn, endl, 2) != 2 || | 236 if (fetch_read(io->conn, endl, 2) != 2 || |
237 endl[0] != '\r' || endl[1] != '\n') 238 return (-1); 239 } 240 241 io->bufpos = 0; 242 243 return (io->buflen); 244} 245 246/* 247 * Read function 248 */ 249static int | 237 endl[0] != '\r' || endl[1] != '\n') 238 return (-1); 239 } 240 241 io->bufpos = 0; 242 243 return (io->buflen); 244} 245 246/* 247 * Read function 248 */ 249static int |
250_http_readfn(void *v, char *buf, int len) | 250http_readfn(void *v, char *buf, int len) |
251{ 252 struct httpio *io = (struct httpio *)v; 253 int l, pos; 254 255 if (io->error) 256 return (-1); 257 if (io->eof) 258 return (0); 259 260 for (pos = 0; len > 0; pos += l, len -= l) { 261 /* empty buffer */ 262 if (!io->buf || io->bufpos == io->buflen) | 251{ 252 struct httpio *io = (struct httpio *)v; 253 int l, pos; 254 255 if (io->error) 256 return (-1); 257 if (io->eof) 258 return (0); 259 260 for (pos = 0; len > 0; pos += l, len -= l) { 261 /* empty buffer */ 262 if (!io->buf || io->bufpos == io->buflen) |
263 if (_http_fillbuf(io, len) < 1) | 263 if (http_fillbuf(io, len) < 1) |
264 break; 265 l = io->buflen - io->bufpos; 266 if (len < l) 267 l = len; 268 bcopy(io->buf + io->bufpos, buf + pos, l); 269 io->bufpos += l; 270 } 271 272 if (!pos && io->error) 273 return (-1); 274 return (pos); 275} 276 277/* 278 * Write function 279 */ 280static int | 264 break; 265 l = io->buflen - io->bufpos; 266 if (len < l) 267 l = len; 268 bcopy(io->buf + io->bufpos, buf + pos, l); 269 io->bufpos += l; 270 } 271 272 if (!pos && io->error) 273 return (-1); 274 return (pos); 275} 276 277/* 278 * Write function 279 */ 280static int |
281_http_writefn(void *v, const char *buf, int len) | 281http_writefn(void *v, const char *buf, int len) |
282{ 283 struct httpio *io = (struct httpio *)v; 284 | 282{ 283 struct httpio *io = (struct httpio *)v; 284 |
285 return (_fetch_write(io->conn, buf, len)); | 285 return (fetch_write(io->conn, buf, len)); |
286} 287 288/* 289 * Close function 290 */ 291static int | 286} 287 288/* 289 * Close function 290 */ 291static int |
292_http_closefn(void *v) | 292http_closefn(void *v) |
293{ 294 struct httpio *io = (struct httpio *)v; 295 int r; 296 | 293{ 294 struct httpio *io = (struct httpio *)v; 295 int r; 296 |
297 r = _fetch_close(io->conn); | 297 r = fetch_close(io->conn); |
298 if (io->buf) 299 free(io->buf); 300 free(io); 301 return (r); 302} 303 304/* 305 * Wrap a file descriptor up 306 */ 307static FILE * | 298 if (io->buf) 299 free(io->buf); 300 free(io); 301 return (r); 302} 303 304/* 305 * Wrap a file descriptor up 306 */ 307static FILE * |
308_http_funopen(conn_t *conn, int chunked) | 308http_funopen(conn_t *conn, int chunked) |
309{ 310 struct httpio *io; 311 FILE *f; 312 313 if ((io = calloc(1, sizeof(*io))) == NULL) { | 309{ 310 struct httpio *io; 311 FILE *f; 312 313 if ((io = calloc(1, sizeof(*io))) == NULL) { |
314 _fetch_syserr(); | 314 fetch_syserr(); |
315 return (NULL); 316 } 317 io->conn = conn; 318 io->chunked = chunked; | 315 return (NULL); 316 } 317 io->conn = conn; 318 io->chunked = chunked; |
319 f = funopen(io, _http_readfn, _http_writefn, NULL, _http_closefn); | 319 f = funopen(io, http_readfn, http_writefn, NULL, http_closefn); |
320 if (f == NULL) { | 320 if (f == NULL) { |
321 _fetch_syserr(); | 321 fetch_syserr(); |
322 free(io); 323 return (NULL); 324 } 325 return (f); 326} 327 328 329/***************************************************************************** --- 27 unchanged lines hidden (view full) --- 357 { hdr_www_authenticate, "WWW-Authenticate" }, 358 { hdr_unknown, NULL }, 359}; 360 361/* 362 * Send a formatted line; optionally echo to terminal 363 */ 364static int | 322 free(io); 323 return (NULL); 324 } 325 return (f); 326} 327 328 329/***************************************************************************** --- 27 unchanged lines hidden (view full) --- 357 { hdr_www_authenticate, "WWW-Authenticate" }, 358 { hdr_unknown, NULL }, 359}; 360 361/* 362 * Send a formatted line; optionally echo to terminal 363 */ 364static int |
365_http_cmd(conn_t *conn, const char *fmt, ...) | 365http_cmd(conn_t *conn, const char *fmt, ...) |
366{ 367 va_list ap; 368 size_t len; 369 char *msg; 370 int r; 371 372 va_start(ap, fmt); 373 len = vasprintf(&msg, fmt, ap); 374 va_end(ap); 375 376 if (msg == NULL) { 377 errno = ENOMEM; | 366{ 367 va_list ap; 368 size_t len; 369 char *msg; 370 int r; 371 372 va_start(ap, fmt); 373 len = vasprintf(&msg, fmt, ap); 374 va_end(ap); 375 376 if (msg == NULL) { 377 errno = ENOMEM; |
378 _fetch_syserr(); | 378 fetch_syserr(); |
379 return (-1); 380 } 381 | 379 return (-1); 380 } 381 |
382 r = _fetch_putln(conn, msg, len); | 382 r = fetch_putln(conn, msg, len); |
383 free(msg); 384 385 if (r == -1) { | 383 free(msg); 384 385 if (r == -1) { |
386 _fetch_syserr(); | 386 fetch_syserr(); |
387 return (-1); 388 } 389 390 return (0); 391} 392 393/* 394 * Get and parse status line 395 */ 396static int | 387 return (-1); 388 } 389 390 return (0); 391} 392 393/* 394 * Get and parse status line 395 */ 396static int |
397_http_get_reply(conn_t *conn) | 397http_get_reply(conn_t *conn) |
398{ 399 char *p; 400 | 398{ 399 char *p; 400 |
401 if (_fetch_getln(conn) == -1) | 401 if (fetch_getln(conn) == -1) |
402 return (-1); 403 /* 404 * A valid status line looks like "HTTP/m.n xyz reason" where m 405 * and n are the major and minor protocol version numbers and xyz 406 * is the reply code. 407 * Unfortunately, there are servers out there (NCSA 1.5.1, to name 408 * just one) that do not send a version number, so we can't rely 409 * on finding one, but if we do, insist on it being 1.0 or 1.1. --- 14 unchanged lines hidden (view full) --- 424 return (conn->err); 425} 426 427/* 428 * Check a header; if the type matches the given string, return a pointer 429 * to the beginning of the value. 430 */ 431static const char * | 402 return (-1); 403 /* 404 * A valid status line looks like "HTTP/m.n xyz reason" where m 405 * and n are the major and minor protocol version numbers and xyz 406 * is the reply code. 407 * Unfortunately, there are servers out there (NCSA 1.5.1, to name 408 * just one) that do not send a version number, so we can't rely 409 * on finding one, but if we do, insist on it being 1.0 or 1.1. --- 14 unchanged lines hidden (view full) --- 424 return (conn->err); 425} 426 427/* 428 * Check a header; if the type matches the given string, return a pointer 429 * to the beginning of the value. 430 */ 431static const char * |
432_http_match(const char *str, const char *hdr) | 432http_match(const char *str, const char *hdr) |
433{ 434 while (*str && *hdr && tolower(*str++) == tolower(*hdr++)) 435 /* nothing */; 436 if (*str || *hdr != ':') 437 return (NULL); 438 while (*hdr && isspace(*++hdr)) 439 /* nothing */; 440 return (hdr); 441} 442 443/* 444 * Get the next header and return the appropriate symbolic code. 445 */ 446static hdr_t | 433{ 434 while (*str && *hdr && tolower(*str++) == tolower(*hdr++)) 435 /* nothing */; 436 if (*str || *hdr != ':') 437 return (NULL); 438 while (*hdr && isspace(*++hdr)) 439 /* nothing */; 440 return (hdr); 441} 442 443/* 444 * Get the next header and return the appropriate symbolic code. 445 */ 446static hdr_t |
447_http_next_header(conn_t *conn, const char **p) | 447http_next_header(conn_t *conn, const char **p) |
448{ 449 int i; 450 | 448{ 449 int i; 450 |
451 if (_fetch_getln(conn) == -1) | 451 if (fetch_getln(conn) == -1) |
452 return (hdr_syserror); 453 while (conn->buflen && isspace(conn->buf[conn->buflen - 1])) 454 conn->buflen--; 455 conn->buf[conn->buflen] = '\0'; 456 if (conn->buflen == 0) 457 return (hdr_end); 458 /* 459 * We could check for malformed headers but we don't really care. 460 * A valid header starts with a token immediately followed by a 461 * colon; a token is any sequence of non-control, non-whitespace 462 * characters except "()<>@,;:\\\"{}". 463 */ 464 for (i = 0; hdr_names[i].num != hdr_unknown; i++) | 452 return (hdr_syserror); 453 while (conn->buflen && isspace(conn->buf[conn->buflen - 1])) 454 conn->buflen--; 455 conn->buf[conn->buflen] = '\0'; 456 if (conn->buflen == 0) 457 return (hdr_end); 458 /* 459 * We could check for malformed headers but we don't really care. 460 * A valid header starts with a token immediately followed by a 461 * colon; a token is any sequence of non-control, non-whitespace 462 * characters except "()<>@,;:\\\"{}". 463 */ 464 for (i = 0; hdr_names[i].num != hdr_unknown; i++) |
465 if ((*p = _http_match(hdr_names[i].name, conn->buf)) != NULL) | 465 if ((*p = http_match(hdr_names[i].name, conn->buf)) != NULL) |
466 return (hdr_names[i].num); 467 return (hdr_unknown); 468} 469 470/* 471 * Parse a last-modified header 472 */ 473static int | 466 return (hdr_names[i].num); 467 return (hdr_unknown); 468} 469 470/* 471 * Parse a last-modified header 472 */ 473static int |
474_http_parse_mtime(const char *p, time_t *mtime) | 474http_parse_mtime(const char *p, time_t *mtime) |
475{ 476 char locale[64], *r; 477 struct tm tm; 478 479 strncpy(locale, setlocale(LC_TIME, NULL), sizeof(locale)); 480 setlocale(LC_TIME, "C"); 481 r = strptime(p, "%a, %d %b %Y %H:%M:%S GMT", &tm); 482 /* XXX should add support for date-2 and date-3 */ --- 7 unchanged lines hidden (view full) --- 490 *mtime = timegm(&tm); 491 return (0); 492} 493 494/* 495 * Parse a content-length header 496 */ 497static int | 475{ 476 char locale[64], *r; 477 struct tm tm; 478 479 strncpy(locale, setlocale(LC_TIME, NULL), sizeof(locale)); 480 setlocale(LC_TIME, "C"); 481 r = strptime(p, "%a, %d %b %Y %H:%M:%S GMT", &tm); 482 /* XXX should add support for date-2 and date-3 */ --- 7 unchanged lines hidden (view full) --- 490 *mtime = timegm(&tm); 491 return (0); 492} 493 494/* 495 * Parse a content-length header 496 */ 497static int |
498_http_parse_length(const char *p, off_t *length) | 498http_parse_length(const char *p, off_t *length) |
499{ 500 off_t len; 501 502 for (len = 0; *p && isdigit(*p); ++p) 503 len = len * 10 + (*p - '0'); 504 if (*p) 505 return (-1); 506 DEBUG(fprintf(stderr, "content length: [%lld]\n", 507 (long long)len)); 508 *length = len; 509 return (0); 510} 511 512/* 513 * Parse a content-range header 514 */ 515static int | 499{ 500 off_t len; 501 502 for (len = 0; *p && isdigit(*p); ++p) 503 len = len * 10 + (*p - '0'); 504 if (*p) 505 return (-1); 506 DEBUG(fprintf(stderr, "content length: [%lld]\n", 507 (long long)len)); 508 *length = len; 509 return (0); 510} 511 512/* 513 * Parse a content-range header 514 */ 515static int |
516_http_parse_range(const char *p, off_t *offset, off_t *length, off_t *size) | 516http_parse_range(const char *p, off_t *offset, off_t *length, off_t *size) |
517{ 518 off_t first, last, len; 519 520 if (strncasecmp(p, "bytes ", 6) != 0) 521 return (-1); 522 p += 6; 523 if (*p == '*') { 524 first = last = -1; --- 30 unchanged lines hidden (view full) --- 555/***************************************************************************** 556 * Helper functions for authorization 557 */ 558 559/* 560 * Base64 encoding 561 */ 562static char * | 517{ 518 off_t first, last, len; 519 520 if (strncasecmp(p, "bytes ", 6) != 0) 521 return (-1); 522 p += 6; 523 if (*p == '*') { 524 first = last = -1; --- 30 unchanged lines hidden (view full) --- 555/***************************************************************************** 556 * Helper functions for authorization 557 */ 558 559/* 560 * Base64 encoding 561 */ 562static char * |
563_http_base64(const char *src) | 563http_base64(const char *src) |
564{ 565 static const char base64[] = 566 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 567 "abcdefghijklmnopqrstuvwxyz" 568 "0123456789+/"; 569 char *str, *dst; 570 size_t l; 571 int t, r; --- 39 unchanged lines hidden (view full) --- 611 *dst = 0; 612 return (str); 613} 614 615/* 616 * Encode username and password 617 */ 618static int | 564{ 565 static const char base64[] = 566 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 567 "abcdefghijklmnopqrstuvwxyz" 568 "0123456789+/"; 569 char *str, *dst; 570 size_t l; 571 int t, r; --- 39 unchanged lines hidden (view full) --- 611 *dst = 0; 612 return (str); 613} 614 615/* 616 * Encode username and password 617 */ 618static int |
619_http_basic_auth(conn_t *conn, const char *hdr, const char *usr, const char *pwd) | 619http_basic_auth(conn_t *conn, const char *hdr, const char *usr, const char *pwd) |
620{ 621 char *upw, *auth; 622 int r; 623 624 DEBUG(fprintf(stderr, "usr: [%s]\n", usr)); 625 DEBUG(fprintf(stderr, "pwd: [%s]\n", pwd)); 626 if (asprintf(&upw, "%s:%s", usr, pwd) == -1) 627 return (-1); | 620{ 621 char *upw, *auth; 622 int r; 623 624 DEBUG(fprintf(stderr, "usr: [%s]\n", usr)); 625 DEBUG(fprintf(stderr, "pwd: [%s]\n", pwd)); 626 if (asprintf(&upw, "%s:%s", usr, pwd) == -1) 627 return (-1); |
628 auth = _http_base64(upw); | 628 auth = http_base64(upw); |
629 free(upw); 630 if (auth == NULL) 631 return (-1); | 629 free(upw); 630 if (auth == NULL) 631 return (-1); |
632 r = _http_cmd(conn, "%s: Basic %s", hdr, auth); | 632 r = http_cmd(conn, "%s: Basic %s", hdr, auth); |
633 free(auth); 634 return (r); 635} 636 637/* 638 * Send an authorization header 639 */ 640static int | 633 free(auth); 634 return (r); 635} 636 637/* 638 * Send an authorization header 639 */ 640static int |
641_http_authorize(conn_t *conn, const char *hdr, const char *p) | 641http_authorize(conn_t *conn, const char *hdr, const char *p) |
642{ 643 /* basic authorization */ 644 if (strncasecmp(p, "basic:", 6) == 0) { 645 char *user, *pwd, *str; 646 int r; 647 648 /* skip realm */ 649 for (p += 6; *p && *p != ':'; ++p) 650 /* nothing */ ; 651 if (!*p || strchr(++p, ':') == NULL) 652 return (-1); 653 if ((str = strdup(p)) == NULL) 654 return (-1); /* XXX */ 655 user = str; 656 pwd = strchr(str, ':'); 657 *pwd++ = '\0'; | 642{ 643 /* basic authorization */ 644 if (strncasecmp(p, "basic:", 6) == 0) { 645 char *user, *pwd, *str; 646 int r; 647 648 /* skip realm */ 649 for (p += 6; *p && *p != ':'; ++p) 650 /* nothing */ ; 651 if (!*p || strchr(++p, ':') == NULL) 652 return (-1); 653 if ((str = strdup(p)) == NULL) 654 return (-1); /* XXX */ 655 user = str; 656 pwd = strchr(str, ':'); 657 *pwd++ = '\0'; |
658 r = _http_basic_auth(conn, hdr, user, pwd); | 658 r = http_basic_auth(conn, hdr, user, pwd); |
659 free(str); 660 return (r); 661 } 662 return (-1); 663} 664 665 666/***************************************************************************** 667 * Helper functions for connecting to a server or proxy 668 */ 669 670/* 671 * Connect to the correct HTTP server or proxy. 672 */ 673static conn_t * | 659 free(str); 660 return (r); 661 } 662 return (-1); 663} 664 665 666/***************************************************************************** 667 * Helper functions for connecting to a server or proxy 668 */ 669 670/* 671 * Connect to the correct HTTP server or proxy. 672 */ 673static conn_t * |
674_http_connect(struct url *URL, struct url *purl, const char *flags) | 674http_connect(struct url *URL, struct url *purl, const char *flags) |
675{ 676 conn_t *conn; 677 int verbose; 678 int af, val; 679 680#ifdef INET6 681 af = AF_UNSPEC; 682#else --- 11 unchanged lines hidden (view full) --- 694 if (purl && strcasecmp(URL->scheme, SCHEME_HTTPS) != 0) { 695 URL = purl; 696 } else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0) { 697 /* can't talk http to an ftp server */ 698 /* XXX should set an error code */ 699 return (NULL); 700 } 701 | 675{ 676 conn_t *conn; 677 int verbose; 678 int af, val; 679 680#ifdef INET6 681 af = AF_UNSPEC; 682#else --- 11 unchanged lines hidden (view full) --- 694 if (purl && strcasecmp(URL->scheme, SCHEME_HTTPS) != 0) { 695 URL = purl; 696 } else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0) { 697 /* can't talk http to an ftp server */ 698 /* XXX should set an error code */ 699 return (NULL); 700 } 701 |
702 if ((conn = _fetch_connect(URL->host, URL->port, af, verbose)) == NULL) 703 /* _fetch_connect() has already set an error code */ | 702 if ((conn = fetch_connect(URL->host, URL->port, af, verbose)) == NULL) 703 /* fetch_connect() has already set an error code */ |
704 return (NULL); 705 if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0 && | 704 return (NULL); 705 if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0 && |
706 _fetch_ssl(conn, verbose) == -1) { 707 _fetch_close(conn); | 706 fetch_ssl(conn, verbose) == -1) { 707 fetch_close(conn); |
708 /* grrr */ 709 errno = EAUTH; | 708 /* grrr */ 709 errno = EAUTH; |
710 _fetch_syserr(); | 710 fetch_syserr(); |
711 return (NULL); 712 } 713 714 val = 1; 715 setsockopt(conn->sd, IPPROTO_TCP, TCP_NOPUSH, &val, sizeof(val)); 716 717 return (conn); 718} 719 720static struct url * | 711 return (NULL); 712 } 713 714 val = 1; 715 setsockopt(conn->sd, IPPROTO_TCP, TCP_NOPUSH, &val, sizeof(val)); 716 717 return (conn); 718} 719 720static struct url * |
721_http_get_proxy(const char *flags) | 721http_get_proxy(const char *flags) |
722{ 723 struct url *purl; 724 char *p; 725 726 if (flags != NULL && strchr(flags, 'd') != NULL) 727 return (NULL); 728 if (((p = getenv("HTTP_PROXY")) || (p = getenv("http_proxy"))) && 729 *p && (purl = fetchParseURL(p))) { 730 if (!*purl->scheme) 731 strcpy(purl->scheme, SCHEME_HTTP); 732 if (!purl->port) | 722{ 723 struct url *purl; 724 char *p; 725 726 if (flags != NULL && strchr(flags, 'd') != NULL) 727 return (NULL); 728 if (((p = getenv("HTTP_PROXY")) || (p = getenv("http_proxy"))) && 729 *p && (purl = fetchParseURL(p))) { 730 if (!*purl->scheme) 731 strcpy(purl->scheme, SCHEME_HTTP); 732 if (!purl->port) |
733 purl->port = _fetch_default_proxy_port(purl->scheme); | 733 purl->port = fetch_default_proxy_port(purl->scheme); |
734 if (strcasecmp(purl->scheme, SCHEME_HTTP) == 0) 735 return (purl); 736 fetchFreeURL(purl); 737 } 738 return (NULL); 739} 740 741static void | 734 if (strcasecmp(purl->scheme, SCHEME_HTTP) == 0) 735 return (purl); 736 fetchFreeURL(purl); 737 } 738 return (NULL); 739} 740 741static void |
742_http_print_html(FILE *out, FILE *in) | 742http_print_html(FILE *out, FILE *in) |
743{ 744 size_t len; 745 char *line, *p, *q; 746 int comment, tag; 747 748 comment = tag = 0; 749 while ((line = fgetln(in, &len)) != NULL) { 750 while (len && isspace(line[len - 1])) --- 32 unchanged lines hidden (view full) --- 783 784/* 785 * Send a request and process the reply 786 * 787 * XXX This function is way too long, the do..while loop should be split 788 * XXX off into a separate function. 789 */ 790FILE * | 743{ 744 size_t len; 745 char *line, *p, *q; 746 int comment, tag; 747 748 comment = tag = 0; 749 while ((line = fgetln(in, &len)) != NULL) { 750 while (len && isspace(line[len - 1])) --- 32 unchanged lines hidden (view full) --- 783 784/* 785 * Send a request and process the reply 786 * 787 * XXX This function is way too long, the do..while loop should be split 788 * XXX off into a separate function. 789 */ 790FILE * |
791_http_request(struct url *URL, const char *op, struct url_stat *us, | 791http_request(struct url *URL, const char *op, struct url_stat *us, |
792 struct url *purl, const char *flags) 793{ 794 conn_t *conn; 795 struct url *url, *new; 796 int chunked, direct, need_auth, noredirect, verbose; 797 int e, i, n, val; 798 off_t offset, clength, length, size; 799 time_t mtime; --- 26 unchanged lines hidden (view full) --- 826 offset = 0; 827 clength = -1; 828 length = -1; 829 size = -1; 830 mtime = 0; 831 832 /* check port */ 833 if (!url->port) | 792 struct url *purl, const char *flags) 793{ 794 conn_t *conn; 795 struct url *url, *new; 796 int chunked, direct, need_auth, noredirect, verbose; 797 int e, i, n, val; 798 off_t offset, clength, length, size; 799 time_t mtime; --- 26 unchanged lines hidden (view full) --- 826 offset = 0; 827 clength = -1; 828 length = -1; 829 size = -1; 830 mtime = 0; 831 832 /* check port */ 833 if (!url->port) |
834 url->port = _fetch_default_port(url->scheme); | 834 url->port = fetch_default_port(url->scheme); |
835 836 /* were we redirected to an FTP URL? */ 837 if (purl == NULL && strcmp(url->scheme, SCHEME_FTP) == 0) { 838 if (strcmp(op, "GET") == 0) | 835 836 /* were we redirected to an FTP URL? */ 837 if (purl == NULL && strcmp(url->scheme, SCHEME_FTP) == 0) { 838 if (strcmp(op, "GET") == 0) |
839 return (_ftp_request(url, "RETR", us, purl, flags)); | 839 return (ftp_request(url, "RETR", us, purl, flags)); |
840 else if (strcmp(op, "HEAD") == 0) | 840 else if (strcmp(op, "HEAD") == 0) |
841 return (_ftp_request(url, "STAT", us, purl, flags)); | 841 return (ftp_request(url, "STAT", us, purl, flags)); |
842 } 843 844 /* connect to server or proxy */ | 842 } 843 844 /* connect to server or proxy */ |
845 if ((conn = _http_connect(url, purl, flags)) == NULL) | 845 if ((conn = http_connect(url, purl, flags)) == NULL) |
846 goto ouch; 847 848 host = url->host; 849#ifdef INET6 850 if (strchr(url->host, ':')) { 851 snprintf(hbuf, sizeof(hbuf), "[%s]", url->host); 852 host = hbuf; 853 } 854#endif | 846 goto ouch; 847 848 host = url->host; 849#ifdef INET6 850 if (strchr(url->host, ':')) { 851 snprintf(hbuf, sizeof(hbuf), "[%s]", url->host); 852 host = hbuf; 853 } 854#endif |
855 if (url->port != _fetch_default_port(url->scheme)) { | 855 if (url->port != fetch_default_port(url->scheme)) { |
856 if (host != hbuf) { 857 strcpy(hbuf, host); 858 host = hbuf; 859 } 860 snprintf(hbuf + strlen(hbuf), 861 sizeof(hbuf) - strlen(hbuf), ":%d", url->port); 862 } 863 864 /* send request */ 865 if (verbose) | 856 if (host != hbuf) { 857 strcpy(hbuf, host); 858 host = hbuf; 859 } 860 snprintf(hbuf + strlen(hbuf), 861 sizeof(hbuf) - strlen(hbuf), ":%d", url->port); 862 } 863 864 /* send request */ 865 if (verbose) |
866 _fetch_info("requesting %s://%s%s", | 866 fetch_info("requesting %s://%s%s", |
867 url->scheme, host, url->doc); 868 if (purl) { | 867 url->scheme, host, url->doc); 868 if (purl) { |
869 _http_cmd(conn, "%s %s://%s%s HTTP/1.1", | 869 http_cmd(conn, "%s %s://%s%s HTTP/1.1", |
870 op, url->scheme, host, url->doc); 871 } else { | 870 op, url->scheme, host, url->doc); 871 } else { |
872 _http_cmd(conn, "%s %s HTTP/1.1", | 872 http_cmd(conn, "%s %s HTTP/1.1", |
873 op, url->doc); 874 } 875 876 /* virtual host */ | 873 op, url->doc); 874 } 875 876 /* virtual host */ |
877 _http_cmd(conn, "Host: %s", host); | 877 http_cmd(conn, "Host: %s", host); |
878 879 /* proxy authorization */ 880 if (purl) { 881 if (*purl->user || *purl->pwd) | 878 879 /* proxy authorization */ 880 if (purl) { 881 if (*purl->user || *purl->pwd) |
882 _http_basic_auth(conn, "Proxy-Authorization", | 882 http_basic_auth(conn, "Proxy-Authorization", |
883 purl->user, purl->pwd); 884 else if ((p = getenv("HTTP_PROXY_AUTH")) != NULL && *p != '\0') | 883 purl->user, purl->pwd); 884 else if ((p = getenv("HTTP_PROXY_AUTH")) != NULL && *p != '\0') |
885 _http_authorize(conn, "Proxy-Authorization", p); | 885 http_authorize(conn, "Proxy-Authorization", p); |
886 } 887 888 /* server authorization */ 889 if (need_auth || *url->user || *url->pwd) { 890 if (*url->user || *url->pwd) | 886 } 887 888 /* server authorization */ 889 if (need_auth || *url->user || *url->pwd) { 890 if (*url->user || *url->pwd) |
891 _http_basic_auth(conn, "Authorization", url->user, url->pwd); | 891 http_basic_auth(conn, "Authorization", url->user, url->pwd); |
892 else if ((p = getenv("HTTP_AUTH")) != NULL && *p != '\0') | 892 else if ((p = getenv("HTTP_AUTH")) != NULL && *p != '\0') |
893 _http_authorize(conn, "Authorization", p); | 893 http_authorize(conn, "Authorization", p); |
894 else if (fetchAuthMethod && fetchAuthMethod(url) == 0) { | 894 else if (fetchAuthMethod && fetchAuthMethod(url) == 0) { |
895 _http_basic_auth(conn, "Authorization", url->user, url->pwd); | 895 http_basic_auth(conn, "Authorization", url->user, url->pwd); |
896 } else { | 896 } else { |
897 _http_seterr(HTTP_NEED_AUTH); | 897 http_seterr(HTTP_NEED_AUTH); |
898 goto ouch; 899 } 900 } 901 902 /* other headers */ 903 if ((p = getenv("HTTP_REFERER")) != NULL && *p != '\0') { 904 if (strcasecmp(p, "auto") == 0) | 898 goto ouch; 899 } 900 } 901 902 /* other headers */ 903 if ((p = getenv("HTTP_REFERER")) != NULL && *p != '\0') { 904 if (strcasecmp(p, "auto") == 0) |
905 _http_cmd(conn, "Referer: %s://%s%s", | 905 http_cmd(conn, "Referer: %s://%s%s", |
906 url->scheme, host, url->doc); 907 else | 906 url->scheme, host, url->doc); 907 else |
908 _http_cmd(conn, "Referer: %s", p); | 908 http_cmd(conn, "Referer: %s", p); |
909 } 910 if ((p = getenv("HTTP_USER_AGENT")) != NULL && *p != '\0') | 909 } 910 if ((p = getenv("HTTP_USER_AGENT")) != NULL && *p != '\0') |
911 _http_cmd(conn, "User-Agent: %s", p); | 911 http_cmd(conn, "User-Agent: %s", p); |
912 else | 912 else |
913 _http_cmd(conn, "User-Agent: %s " _LIBFETCH_VER, getprogname()); | 913 http_cmd(conn, "User-Agent: %s " _LIBFETCH_VER, getprogname()); |
914 if (url->offset > 0) | 914 if (url->offset > 0) |
915 _http_cmd(conn, "Range: bytes=%lld-", (long long)url->offset); 916 _http_cmd(conn, "Connection: close"); 917 _http_cmd(conn, ""); | 915 http_cmd(conn, "Range: bytes=%lld-", (long long)url->offset); 916 http_cmd(conn, "Connection: close"); 917 http_cmd(conn, ""); |
918 919 /* 920 * Force the queued request to be dispatched. Normally, one 921 * would do this with shutdown(2) but squid proxies can be 922 * configured to disallow such half-closed connections. To 923 * be compatible with such configurations, fiddle with socket 924 * options to force the pending data to be written. 925 */ 926 val = 0; 927 setsockopt(conn->sd, IPPROTO_TCP, TCP_NOPUSH, &val, 928 sizeof(val)); 929 val = 1; 930 setsockopt(conn->sd, IPPROTO_TCP, TCP_NODELAY, &val, 931 sizeof(val)); 932 933 /* get reply */ | 918 919 /* 920 * Force the queued request to be dispatched. Normally, one 921 * would do this with shutdown(2) but squid proxies can be 922 * configured to disallow such half-closed connections. To 923 * be compatible with such configurations, fiddle with socket 924 * options to force the pending data to be written. 925 */ 926 val = 0; 927 setsockopt(conn->sd, IPPROTO_TCP, TCP_NOPUSH, &val, 928 sizeof(val)); 929 val = 1; 930 setsockopt(conn->sd, IPPROTO_TCP, TCP_NODELAY, &val, 931 sizeof(val)); 932 933 /* get reply */ |
934 switch (_http_get_reply(conn)) { | 934 switch (http_get_reply(conn)) { |
935 case HTTP_OK: 936 case HTTP_PARTIAL: 937 /* fine */ 938 break; 939 case HTTP_MOVED_PERM: 940 case HTTP_MOVED_TEMP: 941 case HTTP_SEE_OTHER: 942 /* 943 * Not so fine, but we still have to read the 944 * headers to get the new location. 945 */ 946 break; 947 case HTTP_NEED_AUTH: 948 if (need_auth) { 949 /* 950 * We already sent out authorization code, 951 * so there's nothing more we can do. 952 */ | 935 case HTTP_OK: 936 case HTTP_PARTIAL: 937 /* fine */ 938 break; 939 case HTTP_MOVED_PERM: 940 case HTTP_MOVED_TEMP: 941 case HTTP_SEE_OTHER: 942 /* 943 * Not so fine, but we still have to read the 944 * headers to get the new location. 945 */ 946 break; 947 case HTTP_NEED_AUTH: 948 if (need_auth) { 949 /* 950 * We already sent out authorization code, 951 * so there's nothing more we can do. 952 */ |
953 _http_seterr(conn->err); | 953 http_seterr(conn->err); |
954 goto ouch; 955 } 956 /* try again, but send the password this time */ 957 if (verbose) | 954 goto ouch; 955 } 956 /* try again, but send the password this time */ 957 if (verbose) |
958 _fetch_info("server requires authorization"); | 958 fetch_info("server requires authorization"); |
959 break; 960 case HTTP_NEED_PROXY_AUTH: 961 /* 962 * If we're talking to a proxy, we already sent 963 * our proxy authorization code, so there's 964 * nothing more we can do. 965 */ | 959 break; 960 case HTTP_NEED_PROXY_AUTH: 961 /* 962 * If we're talking to a proxy, we already sent 963 * our proxy authorization code, so there's 964 * nothing more we can do. 965 */ |
966 _http_seterr(conn->err); | 966 http_seterr(conn->err); |
967 goto ouch; 968 case HTTP_BAD_RANGE: 969 /* 970 * This can happen if we ask for 0 bytes because 971 * we already have the whole file. Consider this 972 * a success for now, and check sizes later. 973 */ 974 break; 975 case HTTP_PROTOCOL_ERROR: 976 /* fall through */ 977 case -1: | 967 goto ouch; 968 case HTTP_BAD_RANGE: 969 /* 970 * This can happen if we ask for 0 bytes because 971 * we already have the whole file. Consider this 972 * a success for now, and check sizes later. 973 */ 974 break; 975 case HTTP_PROTOCOL_ERROR: 976 /* fall through */ 977 case -1: |
978 _fetch_syserr(); | 978 fetch_syserr(); |
979 goto ouch; 980 default: | 979 goto ouch; 980 default: |
981 _http_seterr(conn->err); | 981 http_seterr(conn->err); |
982 if (!verbose) 983 goto ouch; 984 /* fall through so we can get the full error message */ 985 } 986 987 /* get headers */ 988 do { | 982 if (!verbose) 983 goto ouch; 984 /* fall through so we can get the full error message */ 985 } 986 987 /* get headers */ 988 do { |
989 switch ((h = _http_next_header(conn, &p))) { | 989 switch ((h = http_next_header(conn, &p))) { |
990 case hdr_syserror: | 990 case hdr_syserror: |
991 _fetch_syserr(); | 991 fetch_syserr(); |
992 goto ouch; 993 case hdr_error: | 992 goto ouch; 993 case hdr_error: |
994 _http_seterr(HTTP_PROTOCOL_ERROR); | 994 http_seterr(HTTP_PROTOCOL_ERROR); |
995 goto ouch; 996 case hdr_content_length: | 995 goto ouch; 996 case hdr_content_length: |
997 _http_parse_length(p, &clength); | 997 http_parse_length(p, &clength); |
998 break; 999 case hdr_content_range: | 998 break; 999 case hdr_content_range: |
1000 _http_parse_range(p, &offset, &length, &size); | 1000 http_parse_range(p, &offset, &length, &size); |
1001 break; 1002 case hdr_last_modified: | 1001 break; 1002 case hdr_last_modified: |
1003 _http_parse_mtime(p, &mtime); | 1003 http_parse_mtime(p, &mtime); |
1004 break; 1005 case hdr_location: 1006 if (!HTTP_REDIRECT(conn->err)) 1007 break; 1008 if (new) 1009 free(new); 1010 if (verbose) | 1004 break; 1005 case hdr_location: 1006 if (!HTTP_REDIRECT(conn->err)) 1007 break; 1008 if (new) 1009 free(new); 1010 if (verbose) |
1011 _fetch_info("%d redirect to %s", conn->err, p); | 1011 fetch_info("%d redirect to %s", conn->err, p); |
1012 if (*p == '/') 1013 /* absolute path */ 1014 new = fetchMakeURL(url->scheme, url->host, url->port, p, 1015 url->user, url->pwd); 1016 else 1017 new = fetchParseURL(p); 1018 if (new == NULL) { 1019 /* XXX should set an error code */ --- 23 unchanged lines hidden (view full) --- 1043 break; 1044 } 1045 } while (h > hdr_end); 1046 1047 /* we need to provide authentication */ 1048 if (conn->err == HTTP_NEED_AUTH) { 1049 e = conn->err; 1050 need_auth = 1; | 1012 if (*p == '/') 1013 /* absolute path */ 1014 new = fetchMakeURL(url->scheme, url->host, url->port, p, 1015 url->user, url->pwd); 1016 else 1017 new = fetchParseURL(p); 1018 if (new == NULL) { 1019 /* XXX should set an error code */ --- 23 unchanged lines hidden (view full) --- 1043 break; 1044 } 1045 } while (h > hdr_end); 1046 1047 /* we need to provide authentication */ 1048 if (conn->err == HTTP_NEED_AUTH) { 1049 e = conn->err; 1050 need_auth = 1; |
1051 _fetch_close(conn); | 1051 fetch_close(conn); |
1052 conn = NULL; 1053 continue; 1054 } 1055 1056 /* requested range not satisfiable */ 1057 if (conn->err == HTTP_BAD_RANGE) { 1058 if (url->offset == size && url->length == 0) { 1059 /* asked for 0 bytes; fake it */ 1060 offset = url->offset; 1061 conn->err = HTTP_OK; 1062 break; 1063 } else { | 1052 conn = NULL; 1053 continue; 1054 } 1055 1056 /* requested range not satisfiable */ 1057 if (conn->err == HTTP_BAD_RANGE) { 1058 if (url->offset == size && url->length == 0) { 1059 /* asked for 0 bytes; fake it */ 1060 offset = url->offset; 1061 conn->err = HTTP_OK; 1062 break; 1063 } else { |
1064 _http_seterr(conn->err); | 1064 http_seterr(conn->err); |
1065 goto ouch; 1066 } 1067 } 1068 1069 /* we have a hit or an error */ 1070 if (conn->err == HTTP_OK || conn->err == HTTP_PARTIAL || HTTP_ERROR(conn->err)) 1071 break; 1072 1073 /* all other cases: we got a redirect */ 1074 e = conn->err; 1075 need_auth = 0; | 1065 goto ouch; 1066 } 1067 } 1068 1069 /* we have a hit or an error */ 1070 if (conn->err == HTTP_OK || conn->err == HTTP_PARTIAL || HTTP_ERROR(conn->err)) 1071 break; 1072 1073 /* all other cases: we got a redirect */ 1074 e = conn->err; 1075 need_auth = 0; |
1076 _fetch_close(conn); | 1076 fetch_close(conn); |
1077 conn = NULL; 1078 if (!new) { 1079 DEBUG(fprintf(stderr, "redirect with no new location\n")); 1080 break; 1081 } 1082 if (url != URL) 1083 fetchFreeURL(url); 1084 url = new; 1085 } while (++i < n); 1086 1087 /* we failed, or ran out of retries */ 1088 if (conn == NULL) { | 1077 conn = NULL; 1078 if (!new) { 1079 DEBUG(fprintf(stderr, "redirect with no new location\n")); 1080 break; 1081 } 1082 if (url != URL) 1083 fetchFreeURL(url); 1084 url = new; 1085 } while (++i < n); 1086 1087 /* we failed, or ran out of retries */ 1088 if (conn == NULL) { |
1089 _http_seterr(e); | 1089 http_seterr(e); |
1090 goto ouch; 1091 } 1092 1093 DEBUG(fprintf(stderr, "offset %lld, length %lld," 1094 " size %lld, clength %lld\n", 1095 (long long)offset, (long long)length, 1096 (long long)size, (long long)clength)); 1097 1098 /* check for inconsistencies */ 1099 if (clength != -1 && length != -1 && clength != length) { | 1090 goto ouch; 1091 } 1092 1093 DEBUG(fprintf(stderr, "offset %lld, length %lld," 1094 " size %lld, clength %lld\n", 1095 (long long)offset, (long long)length, 1096 (long long)size, (long long)clength)); 1097 1098 /* check for inconsistencies */ 1099 if (clength != -1 && length != -1 && clength != length) { |
1100 _http_seterr(HTTP_PROTOCOL_ERROR); | 1100 http_seterr(HTTP_PROTOCOL_ERROR); |
1101 goto ouch; 1102 } 1103 if (clength == -1) 1104 clength = length; 1105 if (clength != -1) 1106 length = offset + clength; 1107 if (length != -1 && size != -1 && length != size) { | 1101 goto ouch; 1102 } 1103 if (clength == -1) 1104 clength = length; 1105 if (clength != -1) 1106 length = offset + clength; 1107 if (length != -1 && size != -1 && length != size) { |
1108 _http_seterr(HTTP_PROTOCOL_ERROR); | 1108 http_seterr(HTTP_PROTOCOL_ERROR); |
1109 goto ouch; 1110 } 1111 if (size == -1) 1112 size = length; 1113 1114 /* fill in stats */ 1115 if (us) { 1116 us->size = size; 1117 us->atime = us->mtime = mtime; 1118 } 1119 1120 /* too far? */ 1121 if (URL->offset > 0 && offset > URL->offset) { | 1109 goto ouch; 1110 } 1111 if (size == -1) 1112 size = length; 1113 1114 /* fill in stats */ 1115 if (us) { 1116 us->size = size; 1117 us->atime = us->mtime = mtime; 1118 } 1119 1120 /* too far? */ 1121 if (URL->offset > 0 && offset > URL->offset) { |
1122 _http_seterr(HTTP_PROTOCOL_ERROR); | 1122 http_seterr(HTTP_PROTOCOL_ERROR); |
1123 goto ouch; 1124 } 1125 1126 /* report back real offset and size */ 1127 URL->offset = offset; 1128 URL->length = clength; 1129 1130 /* wrap it up in a FILE */ | 1123 goto ouch; 1124 } 1125 1126 /* report back real offset and size */ 1127 URL->offset = offset; 1128 URL->length = clength; 1129 1130 /* wrap it up in a FILE */ |
1131 if ((f = _http_funopen(conn, chunked)) == NULL) { 1132 _fetch_syserr(); | 1131 if ((f = http_funopen(conn, chunked)) == NULL) { 1132 fetch_syserr(); |
1133 goto ouch; 1134 } 1135 1136 if (url != URL) 1137 fetchFreeURL(url); 1138 if (purl) 1139 fetchFreeURL(purl); 1140 1141 if (HTTP_ERROR(conn->err)) { | 1133 goto ouch; 1134 } 1135 1136 if (url != URL) 1137 fetchFreeURL(url); 1138 if (purl) 1139 fetchFreeURL(purl); 1140 1141 if (HTTP_ERROR(conn->err)) { |
1142 _http_print_html(stderr, f); | 1142 http_print_html(stderr, f); |
1143 fclose(f); 1144 f = NULL; 1145 } 1146 1147 return (f); 1148 1149ouch: 1150 if (url != URL) 1151 fetchFreeURL(url); 1152 if (purl) 1153 fetchFreeURL(purl); 1154 if (conn != NULL) | 1143 fclose(f); 1144 f = NULL; 1145 } 1146 1147 return (f); 1148 1149ouch: 1150 if (url != URL) 1151 fetchFreeURL(url); 1152 if (purl) 1153 fetchFreeURL(purl); 1154 if (conn != NULL) |
1155 _fetch_close(conn); | 1155 fetch_close(conn); |
1156 return (NULL); 1157} 1158 1159 1160/***************************************************************************** 1161 * Entry points 1162 */ 1163 1164/* 1165 * Retrieve and stat a file by HTTP 1166 */ 1167FILE * 1168fetchXGetHTTP(struct url *URL, struct url_stat *us, const char *flags) 1169{ | 1156 return (NULL); 1157} 1158 1159 1160/***************************************************************************** 1161 * Entry points 1162 */ 1163 1164/* 1165 * Retrieve and stat a file by HTTP 1166 */ 1167FILE * 1168fetchXGetHTTP(struct url *URL, struct url_stat *us, const char *flags) 1169{ |
1170 return (_http_request(URL, "GET", us, _http_get_proxy(flags), flags)); | 1170 return (http_request(URL, "GET", us, http_get_proxy(flags), flags)); |
1171} 1172 1173/* 1174 * Retrieve a file by HTTP 1175 */ 1176FILE * 1177fetchGetHTTP(struct url *URL, const char *flags) 1178{ --- 13 unchanged lines hidden (view full) --- 1192/* 1193 * Get an HTTP document's metadata 1194 */ 1195int 1196fetchStatHTTP(struct url *URL, struct url_stat *us, const char *flags) 1197{ 1198 FILE *f; 1199 | 1171} 1172 1173/* 1174 * Retrieve a file by HTTP 1175 */ 1176FILE * 1177fetchGetHTTP(struct url *URL, const char *flags) 1178{ --- 13 unchanged lines hidden (view full) --- 1192/* 1193 * Get an HTTP document's metadata 1194 */ 1195int 1196fetchStatHTTP(struct url *URL, struct url_stat *us, const char *flags) 1197{ 1198 FILE *f; 1199 |
1200 f = _http_request(URL, "HEAD", us, _http_get_proxy(flags), flags); | 1200 f = http_request(URL, "HEAD", us, http_get_proxy(flags), flags); |
1201 if (f == NULL) 1202 return (-1); 1203 fclose(f); 1204 return (0); 1205} 1206 1207/* 1208 * List a directory 1209 */ 1210struct url_ent * 1211fetchListHTTP(struct url *url __unused, const char *flags __unused) 1212{ 1213 warnx("fetchListHTTP(): not implemented"); 1214 return (NULL); 1215} | 1201 if (f == NULL) 1202 return (-1); 1203 fclose(f); 1204 return (0); 1205} 1206 1207/* 1208 * List a directory 1209 */ 1210struct url_ent * 1211fetchListHTTP(struct url *url __unused, const char *flags __unused) 1212{ 1213 warnx("fetchListHTTP(): not implemented"); 1214 return (NULL); 1215} |