http_post-20110118/000075500000000000000000000000001215616276200140035ustar00rootroot00000000000000http_post-20110118/Makefile000064400000000000000000000021771215616276200154520ustar00rootroot00000000000000# Makefile for http_post # CONFIGURE: If you are using a SystemV-based operating system, such as # Solaris, you will need to uncomment this definition. #SYSV_LIBS = -lnsl -lsocket # CONFIGURE: If you want to compile in support for https, uncomment these # definitions. You will need to have already built OpenSSL, available at # http://www.openssl.org/ Make sure the SSL_TREE definition points to the # tree with your OpenSSL installation - depending on how you installed it, # it may be in /usr/local instead of /usr/local/ssl. #SSL_TREE = /usr/local/ssl #SSL_DEFS = -DUSE_SSL #SSL_INC = -I$(SSL_TREE)/include #SSL_LIBS = -L$(SSL_TREE)/lib -lssl -lcrypto BINDIR = /usr/local/bin MANDIR = /usr/local/man/man1 CC = gcc CFLAGS = -Wall -O $(SSL_DEFS) $(SSL_INC) #CFLAGS = -Wall -g $(SSL_DEFS) $(SSL_INC) LDFLAGS = -s $(SSL_LIBS) $(SYSV_LIBS) #LDFLAGS = -g $(SSL_LIBS) $(SYSV_LIBS) all: http_post http_post: http_post.c $(CC) $(CFLAGS) http_post.c $(LDFLAGS) -o http_post install: all rm -f $(BINDIR)/http_post cp http_post $(BINDIR) rm -f $(MANDIR)/http_post.1 cp http_post.1 $(MANDIR) clean: rm -f http_post *.o core core.* *.core http_post-20110118/README000064400000000000000000000014141215616276200146630ustar00rootroot00000000000000 http_post - do a POST to an HTTP URL http_post does a POST operation to an HTTP URL and dumps the results to stdout. It does not do gopher, ftp, file, news, or any other type of URL, only HTTP. It can be configured to do HTTPS POSTs as well. Files in this distribution: README this Makefile guess http_post.c source file http_post.1 manual entry To build: If you're on a SysV-like machine (which includes old Linux systems but not new Linux systems), edit the Makefile and uncomment the SYSV_LIBS line. If you're doing SSL, uncomment those lines too. Otherwise, just do a make. Feedback is welcome - send bug reports, enhancements, checks, money orders, etc. to the addresses below. Jef Poskanzer jef@mail.acme.com http://www.acme.com/jef/ http_post-20110118/http_post.1000064400000000000000000000056351215616276200161220ustar00rootroot00000000000000.TH http_post 1 "16 March 1999" .SH NAME http_post - do a POST to an HTTP URL .SH SYNOPSIS .B http_post .RB [ -t .IR timeout ] .RB [ -r .IR referer ] .RB [ -u .IR user-agent ] .RB [ -a .IR username:password ] .RB [ -c .IR cookie ] .RB [ -h .I header value .R ] .RB [ -v ] .I url .RB [ -f ] .I name=value ... .SH DESCRIPTION .PP .I http_post Http_post does a POST operation to an HTTP URL and dumps the results to stdout. It does not do gopher, ftp, file, news, or any other type of URL, only HTTP. It can be configured to do HTTPS POSTs as well. .PP The -t flag specifies a timeout in seconds. If that much time passes with no activity, the post is aborted. The default is 60 seconds. .PP The -r flag specifies a Referer header to send. Some tightly-clenched web admins like to jigger their server to only return files if the proper Referer is given. .PP The -u flag specifies a User-Agent header to send. Some *really* tightly-clenched web admins like to jigger their server to only return files if a well-known User-Agent is given. .PP The -a flag lets you do Basic Authentication. .PP The -c flag lets you pass in a cookie. .PP The -h flag lets you pass in one extra header. .PP The -v flag is for debugging; it writes out the response headers, as well as the response contents. .PP The -f flag can be used before each name=value pair. It tells http_post that the value is actually a filename to be read and inserted into the request. It also switches the entire request to use a content-type of multipart/form-data, instead of the usual application/x-www-form-urlencoded. .SH AUTHOR Copyright © 1999,2003 by Jef Poskanzer . All rights reserved. .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. http_post-20110118/http_post.c000064400000000000000000000556621215616276200162110ustar00rootroot00000000000000/* http_post - do a POST to an HTTP URL ** ** Copyright © 1999,2003 by Jef Poskanzer . ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions ** are met: ** 1. Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** 2. Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in the ** documentation and/or other materials provided with the distribution. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ** SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef USE_SSL #include #include #endif /* Forwards. */ static void usage(); static void postURL( char* url, char* referer, char* user_agent, char* auth_token, int ncookies, char** cookies, char* header_name, char* header_value, char** args, int argc ); static void postURLbyParts( int protocol, char* host, unsigned short port, char* file, char* referer, char* user_agent, char* auth_token, int ncookies, char** cookies, char* header_name, char* header_value, char** args, int argc ); static int open_client_socket( char* hostname, unsigned short port ); static void show_error( char* cause ); static void sigcatch( int sig ); static void strencode( char* to, char* from ); static int b64_encode( unsigned char* ptr, int len, char* space, int size ); static void* malloc_check( size_t size ); static void check( void* ptr ); static off_t file_bytes( const char* filename ); static int file_copy( const char* filename, char* buf ); /* Globals. */ static char* argv0; static int timeout; static char* url; static int verbose; /* Protocol symbols. */ #define PROTO_HTTP 0 #ifdef USE_SSL #define PROTO_HTTPS 1 #endif /* Header FSM states. */ #define HDST_BOL 0 #define HDST_TEXT 1 #define HDST_LF 2 #define HDST_CR 3 #define HDST_CRLF 4 #define HDST_CRLFCR 5 #define MAX_COOKIES 20 int main( int argc, char** argv ) { int argn; char* referer; char* user_agent; char* auth_token; int ncookies; char* cookies[MAX_COOKIES]; char* header_name; char* header_value; argv0 = argv[0]; argn = 1; timeout = 60; referer = (char*) 0; user_agent = "http_post"; auth_token = (char*) 0; ncookies = 0; header_name = (char*) 0; header_value = (char*) 0; verbose = 0; while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) { if ( strcmp( argv[argn], "-t" ) == 0 && argn + 1 < argc ) { ++argn; timeout = atoi( argv[argn] ); } else if ( strcmp( argv[argn], "-r" ) == 0 && argn + 1 < argc ) { ++argn; referer = argv[argn]; } else if ( strcmp( argv[argn], "-u" ) == 0 && argn + 1 < argc ) { ++argn; user_agent = argv[argn]; } else if ( strcmp( argv[argn], "-a" ) == 0 && argn + 1 < argc ) { ++argn; auth_token = argv[argn]; } else if ( strcmp( argv[argn], "-c" ) == 0 && argn + 1 < argc ) { if ( ncookies >= MAX_COOKIES ) { (void) fprintf( stderr, "%s: too many cookies\n", argv0 ); exit( 1 ); } ++argn; cookies[ncookies++] = argv[argn]; } else if ( strcmp( argv[argn], "-h" ) == 0 && argn + 2 < argc ) { ++argn; header_name = argv[argn]; ++argn; header_value = argv[argn]; } else if ( strcmp( argv[argn], "-v" ) == 0 ) verbose = 1; else usage(); ++argn; } if ( argn >= argc ) usage(); url = argv[argn]; ++argn; (void) signal( SIGALRM, sigcatch ); postURL( url, referer, user_agent, auth_token, ncookies, cookies, header_name, header_value, &(argv[argn]), argc - argn ); exit( 0 ); } static void usage() { (void) fprintf( stderr, "usage: %s [-c cookie] [-t timeout] [-r referer] [-u user-agent] [-a username:password] [-h header value] [-v] url\n", argv0 ); exit( 1 ); } /* url must be of the form http://host-name[:port]/file-name */ static void postURL( char* url, char* referer, char* user_agent, char* auth_token, int ncookies, char** cookies, char* header_name, char* header_value, char** args, int argc ) { char* s; int protocol; char host[2000]; int host_len; unsigned short port; char* file = 0; char* http = "http://"; int http_len = strlen( http ); #ifdef USE_SSL char* https = "https://"; int https_len = strlen( https ); #endif /* USE_SSL */ int proto_len; if ( url == (char*) 0 ) { (void) fprintf( stderr, "%s: null URL\n", argv0 ); exit( 1 ); } if ( strncmp( http, url, http_len ) == 0 ) { proto_len = http_len; protocol = PROTO_HTTP; } #ifdef USE_SSL else if ( strncmp( https, url, https_len ) == 0 ) { proto_len = https_len; protocol = PROTO_HTTPS; } #endif /* USE_SSL */ else { (void) fprintf( stderr, "%s: non-http URL\n", argv0 ); exit( 1 ); } /* Get the host name. */ for ( s = url + proto_len; *s != '\0' && *s != ':' && *s != '/'; ++s ) ; host_len = s - url; host_len -= proto_len; strncpy( host, url + proto_len, host_len ); host[host_len] = '\0'; /* Get port number. */ if ( *s == ':' ) { port = (unsigned short) atoi( ++s ); while ( *s != '\0' && *s != '/' ) ++s; } else { #ifdef USE_SSL if ( protocol == PROTO_HTTPS ) port = 443; else #endif port = 80; } /* Get the file name. */ if ( *s == '\0' ) file = "/"; else file = s; postURLbyParts( protocol, host, port, file, referer, user_agent, auth_token, ncookies, cookies, header_name, header_value, args, argc ); } static void postURLbyParts( int protocol, char* host, unsigned short port, char* file, char* referer, char* user_agent, char* auth_token, int ncookies, char** cookies, char* header_name, char* header_value, char** args, int argc ) { int sockfd; #ifdef USE_SSL SSL_CTX* ssl_ctx = (SSL_CTX*) 0; SSL* ssl = (SSL*) 0; #endif char head_buf[20000]; int max_arg, total_bytes; int multipart, next_arg_is_file; static const char* const sep = "http_post-content-separator"; char* data_buf; char* enc_buf; int head_bytes, data_bytes, i, header_state; char* eq; (void) alarm( timeout ); sockfd = open_client_socket( host, port ); #ifdef USE_SSL if ( protocol == PROTO_HTTPS ) { /* Make SSL connection. */ int r; SSL_load_error_strings(); SSLeay_add_ssl_algorithms(); ssl_ctx = SSL_CTX_new( SSLv23_client_method() ); ssl = SSL_new( ssl_ctx ); SSL_set_fd( ssl, sockfd ); r = SSL_connect( ssl ); if ( r <= 0 ) { (void) fprintf( stderr, "%s: %s - SSL connection failed - %d\n", argv0, url, r ); ERR_print_errors_fp( stderr ); exit( 1 ); } } #endif /* Run through the arguments and figure out the total and max sizes, ** then allocate enough space. */ multipart = 0; total_bytes = max_arg = 0; next_arg_is_file = 0; for ( i = 0; i < argc ; ++i ) { int l = strlen( args[i] ); if ( strcmp( args[i], "-f" ) == 0 ) { multipart = 1; next_arg_is_file = 1; continue; } total_bytes += l; if ( l > max_arg ) max_arg = l; if ( next_arg_is_file ) { eq = strchr( args[i], '=' ); if ( eq == (char*) 0 ) { (void) fprintf( stderr, "%s: missing filename\n", argv0 ); exit( 1 ); } else { ++eq; total_bytes += file_bytes( eq ); } next_arg_is_file = 0; } } if ( multipart ) { for ( i = 0; i < argc ; ++i ) total_bytes += strlen( sep ) * 2 + 100; total_bytes += strlen( sep ) * 2; } else { total_bytes *= 4; enc_buf = (char*) malloc_check( max_arg * 4 ); } data_buf = (char*) malloc_check( total_bytes ); /* Encode the POST data. */ if ( multipart ) { next_arg_is_file = 0; data_bytes = 0; for ( i = 0; i < argc ; ++i ) { if ( strcmp( args[i], "-f" ) == 0 ) { next_arg_is_file = 1; continue; } eq = strchr( args[i], '=' ); if ( eq == (char*) 0 ) data_bytes += sprintf( &data_buf[data_bytes], "--%s\r\nContent-Disposition: form-data\r\n\r\n%s\r\n", sep, args[i] ); else { *eq++ = '\0'; if ( next_arg_is_file ) { data_bytes += sprintf( &data_buf[data_bytes], "--%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\n\r\n", sep, args[i], eq ); data_bytes += file_copy( eq, &data_buf[data_bytes] ); data_bytes += sprintf( &data_buf[data_bytes], "\r\n" ); next_arg_is_file = 0; } else data_bytes += sprintf( &data_buf[data_bytes], "--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n", sep, args[i], eq ); } } data_bytes += sprintf( &data_buf[data_bytes], "--%s--\r\n", sep ); } else { /* Not multipart. */ data_bytes = 0; for ( i = 0; i < argc ; ++i ) { if ( data_bytes > 0 ) data_bytes += sprintf( &data_buf[data_bytes], "&" ); eq = strchr( args[i], '=' ); if ( eq == (char*) 0 ) { strencode( enc_buf, args[i] ); data_bytes += sprintf( &data_buf[data_bytes], "%s", enc_buf ); } else { *eq++ = '\0'; strencode( enc_buf, args[i] ); data_bytes += sprintf( &data_buf[data_bytes], "%s=", enc_buf ); strencode( enc_buf, eq ); data_bytes += sprintf( &data_buf[data_bytes], "%s", enc_buf ); } } } /* Build request buffer, starting with the POST. */ (void) alarm( timeout ); head_bytes = snprintf( head_buf, sizeof(head_buf), "POST %s HTTP/1.0\r\n", file ); /* HTTP/1.1 host header - some servers want it even in HTTP/1.0. */ head_bytes += snprintf( &head_buf[head_bytes], sizeof(head_buf) - head_bytes, "Host: %s\r\n", host ); /* Content-length. */ head_bytes += snprintf( &head_buf[head_bytes], sizeof(head_buf) - head_bytes, "Content-Length: %d\r\n", data_bytes ); if ( referer != (char*) 0 ) /* Referer. */ head_bytes += snprintf( &head_buf[head_bytes], sizeof(head_buf) - head_bytes, "Referer: %s\r\n", referer ); /* User-agent. */ head_bytes += snprintf( &head_buf[head_bytes], sizeof(head_buf) - head_bytes, "User-Agent: %s\r\n", user_agent ); /* Content-type. */ if ( multipart ) head_bytes += snprintf( &head_buf[head_bytes], sizeof(head_buf) - head_bytes, "Content-type: multipart/form-data; boundary=\"%s\"\r\n", sep ); else head_bytes += snprintf( &head_buf[head_bytes], sizeof(head_buf) - head_bytes, "Content-type: application/x-www-form-urlencoded\r\n" ); /* Fixed headers. */ head_bytes += snprintf( &head_buf[head_bytes], sizeof(head_buf) - head_bytes, "Accept: */*\r\n" ); head_bytes += snprintf( &head_buf[head_bytes], sizeof(head_buf) - head_bytes, "Accept-Language: en\r\n" ); head_bytes += snprintf( &head_buf[head_bytes], sizeof(head_buf) - head_bytes, "Accept-Charset: iso-8859-1,*,utf-8\r\n" ); if ( auth_token != (char*) 0 ) { /* Basic Auth info. */ char token_buf[1000]; token_buf[b64_encode( (unsigned char*) auth_token, strlen( auth_token ), token_buf, sizeof(token_buf) )] = '\0'; head_bytes += snprintf( &head_buf[head_bytes], sizeof(head_buf) - head_bytes, "Authorization: Basic %s\r\n", token_buf ); } /* Cookies. */ for ( i = 0; i < ncookies; ++i ) head_bytes += snprintf( &head_buf[head_bytes], sizeof(head_buf) - head_bytes, "Cookie: %s\r\n", cookies[i] ); /* Optional extra header. */ if ( header_name != (char*) 0 ) head_bytes += snprintf( &head_buf[head_bytes], sizeof(head_buf) - head_bytes, "%s: %s\r\n", header_name, header_value ); /* Blank line. */ head_bytes += snprintf( &head_buf[head_bytes], sizeof(head_buf) - head_bytes, "\r\n" ); /* Now actually send it. */ #ifdef USE_SSL if ( protocol == PROTO_HTTPS ) (void) SSL_write( ssl, head_buf, head_bytes ); else #endif (void) write( sockfd, head_buf, head_bytes ); /* And send the POST data too. */ #ifdef USE_SSL if ( protocol == PROTO_HTTPS ) (void) SSL_write( ssl, data_buf, data_bytes ); else #endif (void) write( sockfd, data_buf, data_bytes ); /* Get lines until a blank one. */ (void) alarm( timeout ); header_state = HDST_BOL; for (;;) { #ifdef USE_SSL if ( protocol == PROTO_HTTPS ) head_bytes = SSL_read( ssl, head_buf, sizeof(head_buf) ); else #endif head_bytes = read( sockfd, head_buf, sizeof(head_buf) ); if ( head_bytes <= 0 ) break; for ( i = 0; i < head_bytes; ++i ) { if ( verbose ) (void) write( 1, &head_buf[i], 1 ); switch ( header_state ) { case HDST_BOL: switch ( head_buf[i] ) { case '\n': header_state = HDST_LF; break; case '\r': header_state = HDST_CR; break; default: header_state = HDST_TEXT; break; } break; case HDST_TEXT: switch ( head_buf[i] ) { case '\n': header_state = HDST_LF; break; case '\r': header_state = HDST_CR; break; } break; case HDST_LF: switch ( head_buf[i] ) { case '\n': goto end_of_headers; case '\r': header_state = HDST_CR; break; default: header_state = HDST_TEXT; break; } break; case HDST_CR: switch ( head_buf[i] ) { case '\n': header_state = HDST_CRLF; break; case '\r': goto end_of_headers; default: header_state = HDST_TEXT; break; } break; case HDST_CRLF: switch ( head_buf[i] ) { case '\n': goto end_of_headers; case '\r': header_state = HDST_CRLFCR; break; default: header_state = HDST_TEXT; break; } break; case HDST_CRLFCR: switch ( head_buf[i] ) { case '\n': case '\r': goto end_of_headers; default: header_state = HDST_TEXT; break; } break; } } } end_of_headers: /* Dump out the rest of the headers buffer. */ if ( head_bytes > 0 ) { ++i; (void) write( 1, &head_buf[i], head_bytes - i ); } /* Copy the data. */ for (;;) { (void) alarm( timeout ); #ifdef USE_SSL if ( protocol == PROTO_HTTPS ) head_bytes = SSL_read( ssl, head_buf, sizeof(head_buf) ); else #endif head_bytes = read( sockfd, head_buf, sizeof(head_buf) ); if ( head_bytes == 0 ) break; if ( head_bytes < 0 ) show_error( "read" ); (void) write( 1, head_buf, head_bytes ); } #ifdef USE_SSL if ( protocol == PROTO_HTTPS ) { SSL_free( ssl ); SSL_CTX_free( ssl_ctx ); } #endif (void) close( sockfd ); } #if defined(AF_INET6) && defined(IN6_IS_ADDR_V4MAPPED) #define USE_IPV6 #endif static int open_client_socket( char* hostname, unsigned short port ) { #ifdef USE_IPV6 struct addrinfo hints; char portstr[50]; int gaierr; struct addrinfo* ai; struct addrinfo* ai2; struct addrinfo* aiv4; struct addrinfo* aiv6; struct sockaddr_in6 sa; #else /* USE_IPV6 */ struct hostent *he; struct sockaddr_in sa; #endif /* USE_IPV6 */ int sa_len, sock_family, sock_type, sock_protocol; int sockfd; (void) memset( (void*) &sa, 0, sizeof(sa) ); #ifdef USE_IPV6 (void) memset( &hints, 0, sizeof(hints) ); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; (void) sprintf( portstr, "%d", (int) port ); if ( (gaierr = getaddrinfo( hostname, portstr, &hints, &ai )) != 0 ) { (void) fprintf( stderr, "%s: getaddrinfo %s - %s\n", argv0, hostname, gai_strerror( gaierr ) ); exit( 1 ); } /* Find the first IPv4 and IPv6 entries. */ aiv4 = (struct addrinfo*) 0; aiv6 = (struct addrinfo*) 0; for ( ai2 = ai; ai2 != (struct addrinfo*) 0; ai2 = ai2->ai_next ) { switch ( ai2->ai_family ) { case AF_INET: if ( aiv4 == (struct addrinfo*) 0 ) aiv4 = ai2; break; case AF_INET6: if ( aiv6 == (struct addrinfo*) 0 ) aiv6 = ai2; break; } } /* If there's an IPv4 address, use that, otherwise try IPv6. */ if ( aiv4 != (struct addrinfo*) 0 ) { if ( sizeof(sa) < aiv4->ai_addrlen ) { (void) fprintf( stderr, "%s - sockaddr too small (%lu < %lu)\n", hostname, (unsigned long) sizeof(sa), (unsigned long) aiv4->ai_addrlen ); exit( 1 ); } sock_family = aiv4->ai_family; sock_type = aiv4->ai_socktype; sock_protocol = aiv4->ai_protocol; sa_len = aiv4->ai_addrlen; (void) memmove( &sa, aiv4->ai_addr, sa_len ); goto ok; } if ( aiv6 != (struct addrinfo*) 0 ) { if ( sizeof(sa) < aiv6->ai_addrlen ) { (void) fprintf( stderr, "%s - sockaddr too small (%lu < %lu)\n", hostname, (unsigned long) sizeof(sa), (unsigned long) aiv6->ai_addrlen ); exit( 1 ); } sock_family = aiv6->ai_family; sock_type = aiv6->ai_socktype; sock_protocol = aiv6->ai_protocol; sa_len = aiv6->ai_addrlen; (void) memmove( &sa, aiv6->ai_addr, sa_len ); goto ok; } (void) fprintf( stderr, "%s: no valid address found for host %s\n", argv0, hostname ); exit( 1 ); ok: freeaddrinfo( ai ); #else /* USE_IPV6 */ he = gethostbyname( hostname ); if ( he == (struct hostent*) 0 ) { (void) fprintf( stderr, "%s: unknown host - %s\n", argv0, hostname ); exit( 1 ); } sock_family = sa.sin_family = he->h_addrtype; sock_type = SOCK_STREAM; sock_protocol = 0; sa_len = sizeof(sa); (void) memmove( &sa.sin_addr, he->h_addr, he->h_length ); sa.sin_port = htons( port ); #endif /* USE_IPV6 */ sockfd = socket( sock_family, sock_type, sock_protocol ); if ( sockfd < 0 ) show_error( "socket" ); if ( connect( sockfd, (struct sockaddr*) &sa, sa_len ) < 0 ) show_error( "connect" ); return sockfd; } static void show_error( char* cause ) { char buf[5000]; (void) sprintf( buf, "%s: %s - %s", argv0, url, cause ); perror( buf ); exit( 1 ); } static void sigcatch( int sig ) { (void) fprintf( stderr, "%s: %s - timed out\n", argv0, url ); exit( 1 ); } static void strencode( char* to, char* from ) { int tolen; for ( tolen = 0; *from != '\0'; ++from ) { if ( isalnum(*from) || strchr( "/_.", *from ) != (char*) 0 ) { *to = *from; ++to; ++tolen; } else { (void) sprintf( to, "%%%02x", (int) *from & 0xff ); to += 3; tolen += 3; } } *to = '\0'; } /* Base-64 encoding. This encodes binary data as printable ASCII characters. ** Three 8-bit binary bytes are turned into four 6-bit values, like so: ** ** [11111111] [22222222] [33333333] ** ** [111111] [112222] [222233] [333333] ** ** Then the 6-bit values are represented using the characters "A-Za-z0-9+/". */ static char b64_encode_table[64] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', /* 0-7 */ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 8-15 */ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', /* 16-23 */ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', /* 24-31 */ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 32-39 */ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', /* 40-47 */ 'w', 'x', 'y', 'z', '0', '1', '2', '3', /* 48-55 */ '4', '5', '6', '7', '8', '9', '+', '/' /* 56-63 */ }; static int b64_decode_table[256] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */ 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */ 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */ -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */ 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 /* F0-FF */ }; /* Do base-64 encoding on a hunk of bytes. Return the actual number of ** bytes generated. Base-64 encoding takes up 4/3 the space of the original, ** plus a bit for end-padding. 3/2+5 gives a safe margin. */ static int b64_encode( unsigned char* ptr, int len, char* space, int size ) { int ptr_idx, space_idx, phase; char c; space_idx = 0; phase = 0; for ( ptr_idx = 0; ptr_idx < len; ++ptr_idx ) { switch ( phase ) { case 0: c = b64_encode_table[ptr[ptr_idx] >> 2]; if ( space_idx < size ) space[space_idx++] = c; c = b64_encode_table[( ptr[ptr_idx] & 0x3 ) << 4]; if ( space_idx < size ) space[space_idx++] = c; ++phase; break; case 1: space[space_idx - 1] = b64_encode_table[ b64_decode_table[(int) ((unsigned char) space[space_idx - 1])] | ( ptr[ptr_idx] >> 4 ) ]; c = b64_encode_table[( ptr[ptr_idx] & 0xf ) << 2]; if ( space_idx < size ) space[space_idx++] = c; ++phase; break; case 2: space[space_idx - 1] = b64_encode_table[ b64_decode_table[(int) ((unsigned char) space[space_idx - 1])] | ( ptr[ptr_idx] >> 6 ) ]; c = b64_encode_table[ptr[ptr_idx] & 0x3f]; if ( space_idx < size ) space[space_idx++] = c; phase = 0; break; } } /* Pad with ='s. */ while ( phase++ < 3 ) if ( space_idx < size ) space[space_idx++] = '='; return space_idx; } static void* malloc_check( size_t size ) { void* ptr = malloc( size ); check( ptr ); return ptr; } static void check( void* ptr ) { if ( ptr == (void*) 0 ) { (void) fprintf( stderr, "%s: out of memory\n", argv0 ); exit( 1 ); } } static off_t file_bytes( const char* filename ) { struct stat sb; if ( stat( filename, &sb ) < 0 ) { perror( filename ); exit( 1 ); } return sb.st_size; } static int file_copy( const char* filename, char* buf ) { int fd; struct stat sb; off_t bytes; fd = open( filename, O_RDONLY ); if ( fd == -1 ) { perror( filename ); exit( -1 ); } if ( fstat( fd, &sb ) != 0 ) { perror( filename ); exit( -1 ); } bytes = sb.st_size; if ( read( fd, buf, bytes ) != bytes ) { perror( filename ); exit( -1 ); } (void) close( fd ); return bytes; }