/* * This program is a CGI script that proxies HTTP requests to a * remote host. The path portion of the requested URL is parsed into * a host and URL. * * Author: David Jones * Date: 2-NOV-1994 */ #include #include #include #include #include #include #include #include #include #include #include "scriptlib.h" /* net_link_... routines */ static int open_remote(), send_query(), read_response(); /********************************************************************/ /* Main routine. */ int main ( int argc, char **argv ) { int sd, tcnt, length, i, status; char *inp; char bin_path[256], remhost[256]; /* * Validate command line arguments. The target machine * is appended to the script name that invokes this program. */ if ( argc < 3 ) { fprintf( stderr, "Missing arguments, usage: prog method url\n"); exit ( 1 ); } /* * Open network link and get search/point argument. Note that network * connection is record oriented, a zero length record is allowed. */ status = net_link_open(); if ( (status&1) == 0 ) { perror("Network connect fail"); exit (status); } /* * Verify that URL starts with the appropriate path, then trim * off path and script name from the URL. */ status = net_link_query ( "", bin_path, sizeof(bin_path)-1, &length ); if ( (status&1) == 0 ) { perror("Network I/O failure"); exit (status); } if ( length < 0 ) exit ( 1 ); bin_path[length] = '\0'; /* terminate string */ if ( 0 != strncmp(argv[2], bin_path, length) ) { fprintf( stderr, "Invalid URL (%s), must start with %s\n",argv[2], bin_path); exit ( 1 ); } for ( inp = &argv[2][length]; *inp && (*inp != '/'); inp++ ); /* * Split off remote hostname. */ if ( *inp ) { inp++; for ( i = 0; i < sizeof(remhost)-1; i++ ) { if ( *inp && (*inp != '/') ) remhost[i] = *inp++; else break; } remhost[i] = '\0'; } else remhost[0] = '\0'; /* * Connect to remote host. */ sd = open_remote ( remhost ); if ( sd < 0 ) { } /* * Construct query and send to remote. */ status = send_query ( sd, argv[1], inp, argv[3] ); if ( (status&1) == 1 ) status = read_response ( sd ); return status; } /*****************************************************************************/ /* Create socket and connect to remote host. */ static int open_remote ( char *remhost ) { struct sockaddr local, remote; struct hostent *hostinfo; int i, j, rem_port, sd, status; char *alt_port; /* */ rem_port = 80; alt_port = strchr ( remhost, ':' ); if ( alt_port ) { *alt_port++ = '\0'; rem_port = atoi ( alt_port ); } hostinfo = gethostbyname ( remhost ); if ( !hostinfo ) { fprintf(stderr, "Could not find host '%s'\n", remhost ); return -1; } /* * Attempt connect to remote host. */ sd = socket ( AF_INET, SOCK_STREAM, 0 ); if ( sd < 0 ) { fprintf(stderr,"Error creating socket: %s\n", strerror(errno) ); return sd; } local.sa_family = AF_INET; for ( j = 0; j < sizeof(local.sa_data); j++ ) local.sa_data[j] = '\0'; local.sa_data[0] = local.sa_data[1] = 0; status = bind ( sd, &local, sizeof ( local ) ); if ( status < 0 ) { fprintf(stderr,"Error binding socket: %s\n", strerror(errno) ); return -1; } remote.sa_family = hostinfo->h_addrtype; for ( j = 0; j < hostinfo->h_length; j++ ) { remote.sa_data[j+2] = hostinfo->h_addr_list[0][j]; } remote.sa_data[0] = rem_port >> 8; remote.sa_data[1] = (rem_port&255); status = connect ( sd, &remote, sizeof(remote) ); if ( status != 0 ) { return -1; } return sd; } /*****************************************************************************/ /* Get request information and send query. */ static int send_query ( int sd, char *method, char *path, char *version ) { int content_length, i, status, length, written; char *cmp, buffer[4096]; /* * Send initial part of request. */ strcpy ( buffer, method ); strcat ( buffer, " " ); strcat ( buffer, path ); strcat ( buffer, " " ); strcat ( buffer, version ); strcat ( buffer, "\r\n" ); length = strlen ( buffer ); written = write ( sd, buffer, length ); if ( written != length ) return 0; /* * Fetch header lines. */ cmp = "CONTENT-LENGTH:"; content_length = 0; for ( status = net_link_query ( "", buffer, sizeof(buffer)-2, &length ); ((status&1) == 1) && (length > 0); status = net_link_read ( buffer, sizeof(buffer)-2, &length ) ) { /* * Relay to remote. */ buffer[length++] = '\r'; buffer[length++] = '\n'; written = write ( sd, buffer, length ); if ( written != length ) return 0; /* * Check if line is 'content-length:' and save. */ buffer[length-2] = '\0'; for ( i = 0; i < length; i++ ) { if ( cmp[i] != _toupper(buffer[i]) ) break; if ( cmp[i] == ':' ) { fprintf(stderr,"Found content_length: %s\n", buffer); content_length = atoi ( &buffer[i+1] ); break; } } } written = write ( sd, "\r\n", 2 ); /* * Send additional. */ while ( content_length > 0 ) { status = net_link_query ( "", buffer, sizeof(buffer), &length ); if ( (status&1) == 0 ) break; if ( length > 0 ) { written = write ( sd, buffer, length ); if ( written != length ) return 0; content_length = content_length - length; } } return 1; } /*****************************************************************************/ static int read_response ( int sd ) { int status, length; char buffer[4096]; status = net_link_write ( "", 9 ); if ( (status&1) == 1 ) status = net_link_set_rundown ( "" ); while ( (length = read ( sd, buffer, sizeof(buffer))) > 0 ) { status = net_link_write ( buffer, length ); if ( (status&1) == 0 ) break; } return status; }