Home | History | Annotate | Line # | Download | only in lib
      1 /*	$NetBSD: load_http.c,v 1.3 2012/07/22 14:27:36 darrenr Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 2012 by Darren Reed.
      5  *
      6  * See the IPFILTER.LICENCE file for details on licencing.
      7  *
      8  * Id: load_http.c,v 1.1.1.2 2012/07/22 13:44:39 darrenr
      9  */
     10 
     11 #include "ipf.h"
     12 #include <ctype.h>
     13 
     14 /*
     15  * Because the URL can be included twice into the buffer, once as the
     16  * full path for the "GET" and once as the "Host:", the buffer it is
     17  * put in needs to be larger than 512*2 to make room for the supporting
     18  * text. Why not just use snprintf and truncate? The warning about the
     19  * URL being too long tells you something is wrong and does not fetch
     20  * any data - just truncating the URL (with snprintf, etc) and sending
     21  * that to the server is allowing an unknown and unintentioned action
     22  * to happen.
     23  */
     24 #define	MAX_URL_LEN	512
     25 #define	LOAD_BUFSIZE	(MAX_URL_LEN * 2 + 128)
     26 
     27 /*
     28  * Format expected is one addres per line, at the start of each line.
     29  */
     30 alist_t *
     31 load_http(char *url)
     32 {
     33 	int fd, len, left, port, endhdr, removed, linenum = 0;
     34 	char *s, *t, *u, buffer[LOAD_BUFSIZE], *myurl;
     35 	alist_t *a, *rtop, *rbot;
     36 	int rem;
     37 
     38 	/*
     39 	 * More than this would just be absurd.
     40 	 */
     41 	if (strlen(url) > MAX_URL_LEN) {
     42 		fprintf(stderr, "load_http has a URL > %d bytes?!\n",
     43 			MAX_URL_LEN);
     44 		return NULL;
     45 	}
     46 
     47 	fd = -1;
     48 	rtop = NULL;
     49 	rbot = NULL;
     50 
     51 	myurl = strdup(url);
     52 	if (myurl == NULL)
     53 		goto done;
     54 
     55 	rem = sizeof(buffer);
     56 	left = snprintf(buffer, rem, "GET %s HTTP/1.0\r\n", url);
     57 	if (left < 0 || left > rem)
     58 		goto done;
     59 	rem -= left;
     60 
     61 	s = myurl + 7;			/* http:// */
     62 	t = strchr(s, '/');
     63 	if (t == NULL) {
     64 		fprintf(stderr, "load_http has a malformed URL '%s'\n", url);
     65 		goto done;
     66 	}
     67 	*t++ = '\0';
     68 
     69 	/*
     70 	 * 10 is the length of 'Host: \r\n\r\n' below.
     71 	 */
     72 	if (strlen(s) + strlen(buffer) + 10 > sizeof(buffer)) {
     73 		fprintf(stderr, "load_http has a malformed URL '%s'\n", url);
     74 		free(myurl);
     75 		return NULL;
     76 	}
     77 
     78 	u = strchr(s, '@');
     79 	if (u != NULL)
     80 		s = u + 1;		/* AUTH */
     81 
     82 	left = snprintf(buffer + left, rem, "Host: %s\r\n\r\n", s);
     83 	if (left < 0 || left > rem)
     84 		goto done;
     85 	rem -= left;
     86 
     87 	u = strchr(s, ':');
     88 	if (u != NULL) {
     89 		*u++ = '\0';
     90 		port = atoi(u);
     91 		if (port < 0 || port > 65535)
     92 			goto done;
     93 	} else {
     94 		port = 80;
     95 	}
     96 
     97 
     98 	fd = connecttcp(s, port);
     99 	if (fd == -1)
    100 		goto done;
    101 
    102 	len = strlen(buffer);
    103 	if (write(fd, buffer, len) != len)
    104 		goto done;
    105 
    106 	s = buffer;
    107 	endhdr = 0;
    108 	left = sizeof(buffer) - 1;
    109 
    110 	while ((len = read(fd, s, left)) > 0) {
    111 		s[len] = '\0';
    112 		left -= len;
    113 		s += len;
    114 
    115 		if (endhdr >= 0) {
    116 			if (endhdr == 0) {
    117 				t = strchr(buffer, ' ');
    118 				if (t == NULL)
    119 					continue;
    120 				t++;
    121 				if (*t != '2')
    122 					break;
    123 			}
    124 
    125 			u = buffer;
    126 			while ((t = strchr(u, '\r')) != NULL) {
    127 				if (t == u) {
    128 					if (*(t + 1) == '\n') {
    129 						u = t + 2;
    130 						endhdr = -1;
    131 						break;
    132 					} else
    133 						t++;
    134 				} else if (*(t + 1) == '\n') {
    135 					endhdr++;
    136 					u = t + 2;
    137 				} else
    138 					u = t + 1;
    139 			}
    140 			if (endhdr >= 0)
    141 				continue;
    142 			removed = (u - buffer) + 1;
    143 			memmove(buffer, u, (sizeof(buffer) - left) - removed);
    144 			s -= removed;
    145 			left += removed;
    146 		}
    147 
    148 		do {
    149 			t = strchr(buffer, '\n');
    150 			if (t == NULL)
    151 				break;
    152 
    153 			linenum++;
    154 			*t = '\0';
    155 
    156 			for (u = buffer; isdigit((unsigned char)*u) ||
    157 			    (*u == '.'); u++)
    158 				continue;
    159 			if (*u == '/') {
    160 				char *slash;
    161 
    162 				slash = u;
    163 				u++;
    164 				while (isdigit((unsigned char)*u))
    165 					u++;
    166 				if (!isspace((unsigned char)*u) && *u)
    167 					u = slash;
    168 			}
    169 
    170 			/*
    171 			 * Remove comment and continue to the next line if
    172 			 * the comment is at the start of the line.
    173 			 */
    174 			u = strchr(buffer, '#');
    175 			if (u != NULL) {
    176 				*u = '\0';
    177 				if (u == buffer)
    178 					continue;
    179 			}
    180 
    181 			/*
    182 			 * Trim off tailing white spaces, will include \r
    183 			 */
    184 			for (u = t - 1; (u >= buffer) && ISSPACE(*u); u--)
    185 				*u = '\0';
    186 
    187 			a = alist_new(AF_UNSPEC, buffer);
    188 			if (a != NULL) {
    189 				if (rbot != NULL)
    190 					rbot->al_next = a;
    191 				else
    192 					rtop = a;
    193 				rbot = a;
    194 			} else {
    195 				fprintf(stderr,
    196 					"%s:%d unrecognised content:%s\n",
    197 					url, linenum, buffer);
    198 			}
    199 
    200 			t++;
    201 			removed = t - buffer;
    202 			memmove(buffer, t, sizeof(buffer) - left - removed);
    203 			s -= removed;
    204 			left += removed;
    205 
    206 		} while (1);
    207 	}
    208 
    209 done:
    210 	if (myurl != NULL)
    211 		free(myurl);
    212 	if (fd != -1)
    213 		close(fd);
    214 	return rtop;
    215 }
    216