/*
  decode_http.c

  Hypertext Transfer Protocol.
  
  Copyright (c) 2000 Dug Song <dugsong@monkey.org>
 
  $Id: decode_http.c,v 1.5 2000/06/16 20:36:16 dugsong Exp $
*/

#include "config.h"

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef HAVE_LIBGEN_H
#include <libgen.h>
#endif
#include "base64.h"
#include "decode.h"

enum {
	M_GET = 1,
	M_POST,
	M_CONNECT
};
	
static int
http_method(char **p)
{
	if (strncmp(*p, "GET ", 4) == 0) {
		*p += 4;
		return (M_GET);
	}
	else if (strncmp(*p, "POST ", 5) == 0) {
		*p += 5;
		return (M_POST);
	}
	else if (strncmp(*p, "CONNECT ", 8) == 0) {
		*p += 5;
		return (M_CONNECT);
	}
	return (0);
}

static char *
http_req_dirname(char *req)
{
	char *uri, *vers;
	
	if ((uri = strchr(req, ' ')) == NULL)
		return (req);
	
	if ((vers = strrchr(uri, ' ')) == uri) {
		vers = NULL;
	}
	else if (vers[-1] == '/') {
		return (req);
	}
	else *vers++ = '\0';
	
	strcpy(req, dirname(req));
	strcat(req, "/");
	
	if (vers) {
		strcat(req, " ");
		strcat(req, vers);
	}
	return (req);
}  

static char *user_vars[] = {
	"acctname", "alias", "domain", "fname", "email", "id", "login",
	"loginid", "loginname", "login_id", "mn", "name", "uid", "unickname",
	"user", "userid", "user_id", "username", "username_login",
	"u2_username", NULL
};

static char *pass_vars[] = {
	"pass", "passname", "passwd", "password", "password1",
	"password_from_form", "password_login", "pw", "upasswd",
	"u2_password", NULL
};

static int
grep_query_auth(char *buf)
{
	char *p, *q, *tmp;
	int i, user, pass;

	user = pass = 0;
	
	if ((tmp = strdup(buf)) == NULL)
		return (0);
	
	for (p = strtok(tmp, "&"); p != NULL; p = strtok(NULL, "&")) {
		if ((q = strchr(p, '=')) == NULL)
			continue;
		*q = '\0';

		if (!user) {
			for (i = 0; user_vars[i] != NULL; i++) {
				if (strcasecmp(p, user_vars[i]) == 0) {
					user = 1;
					break;
				}
			}
			if (user) continue;
		}
		if (!pass) {
			for (i = 0; pass_vars[i] != NULL; i++) {
				if (strcasecmp(p, pass_vars[i]) == 0) {
					pass = 1;
					break;
				}
			}
		}
		if (user && pass) break;
	}
	free(tmp);
	
	return (user && pass);
}

int
decode_http(u_char *buf, int len)
{
	u_char *end;
	char *p, *auth, *query, *host;
	int i, method;
	
	Buf[0] = '\0';
	
	for ( ; (end = bufbuf(buf, len, "\r\n\r\n", 4)) != NULL;
	      len -= (end - buf), buf = end) {
		*end = '\0';
		end += 4;

		auth = query = host = NULL;

		if ((p = strtok(buf, "\r\n")) == NULL)
			continue;
		
		if ((method = http_method(&p)) == 0)
			continue;

		if (method == M_GET && (p = strchr(p, '?')) != NULL)
			query = p + 1;
		
		while ((p = strtok(NULL, "\r\n")) != NULL) {
			if (strncmp(p, "Host: ", 6) == 0) {
				host = p;
			}
			else if (strncmp(p, "Authorization: Basic ",21) == 0) {
				auth = p;
			}
			else if (method == M_POST) {
				if (strncmp(p, "Content-type: ", 14) == 0) {
					if (strncmp(p + 14, "application/"
						    "x-www-form-urlencoded",
						    33) != 0) {
						query = NULL;
						continue;
					}
				}
				else if (strncmp(p, "Content-length: ", 16)
					 == 0) {
					query = end;
					i = atoi(p + 16);
					if (i < 0 || (end - buf) + i > len)
						continue;
					end += i + 2;
					end[-2] = '\0';
				}
			}
		}
		if (auth || (query && grep_query_auth(query))) {
			if (Buf[0] != '\0')
				strlcat(Buf, "\n", sizeof(Buf));
			
			if (method == M_GET && auth)
				buf = http_req_dirname(buf);
			
			strlcat(Buf, buf, sizeof(Buf));
			strlcat(Buf, "\n", sizeof(Buf));

			if (host) {
				strlcat(Buf, host, sizeof(Buf));
				strlcat(Buf, "\n", sizeof(Buf));
			}
			if (auth) {
				strlcat(Buf, auth, sizeof(Buf));
				p = auth + 21;
				i = base64_pton(p, p, strlen(p));
				p[i] = '\0';
				i = strlen(Buf);
				snprintf(Buf + i, sizeof(Buf) - i,
					 " [%s]\n", p);
			}
			else if (method == M_POST && query) {
				i = strlen(Buf);
				snprintf(Buf + i, sizeof(Buf) - i,
					 "Content-type: application/"
					 "x-www-form-urlencoded\n"
					 "Content-length: %d\n%s\n",
					 strlen(query), query);
			}
		}
	}
	return (strlen(Buf));
}
