/* * cgiproxy.c * this file contains source to proxy a CGI request to another * web server. * * Author(s) * Scott A. Leerssen, leerssen@issl.atl.hp.com * * Protection Notice * Copyright (c) 1997, Scott Leerssen, All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #define BUFSIZE 8192 #define DEFAULTPORT 80 static char iobuf[BUFSIZE]; /* * error * simple function to spew out an error to standard output */ void error(char *fmt, ...) { va_list args; static char *title = "CGI Proxy Error"; fprintf(stdout, "Status: 500 internal-error\n"); fprintf(stdout, "Content-type: text/html\n"); fprintf(stdout, "\n"); fprintf(stdout, ""); fprintf(stdout, "%s", title); fprintf(stdout, ""); fprintf(stdout, "

%s

", title); va_start(args, fmt); vfprintf(stdout, fmt, args); va_end(args); fprintf(stdout, ""); fprintf(stdout, ""); } /* * get_host_port * get hostname and port */ char *get_host_port(char *host, int *port) { char *myname = "CGI Proxy get_host_port()"; char *t; if (host = getenv("HTTPPROX")) { host = strdup(host); } else { error("%s: HTTPPROX not set in environment", myname); return (NULL); } /* * Now determine the port number. First see if we have a colon. */ if ((t = strchr(host, ':')) == NULL) { /* * No colon found, therefore use default. */ *port = DEFAULTPORT; } else { /* * Found a colon. So we might have a port number. * * First mark the end of the hostname. * Then move one space forward to point to the beginning of the * port number and convert it into an integer. */ *t = '\0'; t++; if ((*port = atoi(t)) == 0) { /* * There seems to be some problem converting the port number * to an integer. So lets use the default. */ *port = DEFAULTPORT; } } return(host); } /* * server_connect * connects to the web server */ int server_connect(char *host, int port) { char *myname = "CGI Proxy server_connect()"; int sd; if ((sd = tcp_open(host, 0, port)) >= 0) { return(sd); } error("%s: unable to connect to web server at %s:%d", myname, host, port); return(-1); } #ifdef DEBUG FILE *fp; #define WRITE_STR(d, s) fprintf(fp, "%s", s); write((d), (s), strlen(s)); fflush(fp) #else #define WRITE_STR(d, s) write((d), (s), strlen(s)) #endif /* * write_request * rebuilds the http request from the browser and barfs it out to the * web server. */ int write_request(int sd) { char *myname = "CGI Proxy write_request()"; char *method, *script, *path_info, *query, *protocol; char *content_type; char *content_length; char **e, *s, *t, *n; int bytes, len; /* * suck up some environment variables */ if (method = getenv("REQUEST_METHOD")) { method = strdup(method); } if (script = getenv("SCRIPT_NAME")) { script = strdup(script); } if (path_info = getenv("PATH_INFO")) { path_info = strdup(path_info); } if (query = getenv("QUERY_STRING")) { query = strdup(query); } if (protocol = getenv("SERVER_PROTOCOL")) { protocol = strdup(protocol); } if (content_type = getenv("CONTENT_TYPE")) { content_type = strdup(content_type); } if (content_length = getenv("CONTENT_LENGTH")) { content_length = strdup(content_length); } /* * spew out the RFC 822 style HTTP headers */ /* * construct the HTTP request header line */ sprintf(iobuf, "%s %s%s%s%s %s\n", method, script, (path_info ? path_info : ""), (query ? "?" : ""), (query ? query : ""), protocol); WRITE_STR(sd, iobuf); free(method); free(script); free(path_info); free(query); free(protocol); /* * now, just grab all the environment variables available, except * for a few select ones */ for (e=environ; *e; e++) { t = strdup(*e); if ((n = strchr(t, '=')) == 0) { free(t); continue; /* shouldn't happen, but... */ } *n = 0; s = ++n; if (!(strcasecmp(t, "REQUEST_METHOD") && strcasecmp(t, "SCRIPT_NAME") && strcasecmp(t, "PATH_INFO") && strcasecmp(t, "QUERY_STRING") && strcasecmp(t, "SERVER_PROTOCOL"))) { free(t); continue; } while (n=strchr(t, '_')) { *n = '-'; } sprintf(iobuf, "%s: %s\n", (strncmp("HTTP-", t, 5) ? t : t+5), s); WRITE_STR(sd, iobuf); free(t); } /* * last, but not at all least, the trailing newline */ sprintf(iobuf, "\n"); WRITE_STR(sd, iobuf); /* * Handle the POST method * * start shoveling stdin to the web server socket */ if (content_length) { len = atoi(content_length); while (len > 0) { bytes = read(0, iobuf, (len > BUFSIZE) ? BUFSIZE : len); write(sd, iobuf, bytes); len -= bytes; } } return(0); } /* * pass_response * passes the response from the web server back to the main web * server */ void pass_response(int sd) { char *myname = "CGI Proxy pass_response()"; int bytes; int i; char *b; char protocol[80]; char status[80]; char status_msg[80]; /* * first, read the status message line... the sender is expecting * a browser to be reading this, so we need to do a little work * first. */ b=iobuf; for (i=0;i < BUFSIZE;i++) { if ((bytes = read(sd, b, 1)) <= 0) { if (errno == EAGAIN) { continue; } if (bytes < 0) { error("%s: unexpected end of input stream.", myname); } return; } if (*b == '\n') { break; } b++; } *b = 0; sscanf(iobuf, "%80s%80s%80s", protocol, status, status_msg); /* * now, write out the extracted status and the rest of the * message to stdout, where the main web server is expecting * data. */ sprintf(iobuf, "Status: %s\n", status); while ((bytes = read(sd, iobuf, BUFSIZE))) { write(1, iobuf, bytes); } } /* * main */ main() { char *myname = "CGI Proxy main()"; char *host; int port; int sd; #ifdef DEBUG fp = fopen("/tmp/cgi-out", "a"); #endif /* * connect to the web server */ if ((host = get_host_port(host, &port)) == NULL) { exit(3); } if ((sd = server_connect(host, port)) < 0) { exit(3); } /* * send the request to the web server */ if (write_request(sd)) { close(sd); exit(5); } /* * pass the response from the web server back to the * main web server who started me */ pass_response(sd); /* * go away */ close(sd); #ifdef DEBUG fclose(fp); #endif exit(0); }