xref: /freebsd/sys/netinet/accf_http.c (revision b601c69bdbe8755d26570261d7fd4c02ee4eff74)
1 /*-
2  * Copyright (c) 2000 Alfred Perlstein <alfred@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *	$FreeBSD$
27  */
28 
29 #define ACCEPT_FILTER_MOD
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/sysproto.h>
34 #include <sys/kernel.h>
35 #include <sys/proc.h>
36 #include <sys/malloc.h>
37 #include <sys/unistd.h>
38 #include <sys/file.h>
39 #include <sys/fcntl.h>
40 #include <sys/protosw.h>
41 #include <sys/socket.h>
42 #include <sys/socketvar.h>
43 #include <sys/stat.h>
44 #include <sys/mbuf.h>
45 #include <sys/resource.h>
46 #include <sys/sysent.h>
47 #include <sys/resourcevar.h>
48 
49 /*
50  * XXX: doesn't work with 0.9 requests, make a seperate filter
51  * based on this one if you want to decode those.
52  */
53 
54 /* check for GET */
55 static void sohashttpget(struct socket *so, void *arg, int waitflag);
56 /* check for end of HTTP request */
57 static void soishttpconnected(struct socket *so, void *arg, int waitflag);
58 static char sbindex(struct mbuf **mp, int *begin, int end);
59 
60 static struct accept_filter accf_http_filter = {
61 	"httpready",
62 	sohashttpget,
63 	NULL,
64 	NULL
65 };
66 
67 static moduledata_t accf_http_mod = {
68 	"accf_http",
69 	accept_filt_generic_mod_event,
70 	&accf_http_filter
71 };
72 
73 DECLARE_MODULE(accf_http, accf_http_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
74 
75 
76 static char
77 sbindex(struct mbuf **mp, int *begin, int end)
78 {
79 	struct mbuf *m = *mp;
80 	int diff = end - *begin + 1;
81 
82 	while (m->m_len < diff) {
83 		*begin += m->m_len;
84 		diff -= m->m_len;
85 		if (m->m_next) {
86 			m = m->m_next;
87 		} else if (m->m_nextpkt) {
88 			m = m->m_nextpkt;
89 		} else {
90 			/* only happens if end > data in socket buffer */
91 			panic("sbindex: not enough data");
92 		}
93 	}
94 	*mp = m;
95 	return *(mtod(m, char *) + diff - 1);
96 }
97 
98 static void
99 sohashttpget(struct socket *so, void *arg, int waitflag)
100 {
101 
102 	if ((so->so_state & SS_CANTRCVMORE) == 0) {
103 		struct mbuf *m;
104 
105 		if (so->so_rcv.sb_cc < 6)
106 			return;
107 		m = so->so_rcv.sb_mb;
108 		if (bcmp(mtod(m, char *), "GET ", 4) == 0) {
109 			soishttpconnected(so, arg, waitflag);
110 			return;
111 		}
112 	}
113 
114 	so->so_upcall = NULL;
115 	so->so_rcv.sb_flags &= ~SB_UPCALL;
116 	soisconnected(so);
117 	return;
118 }
119 
120 static void
121 soishttpconnected(struct socket *so, void *arg, int waitflag)
122 {
123 	char a, b, c;
124 	struct mbuf *y, *z;
125 
126 	if ((so->so_state & SS_CANTRCVMORE) == 0) {
127 		/* seek to end and keep track of next to last mbuf */
128 		y = so->so_rcv.sb_mb;
129 		while (y->m_nextpkt)
130 			y = y->m_nextpkt;
131 		z = y;
132 		while (y->m_next) {
133 			z = y;
134 			y = y->m_next;
135 		}
136 
137 		if (z->m_len + y->m_len > 2) {
138 			int index = y->m_len - 1;
139 
140 			c = *(mtod(y, char *) + index--);
141 			switch (index) {
142 			case -1:
143 				y = z;
144 				index = y->m_len - 1;
145 				b = *(mtod(y, char *) + index--);
146 				break;
147 			case 0:
148 				b = *(mtod(y, char *) + index--);
149 				y = z;
150 				index = y->m_len - 1;
151 				break;
152 			default:
153 				b = *(mtod(y, char *) + index--);
154 				break;
155 			}
156 			a = *(mtod(y, char *) + index--);
157 		} else {
158 			int begin = 0;
159 			int end = so->so_rcv.sb_cc - 3;
160 
161 			y = so->so_rcv.sb_mb;
162 			a = sbindex(&y, &begin, end++);
163 			b = sbindex(&y, &begin, end++);
164 			c = sbindex(&y, &begin, end++);
165 		}
166 
167 		if (c == '\n' && (b == '\n' || (b == '\r' && a == '\n'))) {
168 			/* we have all request headers */
169 			goto done;
170 		} else {
171 			/* still need more data */
172 			so->so_upcall = soishttpconnected;
173 			so->so_rcv.sb_flags |= SB_UPCALL;
174 			return;
175 		}
176 	}
177 
178 done:
179 	so->so_upcall = NULL;
180 	so->so_rcv.sb_flags &= ~SB_UPCALL;
181 	soisconnected(so);
182 	return;
183 }
184