xref: /freebsd/sys/netinet/accf_http.c (revision fe267a559009cbf34f9341666fe4d88a92c02d5e)
1c398230bSWarner Losh /*-
2*fe267a55SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*fe267a55SPedro F. Giffuni  *
434b94e8bSAlfred Perlstein  * Copyright (c) 2000 Paycounter, Inc.
534b94e8bSAlfred Perlstein  * Author: Alfred Perlstein <alfred@paycounter.com>, <alfred@FreeBSD.org>
6a79b7128SAlfred Perlstein  * All rights reserved.
7a79b7128SAlfred Perlstein  *
8a79b7128SAlfred Perlstein  * Redistribution and use in source and binary forms, with or without
9a79b7128SAlfred Perlstein  * modification, are permitted provided that the following conditions
10a79b7128SAlfred Perlstein  * are met:
11a79b7128SAlfred Perlstein  * 1. Redistributions of source code must retain the above copyright
12a79b7128SAlfred Perlstein  *    notice, this list of conditions and the following disclaimer.
13a79b7128SAlfred Perlstein  * 2. Redistributions in binary form must reproduce the above copyright
14a79b7128SAlfred Perlstein  *    notice, this list of conditions and the following disclaimer in the
15a79b7128SAlfred Perlstein  *    documentation and/or other materials provided with the distribution.
16a79b7128SAlfred Perlstein  *
17a79b7128SAlfred Perlstein  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18a79b7128SAlfred Perlstein  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19a79b7128SAlfred Perlstein  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20a79b7128SAlfred Perlstein  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21a79b7128SAlfred Perlstein  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22a79b7128SAlfred Perlstein  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23a79b7128SAlfred Perlstein  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24a79b7128SAlfred Perlstein  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25a79b7128SAlfred Perlstein  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26a79b7128SAlfred Perlstein  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27a79b7128SAlfred Perlstein  * SUCH DAMAGE.
28a79b7128SAlfred Perlstein  */
29a79b7128SAlfred Perlstein 
304b421e2dSMike Silbersack #include <sys/cdefs.h>
314b421e2dSMike Silbersack __FBSDID("$FreeBSD$");
324b421e2dSMike Silbersack 
33a79b7128SAlfred Perlstein #define ACCEPT_FILTER_MOD
34a79b7128SAlfred Perlstein 
35a79b7128SAlfred Perlstein #include <sys/param.h>
36a79b7128SAlfred Perlstein #include <sys/kernel.h>
37960ed29cSSeigo Tanimura #include <sys/mbuf.h>
385dba30f1SPoul-Henning Kamp #include <sys/module.h>
39960ed29cSSeigo Tanimura #include <sys/signalvar.h>
4034b94e8bSAlfred Perlstein #include <sys/sysctl.h>
41a79b7128SAlfred Perlstein #include <sys/socketvar.h>
42a79b7128SAlfred Perlstein 
4334b94e8bSAlfred Perlstein /* check for GET/HEAD */
4474fb0ba7SJohn Baldwin static int sohashttpget(struct socket *so, void *arg, int waitflag);
4534b94e8bSAlfred Perlstein /* check for HTTP/1.0 or HTTP/1.1 */
4674fb0ba7SJohn Baldwin static int soparsehttpvers(struct socket *so, void *arg, int waitflag);
4734b94e8bSAlfred Perlstein /* check for end of HTTP/1.x request */
4874fb0ba7SJohn Baldwin static int soishttpconnected(struct socket *so, void *arg, int waitflag);
4934b94e8bSAlfred Perlstein /* strcmp on an mbuf chain */
5034b94e8bSAlfred Perlstein static int mbufstrcmp(struct mbuf *m, struct mbuf *npkt, int offset, char *cmp);
5134b94e8bSAlfred Perlstein /* strncmp on an mbuf chain */
5234b94e8bSAlfred Perlstein static int mbufstrncmp(struct mbuf *m, struct mbuf *npkt, int offset,
5334b94e8bSAlfred Perlstein 	int max, char *cmp);
5434b94e8bSAlfred Perlstein /* socketbuffer is full */
5534b94e8bSAlfred Perlstein static int sbfull(struct sockbuf *sb);
56a79b7128SAlfred Perlstein 
57a79b7128SAlfred Perlstein static struct accept_filter accf_http_filter = {
58a79b7128SAlfred Perlstein 	"httpready",
59a79b7128SAlfred Perlstein 	sohashttpget,
60a79b7128SAlfred Perlstein 	NULL,
61a79b7128SAlfred Perlstein 	NULL
62a79b7128SAlfred Perlstein };
63a79b7128SAlfred Perlstein 
64a79b7128SAlfred Perlstein static moduledata_t accf_http_mod = {
65a79b7128SAlfred Perlstein 	"accf_http",
66a79b7128SAlfred Perlstein 	accept_filt_generic_mod_event,
67a79b7128SAlfred Perlstein 	&accf_http_filter
68a79b7128SAlfred Perlstein };
69a79b7128SAlfred Perlstein 
70a79b7128SAlfred Perlstein DECLARE_MODULE(accf_http, accf_http_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
71a79b7128SAlfred Perlstein 
7234b94e8bSAlfred Perlstein static int parse_http_version = 1;
73a79b7128SAlfred Perlstein 
746472ac3dSEd Schouten static SYSCTL_NODE(_net_inet_accf, OID_AUTO, http, CTLFLAG_RW, 0,
7534b94e8bSAlfred Perlstein "HTTP accept filter");
7634b94e8bSAlfred Perlstein SYSCTL_INT(_net_inet_accf_http, OID_AUTO, parsehttpversion, CTLFLAG_RW,
7734b94e8bSAlfred Perlstein &parse_http_version, 1,
7834b94e8bSAlfred Perlstein "Parse http version so that non 1.x requests work");
7934b94e8bSAlfred Perlstein 
8034b94e8bSAlfred Perlstein #ifdef ACCF_HTTP_DEBUG
8134b94e8bSAlfred Perlstein #define DPRINT(fmt, args...)						\
8234b94e8bSAlfred Perlstein 	do {								\
8334b94e8bSAlfred Perlstein 		printf("%s:%d: " fmt "\n", __func__, __LINE__, ##args);	\
8434b94e8bSAlfred Perlstein 	} while (0)
8534b94e8bSAlfred Perlstein #else
8634b94e8bSAlfred Perlstein #define DPRINT(fmt, args...)
8734b94e8bSAlfred Perlstein #endif
8834b94e8bSAlfred Perlstein 
8934b94e8bSAlfred Perlstein static int
9034b94e8bSAlfred Perlstein sbfull(struct sockbuf *sb)
91a79b7128SAlfred Perlstein {
92a79b7128SAlfred Perlstein 
93ef104730SAlfred Perlstein 	DPRINT("sbfull, cc(%ld) >= hiwat(%ld): %d, "
94ef104730SAlfred Perlstein 	    "mbcnt(%ld) >= mbmax(%ld): %d",
9534b94e8bSAlfred Perlstein 	    sb->sb_cc, sb->sb_hiwat, sb->sb_cc >= sb->sb_hiwat,
9634b94e8bSAlfred Perlstein 	    sb->sb_mbcnt, sb->sb_mbmax, sb->sb_mbcnt >= sb->sb_mbmax);
97cfa6009eSGleb Smirnoff 	return (sbused(sb) >= sb->sb_hiwat || sb->sb_mbcnt >= sb->sb_mbmax);
9834b94e8bSAlfred Perlstein }
9934b94e8bSAlfred Perlstein 
10034b94e8bSAlfred Perlstein /*
10134b94e8bSAlfred Perlstein  * start at mbuf m, (must provide npkt if exists)
10234b94e8bSAlfred Perlstein  * starting at offset in m compare characters in mbuf chain for 'cmp'
10334b94e8bSAlfred Perlstein  */
10434b94e8bSAlfred Perlstein static int
10534b94e8bSAlfred Perlstein mbufstrcmp(struct mbuf *m, struct mbuf *npkt, int offset, char *cmp)
10634b94e8bSAlfred Perlstein {
10734b94e8bSAlfred Perlstein 	struct mbuf *n;
10834b94e8bSAlfred Perlstein 
10934b94e8bSAlfred Perlstein 	for (; m != NULL; m = n) {
11034b94e8bSAlfred Perlstein 		n = npkt;
11134b94e8bSAlfred Perlstein 		if (npkt)
11234b94e8bSAlfred Perlstein 			npkt = npkt->m_nextpkt;
11334b94e8bSAlfred Perlstein 		for (; m; m = m->m_next) {
11434b94e8bSAlfred Perlstein 			for (; offset < m->m_len; offset++, cmp++) {
115ef104730SAlfred Perlstein 				if (*cmp == '\0')
11634b94e8bSAlfred Perlstein 					return (1);
117ef104730SAlfred Perlstein 				else if (*cmp != *(mtod(m, char *) + offset))
11834b94e8bSAlfred Perlstein 					return (0);
119a79b7128SAlfred Perlstein 			}
12059017610SAlfred Perlstein 			if (*cmp == '\0')
12159017610SAlfred Perlstein 				return (1);
12234b94e8bSAlfred Perlstein 			offset = 0;
123a79b7128SAlfred Perlstein 		}
12434b94e8bSAlfred Perlstein 	}
12534b94e8bSAlfred Perlstein 	return (0);
12634b94e8bSAlfred Perlstein }
12734b94e8bSAlfred Perlstein 
12834b94e8bSAlfred Perlstein /*
12934b94e8bSAlfred Perlstein  * start at mbuf m, (must provide npkt if exists)
13034b94e8bSAlfred Perlstein  * starting at offset in m compare characters in mbuf chain for 'cmp'
13134b94e8bSAlfred Perlstein  * stop at 'max' characters
13234b94e8bSAlfred Perlstein  */
13334b94e8bSAlfred Perlstein static int
13434b94e8bSAlfred Perlstein mbufstrncmp(struct mbuf *m, struct mbuf *npkt, int offset, int max, char *cmp)
13534b94e8bSAlfred Perlstein {
13634b94e8bSAlfred Perlstein 	struct mbuf *n;
13734b94e8bSAlfred Perlstein 
13834b94e8bSAlfred Perlstein 	for (; m != NULL; m = n) {
13934b94e8bSAlfred Perlstein 		n = npkt;
14034b94e8bSAlfred Perlstein 		if (npkt)
14134b94e8bSAlfred Perlstein 			npkt = npkt->m_nextpkt;
14234b94e8bSAlfred Perlstein 		for (; m; m = m->m_next) {
14334b94e8bSAlfred Perlstein 			for (; offset < m->m_len; offset++, cmp++, max--) {
144ef104730SAlfred Perlstein 				if (max == 0 || *cmp == '\0')
14534b94e8bSAlfred Perlstein 					return (1);
146ef104730SAlfred Perlstein 				else if (*cmp != *(mtod(m, char *) + offset))
14734b94e8bSAlfred Perlstein 					return (0);
14834b94e8bSAlfred Perlstein 			}
14959017610SAlfred Perlstein 			if (max == 0 || *cmp == '\0')
15059017610SAlfred Perlstein 				return (1);
15134b94e8bSAlfred Perlstein 			offset = 0;
15234b94e8bSAlfred Perlstein 		}
15334b94e8bSAlfred Perlstein 	}
15434b94e8bSAlfred Perlstein 	return (0);
15534b94e8bSAlfred Perlstein }
15634b94e8bSAlfred Perlstein 
15734b94e8bSAlfred Perlstein #define STRSETUP(sptr, slen, str)					\
15834b94e8bSAlfred Perlstein 	do {								\
15934b94e8bSAlfred Perlstein 		sptr = str;						\
16034b94e8bSAlfred Perlstein 		slen = sizeof(str) - 1;					\
16134b94e8bSAlfred Perlstein 	} while(0)
162a79b7128SAlfred Perlstein 
16374fb0ba7SJohn Baldwin static int
164a79b7128SAlfred Perlstein sohashttpget(struct socket *so, void *arg, int waitflag)
165a79b7128SAlfred Perlstein {
166a79b7128SAlfred Perlstein 
167cfa6009eSGleb Smirnoff 	if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) == 0 &&
168cfa6009eSGleb Smirnoff 	    !sbfull(&so->so_rcv)) {
169a79b7128SAlfred Perlstein 		struct mbuf *m;
17034b94e8bSAlfred Perlstein 		char *cmp;
17134b94e8bSAlfred Perlstein 		int	cmplen, cc;
172a79b7128SAlfred Perlstein 
173a79b7128SAlfred Perlstein 		m = so->so_rcv.sb_mb;
174cfa6009eSGleb Smirnoff 		cc = sbavail(&so->so_rcv) - 1;
17534b94e8bSAlfred Perlstein 		if (cc < 1)
17674fb0ba7SJohn Baldwin 			return (SU_OK);
17734b94e8bSAlfred Perlstein 		switch (*mtod(m, char *)) {
17834b94e8bSAlfred Perlstein 		case 'G':
17934b94e8bSAlfred Perlstein 			STRSETUP(cmp, cmplen, "ET ");
18034b94e8bSAlfred Perlstein 			break;
18134b94e8bSAlfred Perlstein 		case 'H':
18234b94e8bSAlfred Perlstein 			STRSETUP(cmp, cmplen, "EAD ");
18334b94e8bSAlfred Perlstein 			break;
18434b94e8bSAlfred Perlstein 		default:
18534b94e8bSAlfred Perlstein 			goto fallout;
18634b94e8bSAlfred Perlstein 		}
18734b94e8bSAlfred Perlstein 		if (cc < cmplen) {
18834b94e8bSAlfred Perlstein 			if (mbufstrncmp(m, m->m_nextpkt, 1, cc, cmp) == 1) {
18934b94e8bSAlfred Perlstein 				DPRINT("short cc (%d) but mbufstrncmp ok", cc);
19074fb0ba7SJohn Baldwin 				return (SU_OK);
19134b94e8bSAlfred Perlstein 			} else {
19234b94e8bSAlfred Perlstein 				DPRINT("short cc (%d) mbufstrncmp failed", cc);
19334b94e8bSAlfred Perlstein 				goto fallout;
19434b94e8bSAlfred Perlstein 			}
19534b94e8bSAlfred Perlstein 		}
19634b94e8bSAlfred Perlstein 		if (mbufstrcmp(m, m->m_nextpkt, 1, cmp) == 1) {
19734b94e8bSAlfred Perlstein 			DPRINT("mbufstrcmp ok");
19834b94e8bSAlfred Perlstein 			if (parse_http_version == 0)
19974fb0ba7SJohn Baldwin 				return (soishttpconnected(so, arg, waitflag));
20034b94e8bSAlfred Perlstein 			else
20174fb0ba7SJohn Baldwin 				return (soparsehttpvers(so, arg, waitflag));
202a79b7128SAlfred Perlstein 		}
20334b94e8bSAlfred Perlstein 		DPRINT("mbufstrcmp bad");
2044cc20ab1SSeigo Tanimura 	}
205a79b7128SAlfred Perlstein 
20634b94e8bSAlfred Perlstein fallout:
20734b94e8bSAlfred Perlstein 	DPRINT("fallout");
20874fb0ba7SJohn Baldwin 	return (SU_ISCONNECTED);
209a79b7128SAlfred Perlstein }
210a79b7128SAlfred Perlstein 
21174fb0ba7SJohn Baldwin static int
21234b94e8bSAlfred Perlstein soparsehttpvers(struct socket *so, void *arg, int waitflag)
21334b94e8bSAlfred Perlstein {
21434b94e8bSAlfred Perlstein 	struct mbuf *m, *n;
21534b94e8bSAlfred Perlstein 	int	i, cc, spaces, inspaces;
21634b94e8bSAlfred Perlstein 
217c0b99ffaSRobert Watson 	if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv))
21834b94e8bSAlfred Perlstein 		goto fallout;
21934b94e8bSAlfred Perlstein 
22034b94e8bSAlfred Perlstein 	m = so->so_rcv.sb_mb;
221cfa6009eSGleb Smirnoff 	cc = sbavail(&so->so_rcv);
22234b94e8bSAlfred Perlstein 	inspaces = spaces = 0;
22334b94e8bSAlfred Perlstein 	for (m = so->so_rcv.sb_mb; m; m = n) {
22434b94e8bSAlfred Perlstein 		n = m->m_nextpkt;
22534b94e8bSAlfred Perlstein 		for (; m; m = m->m_next) {
22634b94e8bSAlfred Perlstein 			for (i = 0; i < m->m_len; i++, cc--) {
22734b94e8bSAlfred Perlstein 				switch (*(mtod(m, char *) + i)) {
22834b94e8bSAlfred Perlstein 				case ' ':
229ef104730SAlfred Perlstein 					/* tabs? '\t' */
23034b94e8bSAlfred Perlstein 					if (!inspaces) {
23134b94e8bSAlfred Perlstein 						spaces++;
23234b94e8bSAlfred Perlstein 						inspaces = 1;
23334b94e8bSAlfred Perlstein 					}
23434b94e8bSAlfred Perlstein 					break;
23534b94e8bSAlfred Perlstein 				case '\r':
23634b94e8bSAlfred Perlstein 				case '\n':
23734b94e8bSAlfred Perlstein 					DPRINT("newline");
23834b94e8bSAlfred Perlstein 					goto fallout;
23934b94e8bSAlfred Perlstein 				default:
240ef104730SAlfred Perlstein 					if (spaces != 2) {
24134b94e8bSAlfred Perlstein 						inspaces = 0;
24234b94e8bSAlfred Perlstein 						break;
24334b94e8bSAlfred Perlstein 					}
244ef104730SAlfred Perlstein 
245ef104730SAlfred Perlstein 					/*
246ef104730SAlfred Perlstein 					 * if we don't have enough characters
247ef104730SAlfred Perlstein 					 * left (cc < sizeof("HTTP/1.0") - 1)
248ef104730SAlfred Perlstein 					 * then see if the remaining ones
249ef104730SAlfred Perlstein 					 * are a request we can parse.
250ef104730SAlfred Perlstein 					 */
251ef104730SAlfred Perlstein 					if (cc < sizeof("HTTP/1.0") - 1) {
252ef104730SAlfred Perlstein 						if (mbufstrncmp(m, n, i, cc,
253ef104730SAlfred Perlstein 							"HTTP/1.") == 1) {
254ef104730SAlfred Perlstein 							DPRINT("ok");
255ef104730SAlfred Perlstein 							goto readmore;
256ef104730SAlfred Perlstein 						} else {
257ef104730SAlfred Perlstein 							DPRINT("bad");
258ef104730SAlfred Perlstein 							goto fallout;
259ef104730SAlfred Perlstein 						}
260ef104730SAlfred Perlstein 					} else if (
261ef104730SAlfred Perlstein 					    mbufstrcmp(m, n, i, "HTTP/1.0") ||
262ef104730SAlfred Perlstein 					    mbufstrcmp(m, n, i, "HTTP/1.1")) {
263ef104730SAlfred Perlstein 						DPRINT("ok");
26474fb0ba7SJohn Baldwin 						return (soishttpconnected(so,
26574fb0ba7SJohn Baldwin 						    arg, waitflag));
266ef104730SAlfred Perlstein 					} else {
267ef104730SAlfred Perlstein 						DPRINT("bad");
268ef104730SAlfred Perlstein 						goto fallout;
269ef104730SAlfred Perlstein 					}
270ef104730SAlfred Perlstein 				}
27134b94e8bSAlfred Perlstein 			}
27234b94e8bSAlfred Perlstein 		}
27334b94e8bSAlfred Perlstein 	}
27434b94e8bSAlfred Perlstein readmore:
27534b94e8bSAlfred Perlstein 	DPRINT("readmore");
27634b94e8bSAlfred Perlstein 	/*
27734b94e8bSAlfred Perlstein 	 * if we hit here we haven't hit something
27834b94e8bSAlfred Perlstein 	 * we don't understand or a newline, so try again
27934b94e8bSAlfred Perlstein 	 */
28074fb0ba7SJohn Baldwin 	soupcall_set(so, SO_RCV, soparsehttpvers, arg);
28174fb0ba7SJohn Baldwin 	return (SU_OK);
28234b94e8bSAlfred Perlstein 
28334b94e8bSAlfred Perlstein fallout:
28434b94e8bSAlfred Perlstein 	DPRINT("fallout");
28574fb0ba7SJohn Baldwin 	return (SU_ISCONNECTED);
28634b94e8bSAlfred Perlstein }
28734b94e8bSAlfred Perlstein 
28834b94e8bSAlfred Perlstein 
28934b94e8bSAlfred Perlstein #define NCHRS 3
29034b94e8bSAlfred Perlstein 
29174fb0ba7SJohn Baldwin static int
292a79b7128SAlfred Perlstein soishttpconnected(struct socket *so, void *arg, int waitflag)
293a79b7128SAlfred Perlstein {
294a79b7128SAlfred Perlstein 	char a, b, c;
29534b94e8bSAlfred Perlstein 	struct mbuf *m, *n;
29634b94e8bSAlfred Perlstein 	int ccleft, copied;
297a79b7128SAlfred Perlstein 
29834b94e8bSAlfred Perlstein 	DPRINT("start");
299c0b99ffaSRobert Watson 	if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv))
30034b94e8bSAlfred Perlstein 		goto gotit;
301a79b7128SAlfred Perlstein 
30234b94e8bSAlfred Perlstein 	/*
30334b94e8bSAlfred Perlstein 	 * Walk the socketbuffer and copy the last NCHRS (3) into a, b, and c
30434b94e8bSAlfred Perlstein 	 * copied - how much we've copied so far
30534b94e8bSAlfred Perlstein 	 * ccleft - how many bytes remaining in the socketbuffer
30634b94e8bSAlfred Perlstein 	 * just loop over the mbufs subtracting from 'ccleft' until we only
30734b94e8bSAlfred Perlstein 	 * have NCHRS left
30834b94e8bSAlfred Perlstein 	 */
30934b94e8bSAlfred Perlstein 	copied = 0;
310cfa6009eSGleb Smirnoff 	ccleft = sbavail(&so->so_rcv);
31134b94e8bSAlfred Perlstein 	if (ccleft < NCHRS)
31234b94e8bSAlfred Perlstein 		goto readmore;
31334b94e8bSAlfred Perlstein 	a = b = c = '\0';
31434b94e8bSAlfred Perlstein 	for (m = so->so_rcv.sb_mb; m; m = n) {
31534b94e8bSAlfred Perlstein 		n = m->m_nextpkt;
31634b94e8bSAlfred Perlstein 		for (; m; m = m->m_next) {
31734b94e8bSAlfred Perlstein 			ccleft -= m->m_len;
31834b94e8bSAlfred Perlstein 			if (ccleft <= NCHRS) {
31934b94e8bSAlfred Perlstein 				char *src;
32034b94e8bSAlfred Perlstein 				int tocopy;
321a79b7128SAlfred Perlstein 
32234b94e8bSAlfred Perlstein 				tocopy = (NCHRS - ccleft) - copied;
32334b94e8bSAlfred Perlstein 				src = mtod(m, char *) + (m->m_len - tocopy);
32434b94e8bSAlfred Perlstein 
32534b94e8bSAlfred Perlstein 				while (tocopy--) {
32634b94e8bSAlfred Perlstein 					switch (copied++) {
327a79b7128SAlfred Perlstein 					case 0:
32834b94e8bSAlfred Perlstein 						a = *src++;
329a79b7128SAlfred Perlstein 						break;
33034b94e8bSAlfred Perlstein 					case 1:
33134b94e8bSAlfred Perlstein 						b = *src++;
33234b94e8bSAlfred Perlstein 						break;
33334b94e8bSAlfred Perlstein 					case 2:
33434b94e8bSAlfred Perlstein 						c = *src++;
335a79b7128SAlfred Perlstein 						break;
336a79b7128SAlfred Perlstein 					}
337a79b7128SAlfred Perlstein 				}
33834b94e8bSAlfred Perlstein 			}
33934b94e8bSAlfred Perlstein 		}
34034b94e8bSAlfred Perlstein 	}
341a79b7128SAlfred Perlstein 	if (c == '\n' && (b == '\n' || (b == '\r' && a == '\n'))) {
342a79b7128SAlfred Perlstein 		/* we have all request headers */
34334b94e8bSAlfred Perlstein 		goto gotit;
34434b94e8bSAlfred Perlstein 	}
34534b94e8bSAlfred Perlstein 
34634b94e8bSAlfred Perlstein readmore:
34774fb0ba7SJohn Baldwin 	soupcall_set(so, SO_RCV, soishttpconnected, arg);
34874fb0ba7SJohn Baldwin 	return (SU_OK);
349a79b7128SAlfred Perlstein 
35034b94e8bSAlfred Perlstein gotit:
35174fb0ba7SJohn Baldwin 	return (SU_ISCONNECTED);
352a79b7128SAlfred Perlstein }
353