3030 */
3131
3232#include <sys/param.h>
33+ #include <sys/queue.h>
3334#include <sys/socket.h>
3435#include <sys/stat.h>
3536#include <sys/time.h>
3940#include <errno.h>
4041#include <getopt.h>
4142#include <signal.h>
43+ #include <stdbool.h>
4244#include <stdint.h>
4345#include <stdio.h>
4446#include <stdlib.h>
@@ -85,7 +87,10 @@ static int v_tty; /* stdout is a tty */
8587static int v_progress ; /* whether to display progress */
8688static pid_t pgrp ; /* our process group */
8789static long w_secs ; /* -w: retry delay */
90+ static char * method ; /* -X: HTTP method */
8891static int family = PF_UNSPEC ; /* -[46]: address family to use */
92+ static struct http_headers headers = TAILQ_HEAD_INITIALIZER (headers );
93+ /* -H: HTTP headers */
8994
9095static int sigalrm ; /* SIGALRM received */
9196static int siginfo ; /* SIGINFO received */
@@ -127,6 +132,7 @@ static struct option longopts[] =
127132 { "direct" , no_argument , NULL , 'd' },
128133 { "force-restart" , no_argument , NULL , 'F' },
129134 /* -f not mapped, since it's deprecated */
135+ { "header" , required_argument , NULL , 'H' },
130136 /* -h not mapped, since it's deprecated */
131137 { "if-modified-since" , required_argument , NULL , 'i' },
132138 { "symlink" , no_argument , NULL , 'l' },
@@ -146,6 +152,7 @@ static struct option longopts[] =
146152 { "passive-portrange-default" , no_argument , NULL , 'T' },
147153 { "verbose" , no_argument , NULL , 'v' },
148154 { "retry-delay" , required_argument , NULL , 'w' },
155+ { "request" , required_argument , NULL , 'X' },
149156
150157 /* options without a single character equivalent */
151158 { "bind-address" , required_argument , NULL , OPTION_BIND_ADDRESS },
@@ -418,11 +425,23 @@ query_auth(struct url *URL)
418425 return (0 );
419426}
420427
428+ /*
429+ * Decide how to invoke libfetch
430+ */
431+ static FILE *
432+ invoke (struct url * url , struct url_stat * us , const char * flags , bool is_http )
433+ {
434+ if (is_http )
435+ return (fetchXReqHTTP (url , us , method ? method : "GET" , flags ,
436+ & headers , NULL , NULL ));
437+ return (fetchXGet (url , us , flags ));
438+ }
439+
421440/*
422441 * Fetch a file
423442 */
424443static int
425- fetch (char * URL , const char * path , int * is_http )
444+ fetch (char * URL , const char * path , bool * is_http )
426445{
427446 struct url * url ;
428447 struct url_stat us ;
@@ -576,7 +595,7 @@ fetch(char *URL, const char *path, int *is_http)
576595 /* start the transfer */
577596 if (timeout )
578597 alarm (timeout );
579- f = fetchXGet (url , & us , flags );
598+ f = invoke (url , & us , flags , * is_http );
580599 if (timeout )
581600 alarm (0 );
582601 if (sigalrm || sigint )
@@ -708,7 +727,7 @@ fetch(char *URL, const char *path, int *is_http)
708727 * from scratch if we want the whole file
709728 */
710729 url -> offset = 0 ;
711- if ((f = fetchXGet (url , & us , flags )) == NULL ) {
730+ if ((f = invoke (url , & us , flags , * is_http )) == NULL ) {
712731 warnx ("%s: %s" , URL , fetchLastErrString );
713732 goto failure ;
714733 }
@@ -883,22 +902,40 @@ fetch(char *URL, const char *path, int *is_http)
883902 return (r );
884903}
885904
905+ static void
906+ add_header (char * arg )
907+ {
908+ struct http_header * hdr ;
909+ char * split ;
910+
911+ if ((split = strchr (arg , ':' )) == NULL )
912+ errx (1 , "invalid header (%s)" , arg );
913+ * split = '\0' ;
914+ if ((hdr = malloc (sizeof (* hdr ))) == NULL )
915+ errx (1 , "%s" , strerror (ENOMEM ));
916+ hdr -> name = arg ;
917+ hdr -> value = split + 1 ;
918+ hdr -> value += strspn (hdr -> value , " \t" ); /* skip leading whitespace */
919+ TAILQ_INSERT_TAIL (& headers , hdr , headers );
920+ }
921+
886922static void
887923usage (void )
888924{
889- fprintf (stderr , "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n" ,
925+ fprintf (stderr , "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n " ,
890926"usage: fetch [-146AadFlMmnPpqRrsUv] [-B bytes] [--bind-address=host]" ,
891927" [--ca-cert=file] [--ca-path=dir] [--cert=file] [--crl=file]" ,
892- " [-i file] [--key=file] [-N file] [--no-passive] [--no-proxy=list ]" ,
893- " [--no-sslv3 ] [--no-tlsv1 ] [--no-verify-hostname ] [--no-verify-peer ]" ,
894- " [-o file] [--referer=URL] [-S bytes] [-T seconds]" ,
895- " [--user-agent=agent-string] [-w seconds] URL ..." ,
928+ " [-H header] [- i file] [--key=file] [-N file] [--no-passive]" ,
929+ " [--no-proxy=list ] [--no-sslv3 ] [--no-tlsv1 ] [--no-verify-hostname ]" ,
930+ " [--no-verify-peer] [- o file] [--referer=URL] [-S bytes] [-T seconds]" ,
931+ " [--user-agent=agent-string] [-w seconds] [-X method] URL ..." ,
896932" fetch [-146AadFlMmnPpqRrsUv] [-B bytes] [--bind-address=host]" ,
897933" [--ca-cert=file] [--ca-path=dir] [--cert=file] [--crl=file]" ,
898- " [-i file] [--key=file] [-N file] [--no-passive] [--no-proxy=list]" ,
899- " [--no-sslv3] [--no-tlsv1] [--no-verify-hostname] [--no-verify-peer]" ,
900- " [-o file] [--referer=URL] [-S bytes] [-T seconds]" ,
901- " [--user-agent=agent-string] [-w seconds] -h host -f file [-c dir]" );
934+ " [-H header] [-i file] [--key=file] [-N file] [--no-passive]" ,
935+ " [--no-proxy=list] [--no-sslv3] [--no-tlsv1] [--no-verify-hostname]" ,
936+ " [--no-verify-peer] [-o file] [--referer=URL] [-S bytes] [-T seconds]" ,
937+ " [--user-agent=agent-string] [-w seconds] [-X method] -h host -f file" ,
938+ " [-c dir]" );
902939}
903940
904941
@@ -912,11 +949,12 @@ main(int argc, char *argv[])
912949 struct sigaction sa ;
913950 const char * p , * s ;
914951 char * end , * q ;
915- int c , e , is_http , r ;
952+ int c , e , r ;
953+ bool is_http ;
916954
917955
918956 while ((c = getopt_long (argc , argv ,
919- "146AaB:bc:dFf:Hh: i:lMmN:nPpo:qRrS:sT:tUvw:" ,
957+ "146AaB:bc:dFf:H:h: i:lMmN:nPpo:qRrS:sT:tUvw:X :" ,
920958 longopts , NULL )) != -1 )
921959 switch (c ) {
922960 case '1' :
@@ -956,8 +994,7 @@ main(int argc, char *argv[])
956994 f_filename = optarg ;
957995 break ;
958996 case 'H' :
959- warnx ("the -H option is now implicit, "
960- "use -U to disable" );
997+ add_header (optarg );
961998 break ;
962999 case 'h' :
9631000 h_hostname = optarg ;
@@ -1031,6 +1068,9 @@ main(int argc, char *argv[])
10311068 if (* optarg == '\0' || * end != '\0' )
10321069 errx (1 , "invalid delay (%s)" , optarg );
10331070 break ;
1071+ case 'X' :
1072+ method = optarg ;
1073+ break ;
10341074 case OPTION_BIND_ADDRESS :
10351075 setenv ("FETCH_BIND_ADDRESS" , optarg , 1 );
10361076 break ;
0 commit comments