accf_http.c revision 61837
1117395Skan/*-
2169689Skan * Copyright (c) 2000 Alfred Perlstein <alfred@FreeBSD.org>
3117395Skan * All rights reserved.
4117395Skan *
5117395Skan * Redistribution and use in source and binary forms, with or without
6169689Skan * modification, are permitted provided that the following conditions
7117395Skan * are met:
8132718Skan * 1. Redistributions of source code must retain the above copyright
9117395Skan *    notice, this list of conditions and the following disclaimer.
10132718Skan * 2. Redistributions in binary form must reproduce the above copyright
11132718Skan *    notice, this list of conditions and the following disclaimer in the
12132718Skan *    documentation and/or other materials provided with the distribution.
13132718Skan *
14117395Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15132718Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16132718Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17132718Skan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18132718Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19117395Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20132718Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21132718Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22169689Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24117395Skan * SUCH DAMAGE.
25117395Skan *
26117395Skan *	$FreeBSD: head/sys/netinet/accf_http.c 61837 2000-06-20 01:09:23Z alfred $
27132718Skan */
28132718Skan
29117395Skan#define ACCEPT_FILTER_MOD
30117395Skan
31169689Skan#include <sys/param.h>
32117395Skan#include <sys/systm.h>
33169689Skan#include <sys/sysproto.h>
34169689Skan#include <sys/kernel.h>
35117395Skan#include <sys/proc.h>
36169689Skan#include <sys/malloc.h>
37169689Skan#include <sys/unistd.h>
38117395Skan#include <sys/file.h>
39169689Skan#include <sys/fcntl.h>
40169689Skan#include <sys/protosw.h>
41117395Skan#include <sys/socket.h>
42117395Skan#include <sys/socketvar.h>
43117395Skan#include <sys/stat.h>
44117395Skan#include <sys/mbuf.h>
45117395Skan#include <sys/resource.h>
46117395Skan#include <sys/sysent.h>
47117395Skan#include <sys/resourcevar.h>
48117395Skan
49117395Skan/*
50117395Skan * XXX: doesn't work with 0.9 requests, make a seperate filter
51169689Skan * based on this one if you want to decode those.
52169689Skan */
53169689Skan
54169689Skan/* check for GET */
55117395Skanstatic void sohashttpget(struct socket *so, void *arg, int waitflag);
56117395Skan/* check for end of HTTP request */
57117395Skanstatic void soishttpconnected(struct socket *so, void *arg, int waitflag);
58132718Skanstatic char sbindex(struct mbuf **mp, int *begin, int end);
59117395Skan
60117395Skanstatic struct accept_filter accf_http_filter = {
61117395Skan	"httpready",
62117395Skan	sohashttpget,
63117395Skan	NULL,
64117395Skan	NULL
65169689Skan};
66117395Skan
67169689Skanstatic moduledata_t accf_http_mod = {
68117395Skan	"accf_http",
69169689Skan	accept_filt_generic_mod_event,
70117395Skan	&accf_http_filter
71117395Skan};
72169689Skan
73117395SkanDECLARE_MODULE(accf_http, accf_http_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
74117395Skan
75169689Skan
76169689Skanstatic char
77117395Skansbindex(struct mbuf **mp, int *begin, int end)
78169689Skan{
79117395Skan	struct mbuf *m = *mp;
80117395Skan	int diff = end - *begin + 1;
81117395Skan
82117395Skan	while (m->m_len < diff) {
83117395Skan		*begin += m->m_len;
84117395Skan		diff -= m->m_len;
85117395Skan		if (m->m_next) {
86117395Skan			m = m->m_next;
87117395Skan		} else if (m->m_nextpkt) {
88117395Skan			m = m->m_nextpkt;
89132718Skan		} else {
90117395Skan			/* only happens if end > data in socket buffer */
91117395Skan			panic("sbindex: not enough data");
92117395Skan		}
93117395Skan	}
94117395Skan	*mp = m;
95117395Skan	return *(mtod(m, char *) + diff - 1);
96117395Skan}
97169689Skan
98169689Skanstatic void
99169689Skansohashttpget(struct socket *so, void *arg, int waitflag)
100169689Skan{
101117395Skan
102117395Skan	if ((so->so_state & SS_CANTRCVMORE) == 0) {
103169689Skan		struct mbuf *m;
104169689Skan
105169689Skan		if (so->so_rcv.sb_cc < 6)
106169689Skan			return;
107169689Skan		m = so->so_rcv.sb_mb;
108169689Skan		if (bcmp(mtod(m, char *), "GET ", 4) == 0) {
109117395Skan			soishttpconnected(so, arg, waitflag);
110117395Skan			return;
111117395Skan		}
112146895Skan	}
113146895Skan
114146895Skan	so->so_upcall = NULL;
115146895Skan	so->so_rcv.sb_flags &= ~SB_UPCALL;
116146895Skan	soisconnected(so);
117146895Skan	return;
118146895Skan}
119146895Skan
120146895Skanstatic void
121117395Skansoishttpconnected(struct socket *so, void *arg, int waitflag)
122117395Skan{
123117395Skan	char a, b, c;
124117395Skan	struct mbuf *y, *z;
125117395Skan
126117395Skan	if ((so->so_state & SS_CANTRCVMORE) == 0) {
127117395Skan		/* seek to end and keep track of next to last mbuf */
128169689Skan		y = so->so_rcv.sb_mb;
129169689Skan		while (y->m_nextpkt)
130169689Skan			y = y->m_nextpkt;
131117395Skan		z = y;
132117395Skan		while (y->m_next) {
133117395Skan			z = y;
134117395Skan			y = y->m_next;
135117395Skan		}
136117395Skan
137117395Skan		if (z->m_len + y->m_len > 2) {
138117395Skan			int index = y->m_len - 1;
139117395Skan
140117395Skan			c = *(mtod(y, char *) + index--);
141117395Skan			switch (index) {
142117395Skan			case -1:
143117395Skan				y = z;
144117395Skan				index = y->m_len - 1;
145117395Skan				b = *(mtod(y, char *) + index--);
146117395Skan				break;
147117395Skan			case 0:
148117395Skan				b = *(mtod(y, char *) + index--);
149117395Skan				y = z;
150117395Skan				index = y->m_len - 1;
151117395Skan				break;
152117395Skan			default:
153169689Skan				b = *(mtod(y, char *) + index--);
154169689Skan				break;
155169689Skan			}
156169689Skan			a = *(mtod(y, char *) + index--);
157117395Skan		} else {
158169689Skan			int begin = 0;
159169689Skan			int end = so->so_rcv.sb_cc - 3;
160169689Skan
161169689Skan			y = so->so_rcv.sb_mb;
162169689Skan			a = sbindex(&y, &begin, end++);
163169689Skan			b = sbindex(&y, &begin, end++);
164169689Skan			c = sbindex(&y, &begin, end++);
165169689Skan		}
166169689Skan
167169689Skan		if (c == '\n' && (b == '\n' || (b == '\r' && a == '\n'))) {
168169689Skan			/* we have all request headers */
169169689Skan			goto done;
170169689Skan		} else {
171169689Skan			/* still need more data */
172169689Skan			so->so_upcall = soishttpconnected;
173169689Skan			so->so_rcv.sb_flags |= SB_UPCALL;
174169689Skan			return;
175169689Skan		}
176169689Skan	}
177169689Skan
178169689Skandone:
179169689Skan	so->so_upcall = NULL;
180169689Skan	so->so_rcv.sb_flags &= ~SB_UPCALL;
181169689Skan	soisconnected(so);
182169689Skan	return;
183169689Skan}
184169689Skan