http.c
author Sunil Nimmagadda <sunil@nimmagadda.net>
Tue, 06 Dec 2022 13:51:55 +0000
changeset 0 1d0ce1ebbc72
permissions -rw-r--r--
An HTTP(S), FTP client. Found a copy of some old OpenBSD days hacking stashed somewhere in the backups. This version saw the light of the day as official OpenBSD ftp(1) for a grand total of 1 day :-)
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
0
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
     1
/*
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
     2
 * Copyright (c) 2015 Sunil Nimmagadda <sunil@openbsd.org>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
     3
 * Copyright (c) 2012 - 2015 Reyk Floeter <reyk@openbsd.org>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
     4
 *
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
     5
 * Permission to use, copy, modify, and distribute this software for any
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
     6
 * purpose with or without fee is hereby granted, provided that the above
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
     7
 * copyright notice and this permission notice appear in all copies.
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
     8
 *
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
     9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    16
 */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    17
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    18
#include <err.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    19
#include <fcntl.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    20
#include <libgen.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    21
#include <limits.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    22
#include <stdio.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    23
#include <stdint.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    24
#include <stdlib.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    25
#include <string.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    26
#include <strings.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    27
#include <unistd.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    28
#ifndef NOSSL
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    29
#include <tls.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    30
#endif /* NOSSL */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    31
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    32
#include "ftp.h"
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    33
#include "xmalloc.h"
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    34
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    35
#define MAX_REDIRECTS		10
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    36
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    37
#ifndef NOSSL
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    38
#define MINBUF			128
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    39
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    40
static struct tls_config	*tls_config;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    41
static struct tls		*ctx;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    42
static int			 tls_session_fd = -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    43
static char * const		 tls_verify_opts[] = {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    44
#define HTTP_TLS_CAFILE		0
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    45
	"cafile",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    46
#define HTTP_TLS_CAPATH		1
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    47
	"capath",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    48
#define HTTP_TLS_CIPHERS	2
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    49
	"ciphers",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    50
#define HTTP_TLS_DONTVERIFY	3
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    51
	"dont",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    52
#define HTTP_TLS_VERIFYDEPTH	4
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    53
	"depth",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    54
#define HTTP_TLS_MUSTSTAPLE	5
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    55
	"muststaple",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    56
#define HTTP_TLS_NOVERIFYTIME	6
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    57
	"noverifytime",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    58
#define HTTP_TLS_SESSION	7
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    59
	"session",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    60
#define HTTP_TLS_DOVERIFY	8
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    61
	"do",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    62
	NULL
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    63
};
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    64
#endif /* NOSSL */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    65
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    66
/*
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    67
 * HTTP status codes based on IANA assignments (2014-06-11 version):
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    68
 * https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    69
 * plus legacy (306) and non-standard (420).
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    70
 */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    71
