code: plan9front

ref: 5622b0bbd878dbc34045cc6fd37cffa64461eabe
dir: /sys/src/cmd/ip/hproxy.c/

View raw version
#include <u.h>
#include <libc.h>

enum { bufsize = 8*1024 };
char buf[bufsize+1], addr[128], *proto, *host, *port, *path;

void
main(void)
{
	char *f[3], *p, *e;
	int con, fd, n, r;

	/* read all the headers */
	n = 0;
	do {
		if(n >= bufsize)
			return;
		if((r = read(0, buf+n, bufsize-n)) <= 0)
			return;
		n += r;
		buf[n] = 0;
	} while(strstr(buf, "\r\n\r\n") == nil);

	/* remove keep alive headers */
	if(p = cistrstr(buf, "\nConnection:"))
		if(e = strchr(p+1, '\n'))
			strcpy(p, e);
	if(p = cistrstr(buf, "\nProxy-Connection:"))
		if(e = strchr(p+1, '\n'))
			strcpy(p, e);

	/* crack first line of http request */
	if(e = strchr(buf, '\n'))
		*e++ = 0;
	r = tokenize(buf, f, 3);
	if(r < 2)
		return;
	if(r == 2)
		f[2] = "HTTP/1.0";
	proto = f[1];
	if(p = strstr(proto, "://")){
		*p = 0;
		host = p + 3;
	} else {
		host = proto;
		proto = "http";
	}
	port = proto;
	path = "";
	if(p = strchr(host, '/')){
		*p++ = 0;
		path = p;
	}
	if(*host == '['){
		host++;
		if(p = strrchr(host, ']')){
			*p++ = 0;
			if(p = strrchr(p, ':'))
				port = ++p;
		}
	} else if(p = strrchr(host, ':')){
		*p++ = 0;
		port = p;
	}

	snprint(addr, sizeof(addr), "tcp!%s!%s", host, port);

	alarm(30000);
	fd = dial(addr, 0, 0, 0);
	alarm(0);

	con = cistrcmp(f[0], "CONNECT") == 0;
	if(con){
		if(fd < 0)
			print("%s 500 Connection Failed\r\n\r\n%r\n", f[2]);
		else
			print("%s 200 Connection Established\r\n\r\n", f[2]);
	}
	if(fd < 0)
		return;

	switch(rfork(RFPROC|RFFDG|RFNOWAIT)){
	case -1:
		return;
	case 0:
		dup(fd, 0);
		break;
	default:
		dup(fd, 1);
		if(!con)
			print("%s /%s %s\r\nConnection: close\r\n%s", f[0], path, f[2], e);
	}

	while((r = read(0, buf, sizeof(buf))) > 0)
		if(write(1, buf, r) != r)
			break;

	postnote(PNGROUP, getpid(), "kill");
}