static struct http_status {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    72
	int		 code;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    73
	const char	*name;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    74
} http_status[] = {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    75
	{ 100,	"Continue" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    76
	{ 101,	"Switching Protocols" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    77
	{ 102,	"Processing" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    78
	/* 103-199 unassigned */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    79
	{ 200,	"OK" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    80
	{ 201,	"Created" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    81
	{ 202,	"Accepted" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    82
	{ 203,	"Non-Authoritative Information" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    83
	{ 204,	"No Content" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    84
	{ 205,	"Reset Content" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    85
	{ 206,	"Partial Content" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    86
	{ 207,	"Multi-Status" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    87
	{ 208,	"Already Reported" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    88
	/* 209-225 unassigned */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    89
	{ 226,	"IM Used" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    90
	/* 227-299 unassigned */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    91
	{ 300,	"Multiple Choices" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    92
	{ 301,	"Moved Permanently" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    93
	{ 302,	"Found" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    94
	{ 303,	"See Other" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    95
	{ 304,	"Not Modified" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    96
	{ 305,	"Use Proxy" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    97
	{ 306,	"Switch Proxy" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    98
	{ 307,	"Temporary Redirect" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    99
	{ 308,	"Permanent Redirect" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   100
	/* 309-399 unassigned */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   101
	{ 400,	"Bad Request" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   102
	{ 401,	"Unauthorized" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   103
	{ 402,	"Payment Required" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   104
	{ 403,	"Forbidden" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   105
	{ 404,	"Not Found" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   106
	{ 405,	"Method Not Allowed" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   107
	{ 406,	"Not Acceptable" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   108
	{ 407,	"Proxy Authentication Required" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   109
	{ 408,	"Request Timeout" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   110
	{ 409,	"Conflict" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   111
	{ 410,	"Gone" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   112
	{ 411,	"Length Required" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   113
	{ 412,	"Precondition Failed" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   114
	{ 413,	"Payload Too Large" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   115
	{ 414,	"URI Too Long" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   116
	{ 415,	"Unsupported Media Type" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   117
	{ 416,	"Range Not Satisfiable" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   118
	{ 417,	"Expectation Failed" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   119
	{ 418,	"I'm a teapot" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   120
	/* 419-421 unassigned */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   121
	{ 420,	"Enhance Your Calm" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   122
	{ 422,	"Unprocessable Entity" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   123
	{ 423,	"Locked" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   124
	{ 424,	"Failed Dependency" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   125
	/* 425 unassigned */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   126
	{ 426,	"Upgrade Required" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   127
	/* 427 unassigned */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   128
	{ 428,	"Precondition Required" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   129
	{ 429,	"Too Many Requests" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   130
	/* 430 unassigned */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   131
	{ 431,	"Request Header Fields Too Large" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   132
	/* 432-450 unassigned */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   133
	{ 451,	"Unavailable For Legal Reasons" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   134
	/* 452-499 unassigned */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   135
	{ 500,	"Internal Server Error" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   136
	{ 501,	"Not Implemented" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   137
	{ 502,	"Bad Gateway" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   138
	{ 503,	"Service Unavailable" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   139
	{ 504,	"Gateway Timeout" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   140
	{ 505,	"HTTP Version Not Supported" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   141
	{ 506,	"Variant Also Negotiates" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   142
	{ 507,	"Insufficient Storage" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   143
	{ 508,	"Loop Detected" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   144
	/* 509 unassigned */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   145
	{ 510,	"Not Extended" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   146
	{ 511,	"Network Authentication Required" },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   147
	/* 512-599 unassigned */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   148
	{ 0,	NULL },
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   149
};
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   150
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   151
struct http_headers {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   152
	char	*location;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   153
	off_t	 content_length;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   154
	int	 chunked;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   155
	int	 retry_after;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   156
};
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   157
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   158
static void		 decode_chunk(int, uint, FILE *);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   159
static char		*header_lookup(const char *, const char *);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   160
static const char	*http_error(int);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   161
static int		 http_status_cmp(const void *, const void *);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   162
static void		 http_headers_free(struct http_headers *);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   163
static ssize_t		 http_getline(int, char **, size_t *);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   164
static void		 http_proxy_connect(struct url *, struct url *);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   165
static char		*http_prepare_request(struct url *, off_t *);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   166
static size_t		 http_read(int, char *, size_t);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   167
static struct url	*http_redirect(struct url *, char *);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   168
static void		 http_copy_chunks(struct url *, FILE *, off_t *);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   169
static int		 http_request(int, const char *,
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   170
			    struct http_headers **);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   171
static char		*relative_path_resolve(const char *, const char *);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   172
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   173
#ifndef NOSSL
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   174
static void		 tls_copy_file(struct url *, FILE *, off_t *);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   175
static ssize_t		 tls_getline(char **, size_t *, struct tls *);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   176
#endif /* NOSSL */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   177
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   178
static FILE		*fp;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   179
static int		 chunked;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   180
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   181
void
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   182
http_connect(struct url *url, int timeout)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   183
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   184
	static struct url	*proxy;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   185
	const char		*host, *port;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   186
	int			 sock;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   187
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   188
	proxy = (url->scheme == S_HTTPS || url->scheme == S_HTTP) ?
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   189
	    http_proxy : ftp_proxy;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   190
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   191
	host = proxy ? proxy->host : url->host;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   192
	port = proxy ? proxy->port : url->port;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   193
	if ((sock = tcp_connect(host, port, timeout)) == -1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   194
		exit(1);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   195
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   196
	if ((fp = fdopen(sock, "r+")) == NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   197
		err(1, "%s: fdopen", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   198
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   199
	if (proxy)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   200
		http_proxy_connect(proxy, url);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   201
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   202
#ifndef NOSSL
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   203
	if (url->scheme != S_HTTPS)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   204
		return;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   205
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   206
	if ((ctx = tls_client()) == NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   207
		errx(1, "failed to create tls client");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   208
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   209
	if (tls_configure(ctx, tls_config) != 0)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   210
		errx(1, "%s: %s", __func__, tls_error(ctx));
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   211
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   212
	if (tls_connect_socket(ctx, fileno(fp), url->host) != 0)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   213
		errx(1, "%s: %s", __func__, tls_error(ctx));
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   214
#endif /* NOSSL */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   215
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   216
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   217
static void
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   218
http_proxy_connect(struct url *proxy, struct url *url)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   219
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   220
	struct http_headers	*headers;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   221
	char			*auth = NULL, *req;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   222
	int			 authlen = 0, code;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   223
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   224
	if (proxy->basic_auth) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   225
		authlen = xasprintf(&auth,
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   226
		    "Proxy-Authorization: Basic %s\r\n", proxy->basic_auth);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   227
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   228
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   229
	xasprintf(&req,
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   230
	    "CONNECT %s:%s HTTP/1.0\r\n"
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   231
	    "User-Agent: %s\r\n"
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   232
	    "%s"
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   233
	    "\r\n",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   234
	    url->host, url->port,
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   235
	    useragent,
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   236
	    proxy->basic_auth ? auth : "");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   237
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   238
	freezero(auth, authlen);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   239
	if ((code = http_request(S_HTTP, req, &headers)) != 200)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   240
		errx(1, "%s: Failed to CONNECT to %s:%s: %d %s",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   241
			__func__, url->host, url->port, code, http_error(code));
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   242
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   243
	free(req);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   244
	http_headers_free(headers);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   245
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   246
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   247
static char *
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   248
http_prepare_request(struct url *url, off_t *offset)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   249
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   250
	char	*auth = NULL, *path = NULL, *range = NULL, *req;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   251
	int	 authlen = 0;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   252
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   253
	if (*offset)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   254
		xasprintf(&range, "Range: bytes=%lld-\r\n", *offset);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   255
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   256
	if (url->basic_auth) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   257
		authlen = xasprintf(&auth,
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   258
		    "Authorization: Basic %s\r\n", url->basic_auth);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   259
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   260
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   261
	if (url->path)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   262
		path = url_encode(url->path);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   263
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   264
	xasprintf(&req,
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   265
	    "GET %s HTTP/1.1\r\n"
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   266
	    "Host: %s\r\n"
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   267
	    "%s"
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   268
	    "%s"
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   269
	    "Connection: close\r\n"
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   270
	    "User-Agent: %s\r\n"
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   271
	    "\r\n",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   272
	    path ? path : "/",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   273
	    url->host,
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   274
	    *offset ? range : "",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   275
	    url->basic_auth ? auth : "",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   276
	    useragent);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   277
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   278
	free(range);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   279
	freezero(auth, authlen);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   280
	free(path);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   281
	return req;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   282
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   283
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   284
struct url *
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   285
http_get(struct url *url, off_t *offset, off_t *sz)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   286
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   287
	struct http_headers	*headers;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   288
	char			*req;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   289
	int			 code, redirects = 0, retry = 0;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   290
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   291
	do {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   292
		log_request("Requesting", url, http_proxy);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   293
		req = http_prepare_request(url, offset);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   294
		code = http_request(url->scheme, req, &headers);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   295
		free(req);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   296
		switch (code) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   297
		case 200:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   298
			if (*offset) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   299
				warnx("Server does not support resume.");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   300
				*offset = 0;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   301
			}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   302
			break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   303
		case 206:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   304
			break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   305
		case 301:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   306
		case 302:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   307
		case 303:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   308
		case 307:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   309
			http_close(url);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   310
			if (++redirects > MAX_REDIRECTS)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   311
				errx(1, "Too many redirections requested.");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   312
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   313
			if (headers->location == NULL) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   314
				errx(1,
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   315
				    "%s: Location header missing", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   316
			}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   317
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   318
			url = http_redirect(url, headers->location);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   319
			http_headers_free(headers);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   320
			log_request("Redirected to", url, http_proxy);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   321
			http_connect(url, 0);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   322
			break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   323
		case 416:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   324
			errx(1, "File is already fully retrieved.");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   325
			break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   326
		case 503:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   327
			if (headers->retry_after == 0 && retry == 0) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   328
				http_close(url);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   329
				http_headers_free(headers);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   330
				retry = 1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   331
				log_request("Retrying", url, http_proxy);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   332
				http_connect(url, 0);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   333
				break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   334
			}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   335
			/* FALLTHROUGH */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   336
		default:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   337
			errx(1, "Error retrieving file: %d %s",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   338
			    code, http_error(code));
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   339
		}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   340
	} while (code == 301 || code == 302 ||
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   341
	    code == 303 || code == 307 || code == 503);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   342
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   343
	*sz = headers->content_length + *offset;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   344
	chunked = headers->chunked;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   345
	http_headers_free(headers);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   346
	return url;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   347
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   348
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   349
void
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   350
http_save(struct url *url, FILE *dst_fp, off_t *offset)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   351
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   352
	if (chunked)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   353
		http_copy_chunks(url, dst_fp, offset);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   354
#ifndef NOSSL
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   355
	else if (url->scheme == S_HTTPS)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   356
		tls_copy_file(url, dst_fp, offset);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   357
#endif /* NOSSL */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   358
	else
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   359
		copy_file(dst_fp, fp, offset);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   360
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   361
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   362
static struct url *
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   363
http_redirect(struct url *old_url, char *location)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   364
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   365
	struct url	*new_url;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   366
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   367
	/* absolute uri reference */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   368
	if (strncasecmp(location, "http", 4) == 0 ||
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   369
	    strncasecmp(location, "https", 5) == 0) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   370
		new_url = xurl_parse(location);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   371
		goto done;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   372
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   373
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   374
	/* relative uri reference */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   375
	new_url = xcalloc(1, sizeof *new_url);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   376
	new_url->scheme = old_url->scheme;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   377
	new_url->host = xstrdup(old_url->host);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   378
	new_url->port = xstrdup(old_url->port);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   379
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   380
	/* absolute-path reference */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   381
	if (location[0] == '/')
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   382
		new_url->path = xstrdup(location);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   383
	else
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   384
		new_url->path = relative_path_resolve(old_url->path, location);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   385
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   386
 done:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   387
	url_free(old_url);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   388
	return new_url;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   389
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   390
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   391
static char *
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   392
relative_path_resolve(const char *base_path, const char *location)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   393
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   394
	char	*new_path, *p;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   395
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   396
	/* trim fragment component from both uri */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   397
	if ((p = strchr(location, '#')) != NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   398
		*p = '\0';
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   399
	if (base_path && (p = strchr(base_path, '#')) != NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   400
		*p = '\0';
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   401
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   402
	if (base_path == NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   403
		xasprintf(&new_path, "/%s", location);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   404
	else if (base_path[strlen(base_path) - 1] == '/')
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   405
		xasprintf(&new_path, "%s%s", base_path, location);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   406
	else {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   407
		p = dirname(base_path);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   408
		xasprintf(&new_path, "%s/%s",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   409
		    strcmp(p, ".") == 0 ? "" : p, location);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   410
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   411
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   412
	return new_path;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   413
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   414
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   415
static void
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   416
http_copy_chunks(struct url *url, FILE *dst_fp, off_t *offset)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   417
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   418
	char	*buf = NULL;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   419
	size_t	 n = 0;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   420
	uint	 chunk_sz;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   421
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   422
	http_getline(url->scheme, &buf, &n);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   423
	if (sscanf(buf, "%x", &chunk_sz) != 1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   424
		errx(1, "%s: Failed to get chunk size", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   425
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   426
	while (chunk_sz > 0) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   427
		decode_chunk(url->scheme, chunk_sz, dst_fp);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   428
		*offset += chunk_sz;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   429
		http_getline(url->scheme, &buf, &n);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   430
		if (sscanf(buf, "%x", &chunk_sz) != 1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   431
			errx(1, "%s: Failed to get chunk size", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   432
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   433
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   434
	free(buf);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   435
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   436
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   437
static void
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   438
decode_chunk(int scheme, uint sz, FILE *dst_fp)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   439
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   440
	size_t	bufsz;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   441
	size_t	r;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   442
	char	buf[BUFSIZ], crlf[2];
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   443
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   444
	bufsz = sizeof(buf);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   445
	while (sz > 0) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   446
		if (sz < bufsz)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   447
			bufsz = sz;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   448
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   449
		r = http_read(scheme, buf, bufsz);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   450
		if (fwrite(buf, 1, r, dst_fp) != r)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   451
			errx(1, "%s: fwrite", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   452
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   453
		sz -= r;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   454
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   455
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   456
	/* CRLF terminating the chunk */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   457
	if (http_read(scheme, crlf, sizeof(crlf)) != sizeof(crlf))
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   458
		errx(1, "%s: Failed to read terminal crlf", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   459
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   460
	if (crlf[0] != '\r' || crlf[1] != '\n')
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   461
		errx(1, "%s: Invalid chunked encoding", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   462
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   463
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   464
void
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   465
http_close(struct url *url)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   466
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   467
#ifndef NOSSL
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   468
	ssize_t	r;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   469
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   470
	if (url->scheme == S_HTTPS) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   471
		if (tls_session_fd != -1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   472
			dprintf(STDERR_FILENO, "tls session resumed: %s\n",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   473
			    tls_conn_session_resumed(ctx) ? "yes" : "no");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   474
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   475
		do {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   476
			r = tls_close(ctx);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   477
		} while (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   478
		tls_free(ctx);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   479
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   480
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   481
#endif /* NOSSL */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   482
	fclose(fp);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   483
	chunked = 0;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   484
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   485
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   486
static int
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   487
http_request(int scheme, const char *req, struct http_headers **hdrs)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   488
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   489
	struct http_headers	*headers;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   490
	const char		*e;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   491
	char			*buf = NULL, *p;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   492
	size_t			 n = 0;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   493
	ssize_t			 buflen;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   494
	uint			 code;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   495
#ifndef NOSSL
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   496
	size_t			 len;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   497
	ssize_t			 nw;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   498
#endif /* NOSSL */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   499
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   500
	if (io_debug)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   501
		fprintf(stderr, "<<< %s", req);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   502
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   503
	switch (scheme) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   504
#ifndef NOSSL
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   505
	case S_HTTPS:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   506
		len = strlen(req);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   507
		while (len > 0) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   508
			nw = tls_write(ctx, req, len);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   509
			if (nw == TLS_WANT_POLLIN || nw == TLS_WANT_POLLOUT)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   510
				continue;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   511
			if (nw < 0)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   512
				errx(1, "tls_write: %s", tls_error(ctx));
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   513
			req += nw;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   514
			len -= nw;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   515
		}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   516
		break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   517
#endif /* NOSSL */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   518
	case S_HTTP:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   519
		if (fprintf(fp, "%s", req) < 0)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   520
			errx(1, "%s: fprintf", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   521
		(void)fflush(fp);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   522
		break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   523
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   524
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   525
	http_getline(scheme, &buf, &n);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   526
	if (io_debug)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   527
		fprintf(stderr, ">>> %s", buf);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   528
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   529
	if (sscanf(buf, "%*s %u %*s", &code) != 1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   530
		errx(1, "%s: failed to extract status code", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   531
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   532
	if (code < 100 || code > 511)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   533
		errx(1, "%s: invalid status code %d", __func__, code);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   534
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   535
	headers = xcalloc(1, sizeof *headers);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   536
	headers->retry_after = -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   537
	for (;;) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   538
		buflen = http_getline(scheme, &buf, &n);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   539
		buflen -= 1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   540
		if (buflen > 0 && buf[buflen - 1] == '\r')
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   541
			buflen -= 1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   542
		buf[buflen] = '\0';
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   543
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   544
		if (io_debug)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   545
			fprintf(stderr, ">>> %s\n", buf);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   546
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   547
		if (buflen == 0)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   548
			break; /* end of headers */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   549
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   550
		if ((p = header_lookup(buf, "Content-Length:")) != NULL) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   551
			headers->content_length = strtonum(p, 0, INT64_MAX, &e);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   552
			if (e)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   553
				err(1, "%s: Content-Length is %s: %lld",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   554
				    __func__, e, headers->content_length);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   555
		}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   556
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   557
		if ((p = header_lookup(buf, "Location:")) != NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   558
			headers->location = xstrdup(p);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   559
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   560
		if ((p = header_lookup(buf, "Transfer-Encoding:")) != NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   561
			if (strcasestr(p, "chunked") != NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   562
				headers->chunked = 1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   563
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   564
		if ((p = header_lookup(buf, "Retry-After:")) != NULL) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   565
			headers->retry_after = strtonum(p, 0, 0, &e);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   566
			if (e)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   567
				headers->retry_after = -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   568
		}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   569
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   570
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   571
	*hdrs = headers;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   572
	free(buf);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   573
	return code;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   574
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   575
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   576
static void
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   577
http_headers_free(struct http_headers *headers)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   578
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   579
	if (headers == NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   580
		return;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   581
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   582
	free(headers->location);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   583
	free(headers);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   584
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   585
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   586
static char *
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   587
header_lookup(const char *buf, const char *key)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   588
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   589
	char	*p;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   590
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   591
	if (strncasecmp(buf, key, strlen(key)) == 0) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   592
		if ((p = strchr(buf, ' ')) == NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   593
			errx(1, "Failed to parse %s", key);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   594
		return ++p;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   595
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   596
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   597
	return NULL;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   598
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   599
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   600
static ssize_t
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   601
http_getline(int scheme, char **buf, size_t *n)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   602
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   603
	ssize_t	buflen;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   604
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   605
	switch (scheme) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   606
#ifndef NOSSL
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   607
	case S_HTTPS:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   608
		if ((buflen = tls_getline(buf, n, ctx)) == -1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   609
			errx(1, "%s: tls_getline", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   610
		break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   611
#endif /* NOSSL */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   612
	case S_HTTP:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   613
		if ((buflen = getline(buf, n, fp)) == -1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   614
			err(1, "%s: getline", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   615
		break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   616
	default:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   617
		errx(1, "%s: invalid scheme", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   618
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   619
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   620
	return buflen;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   621
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   622
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   623
static size_t
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   624
http_read(int scheme, char *buf, size_t size)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   625
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   626
	size_t	r;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   627
#ifndef NOSSL
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   628
	ssize_t	rs;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   629
#endif /* NOSSL */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   630
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   631
	switch (scheme) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   632
#ifndef NOSSL
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   633
	case S_HTTPS:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   634
		do {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   635
			rs = tls_read(ctx, buf, size);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   636
		} while (rs == TLS_WANT_POLLIN || rs == TLS_WANT_POLLOUT);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   637
		if (rs == -1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   638
			errx(1, "%s: tls_read: %s", __func__, tls_error(ctx));
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   639
		r = rs;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   640
		break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   641
#endif /* NOSSL */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   642
	case S_HTTP:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   643
		if ((r = fread(buf, 1, size, fp)) < size)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   644
			if (!feof(fp))
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   645
				errx(1, "%s: fread", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   646
		break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   647
	default:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   648
		errx(1, "%s: invalid scheme", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   649
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   650
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   651
	return r;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   652
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   653
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   654
static const char *
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   655
http_error(int code)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   656
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   657
	struct http_status	error, *res;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   658
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   659
	/* Set up key */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   660
	error.code = code;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   661
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   662
	if ((res = bsearch(&error, http_status,
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   663
	    sizeof(http_status) / sizeof(http_status[0]) - 1,
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   664
	    sizeof(http_status[0]), http_status_cmp)) != NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   665
		return (res->name);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   666
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   667
	return (NULL);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   668
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   669
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   670
static int
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   671
http_status_cmp(const void *a, const void *b)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   672
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   673
	const struct http_status *ea = a;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   674
	const struct http_status *eb = b;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   675
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   676
	return (ea->code - eb->code);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   677
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   678
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   679
#ifndef NOSSL
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   680
void
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   681
https_init(char *tls_options)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   682
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   683
	char		*str;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   684
	int		 depth;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   685
	const char	*ca_file, *errstr;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   686
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   687
	if (tls_init() != 0)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   688
		errx(1, "tls_init failed");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   689
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   690
	if ((tls_config = tls_config_new()) == NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   691
		errx(1, "tls_config_new failed");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   692
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   693
	if (tls_config_set_protocols(tls_config, TLS_PROTOCOLS_ALL) != 0)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   694
		errx(1, "tls set protocols failed: %s",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   695
		    tls_config_error(tls_config));
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   696
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   697
	if (tls_config_set_ciphers(tls_config, "legacy") != 0)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   698
		errx(1, "tls set ciphers failed: %s",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   699
		    tls_config_error(tls_config));
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   700
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   701
	ca_file = tls_default_ca_cert_file();
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   702
	while (tls_options && *tls_options) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   703
		switch (getsubopt(&tls_options, tls_verify_opts, &str)) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   704
		case HTTP_TLS_CAFILE:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   705
			if (str == NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   706
				errx(1, "missing CA file");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   707
			ca_file = str;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   708
			break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   709
		case HTTP_TLS_CAPATH:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   710
			if (str == NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   711
				errx(1, "missing ca path");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   712
			if (tls_config_set_ca_path(tls_config, str) != 0)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   713
				errx(1, "tls ca path failed");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   714
			break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   715
		case HTTP_TLS_CIPHERS:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   716
			if (str == NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   717
				errx(1, "missing cipher list");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   718
			if (tls_config_set_ciphers(tls_config, str) != 0)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   719
				errx(1, "tls set ciphers failed");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   720
			break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   721
		case HTTP_TLS_DONTVERIFY:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   722
			tls_config_insecure_noverifycert(tls_config);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   723
			tls_config_insecure_noverifyname(tls_config);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   724
			break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   725
		case HTTP_TLS_VERIFYDEPTH:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   726
			if (str == NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   727
				errx(1, "missing depth");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   728
			depth = strtonum(str, 0, INT_MAX, &errstr);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   729
			if (errstr)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   730
				errx(1, "Cert validation depth is %s", errstr);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   731
			tls_config_set_verify_depth(tls_config, depth);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   732
			break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   733
		case HTTP_TLS_MUSTSTAPLE:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   734
			tls_config_ocsp_require_stapling(tls_config);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   735
			break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   736
		case HTTP_TLS_NOVERIFYTIME:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   737
			tls_config_insecure_noverifytime(tls_config);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   738
			break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   739
		case HTTP_TLS_SESSION:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   740
			if (str == NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   741
				errx(1, "missing session file");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   742
			tls_session_fd = open(str, O_RDWR|O_CREAT, 0600);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   743
			if (tls_session_fd == -1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   744
				err(1, "failed to open or create session file "
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   745
				    "'%s'", str);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   746
			if (tls_config_set_session_fd(tls_config,
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   747
			    tls_session_fd) == -1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   748
				errx(1, "failed to set session: %s",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   749
				    tls_config_error(tls_config));
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   750
			break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   751
		case HTTP_TLS_DOVERIFY:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   752
			/* For compatibility, we do verify by default */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   753
			break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   754
		default:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   755
			errx(1, "Unknown -S suboption `%s'",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   756
			    suboptarg ? suboptarg : "");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   757
		}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   758
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   759
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   760
	if (tls_config_set_ca_file(tls_config, ca_file) == -1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   761
		errx(1, "tls_config_set_ca_file failed");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   762
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   763
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   764
static ssize_t
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   765
tls_getline(char **buf, size_t *buflen, struct tls *tls)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   766
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   767
	char		*newb;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   768
	size_t		 newlen, off;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   769
	int		 ret;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   770
	unsigned char	 c;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   771
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   772
	if (buf == NULL || buflen == NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   773
		return -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   774
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   775
	/* If buf is NULL, we have to assume a size of zero */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   776
	if (*buf == NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   777
		*buflen = 0;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   778
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   779
	off = 0;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   780
	do {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   781
		do {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   782
			ret = tls_read(tls, &c, 1);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   783
		} while (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   784
		if (ret == -1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   785
			return -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   786
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   787
		/* Ensure we can handle it */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   788
		if (off + 2 > SSIZE_MAX)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   789
			return -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   790
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   791
		newlen = off + 2; /* reserve space for NUL terminator */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   792
		if (newlen > *buflen) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   793
			newlen = newlen < MINBUF ? MINBUF : *buflen * 2;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   794
			newb = recallocarray(*buf, *buflen, newlen, 1);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   795
			if (newb == NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   796
				return -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   797
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   798
			*buf = newb;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   799
			*buflen = newlen;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   800
		}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   801
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   802
		*(*buf + off) = c;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   803
		off += 1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   804
	} while (c != '\n');
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   805
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   806
	*(*buf + off) = '\0';
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   807
	return off;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   808
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   809
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   810
static void
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   811
tls_copy_file(struct url *url, FILE *dst_fp, off_t *offset)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   812
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   813
	char	*tmp_buf;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   814
	ssize_t	 r;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   815
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   816
	tmp_buf = xmalloc(TMPBUF_LEN);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   817
	for (;;) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   818
		do {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   819
			r = tls_read(ctx, tmp_buf, TMPBUF_LEN);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   820
		} while (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   821
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   822
		if (r == -1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   823
			errx(1, "%s: tls_read: %s", __func__, tls_error(ctx));
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   824
		else if (r == 0)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   825
			break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   826
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   827
		*offset += r;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   828
		if (fwrite(tmp_buf, 1, r, dst_fp) != (size_t)r)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   829
			err(1, "%s: fwrite", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   830
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   831
	free(tmp_buf);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   832
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   833
#endif /* NOSSL */