xref: /freebsd/sys/netinet/accf_http.c (revision 34b94e8b82a3eb745c9cb23f3185fef0fc6c7f10)
134b94e8bSAlfred Perlstein /*
234b94e8bSAlfred Perlstein  * Copyright (c) 2000 Paycounter, Inc.
334b94e8bSAlfred Perlstein  * Author: Alfred Perlstein <alfred@paycounter.com>, <alfred@FreeBSD.org>
4a79b7128SAlfred Perlstein  * All rights reserved.
5a79b7128SAlfred Perlstein  *
6a79b7128SAlfred Perlstein  * Redistribution and use in source and binary forms, with or without
7a79b7128SAlfred Perlstein  * modification, are permitted provided that the following conditions
8a79b7128SAlfred Perlstein  * are met:
9a79b7128SAlfred Perlstein  * 1. Redistributions of source code must retain the above copyright
10a79b7128SAlfred Perlstein  *    notice, this list of conditions and the following disclaimer.
11a79b7128SAlfred Perlstein  * 2. Redistributions in binary form must reproduce the above copyright
12a79b7128SAlfred Perlstein  *    notice, this list of conditions and the following disclaimer in the
13a79b7128SAlfred Perlstein  *    documentation and/or other materials provided with the distribution.
14a79b7128SAlfred Perlstein  *
15a79b7128SAlfred Perlstein  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16a79b7128SAlfred Perlstein  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17a79b7128SAlfred Perlstein  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18a79b7128SAlfred Perlstein  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19a79b7128SAlfred Perlstein  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20a79b7128SAlfred Perlstein  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21a79b7128SAlfred Perlstein  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22a79b7128SAlfred Perlstein  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23a79b7128SAlfred Perlstein  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24a79b7128SAlfred Perlstein  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25a79b7128SAlfred Perlstein  * SUCH DAMAGE.
26a79b7128SAlfred Perlstein  *
27a79b7128SAlfred Perlstein  *	$FreeBSD$
28a79b7128SAlfred Perlstein  */
29a79b7128SAlfred Perlstein 
30a79b7128SAlfred Perlstein #define ACCEPT_FILTER_MOD
31a79b7128SAlfred Perlstein 
32a79b7128SAlfred Perlstein #include <sys/param.h>
33a79b7128SAlfred Perlstein #include <sys/systm.h>
34a79b7128SAlfred Perlstein #include <sys/sysproto.h>
35a79b7128SAlfred Perlstein #include <sys/kernel.h>
36a79b7128SAlfred Perlstein #include <sys/proc.h>
37a79b7128SAlfred Perlstein #include <sys/malloc.h>
38a79b7128SAlfred Perlstein #include <sys/unistd.h>
39a79b7128SAlfred Perlstein #include <sys/file.h>
40a79b7128SAlfred Perlstein #include <sys/fcntl.h>
41a79b7128SAlfred Perlstein #include <sys/protosw.h>
4234b94e8bSAlfred Perlstein #include <sys/sysctl.h>
43a79b7128SAlfred Perlstein #include <sys/socket.h>
44a79b7128SAlfred Perlstein #include <sys/socketvar.h>
45a79b7128SAlfred Perlstein #include <sys/stat.h>
46a79b7128SAlfred Perlstein #include <sys/mbuf.h>
47a79b7128SAlfred Perlstein #include <sys/resource.h>
48a79b7128SAlfred Perlstein #include <sys/sysent.h>
49a79b7128SAlfred Perlstein #include <sys/resourcevar.h>
50a79b7128SAlfred Perlstein 
5134b94e8bSAlfred Perlstein /* check for GET/HEAD */
52a79b7128SAlfred Perlstein static void sohashttpget(struct socket *so, void *arg, int waitflag);
5334b94e8bSAlfred Perlstein /* check for HTTP/1.0 or HTTP/1.1 */
5434b94e8bSAlfred Perlstein static void soparsehttpvers(struct socket *so, void *arg, int waitflag);
5534b94e8bSAlfred Perlstein /* check for end of HTTP/1.x request */
56a79b7128SAlfred Perlstein static void soishttpconnected(struct socket *so, void *arg, int waitflag);
5734b94e8bSAlfred Perlstein /* strcmp on an mbuf chain */
5834b94e8bSAlfred Perlstein static int mbufstrcmp(struct mbuf *m, struct mbuf *npkt, int offset, char *cmp);
5934b94e8bSAlfred Perlstein /* strncmp on an mbuf chain */
6034b94e8bSAlfred Perlstein static int mbufstrncmp(struct mbuf *m, struct mbuf *npkt, int offset,
6134b94e8bSAlfred Perlstein 	int max, char *cmp);
6234b94e8bSAlfred Perlstein /* socketbuffer is full */
6334b94e8bSAlfred Perlstein static int sbfull(struct sockbuf *sb);
64a79b7128SAlfred Perlstein 
65a79b7128SAlfred Perlstein static struct accept_filter accf_http_filter = {
66a79b7128SAlfred Perlstein 	"httpready",
67a79b7128SAlfred Perlstein 	sohashttpget,
68a79b7128SAlfred Perlstein 	NULL,
69a79b7128SAlfred Perlstein 	NULL
70a79b7128SAlfred Perlstein };
71a79b7128SAlfred Perlstein 
72a79b7128SAlfred Perlstein static moduledata_t accf_http_mod = {
73a79b7128SAlfred Perlstein 	"accf_http",
74a79b7128SAlfred Perlstein 	accept_filt_generic_mod_event,
75a79b7128SAlfred Perlstein 	&accf_http_filter
76a79b7128SAlfred Perlstein };
77a79b7128SAlfred Perlstein 
78a79b7128SAlfred Perlstein DECLARE_MODULE(accf_http, accf_http_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
79a79b7128SAlfred Perlstein 
8034b94e8bSAlfred Perlstein static int parse_http_version = 1;
81a79b7128SAlfred Perlstein 
8234b94e8bSAlfred Perlstein SYSCTL_NODE(_net_inet_accf, OID_AUTO, http, CTLFLAG_RW, 0,
8334b94e8bSAlfred Perlstein "HTTP accept filter");
8434b94e8bSAlfred Perlstein SYSCTL_INT(_net_inet_accf_http, OID_AUTO, parsehttpversion, CTLFLAG_RW,
8534b94e8bSAlfred Perlstein &parse_http_version, 1,
8634b94e8bSAlfred Perlstein "Parse http version so that non 1.x requests work");
8734b94e8bSAlfred Perlstein 
8834b94e8bSAlfred Perlstein #ifdef ACCF_HTTP_DEBUG
8934b94e8bSAlfred Perlstein #define DPRINT(fmt, args...) \
9034b94e8bSAlfred Perlstein 	do {	\
9134b94e8bSAlfred Perlstein 		printf("%s:%d: " fmt "\n", __func__, __LINE__ , ##args);	\
9234b94e8bSAlfred Perlstein 	} while (0)
9334b94e8bSAlfred Perlstein #else
9434b94e8bSAlfred Perlstein #define DPRINT(fmt, args...)
9534b94e8bSAlfred Perlstein #endif
9634b94e8bSAlfred Perlstein 
9734b94e8bSAlfred Perlstein static int
9834b94e8bSAlfred Perlstein sbfull(struct sockbuf *sb)
99a79b7128SAlfred Perlstein {
100a79b7128SAlfred Perlstein 
10134b94e8bSAlfred Perlstein 	DPRINT("sbfull, cc(%ld) >= hiwat(%ld): %d, mbcnt(%ld) >= mbmax(%ld): %d",
10234b94e8bSAlfred Perlstein 		sb->sb_cc, sb->sb_hiwat, sb->sb_cc >= sb->sb_hiwat,
10334b94e8bSAlfred Perlstein 		sb->sb_mbcnt, sb->sb_mbmax, sb->sb_mbcnt >= sb->sb_mbmax);
10434b94e8bSAlfred Perlstein 	return(sb->sb_cc >= sb->sb_hiwat || sb->sb_mbcnt >= sb->sb_mbmax);
10534b94e8bSAlfred Perlstein }
10634b94e8bSAlfred Perlstein 
10734b94e8bSAlfred Perlstein /*
10834b94e8bSAlfred Perlstein  * start at mbuf m, (must provide npkt if exists)
10934b94e8bSAlfred Perlstein  * starting at offset in m compare characters in mbuf chain for 'cmp'
11034b94e8bSAlfred Perlstein  */
11134b94e8bSAlfred Perlstein static int
11234b94e8bSAlfred Perlstein mbufstrcmp(struct mbuf *m, struct mbuf *npkt, int offset, char *cmp)
11334b94e8bSAlfred Perlstein {
11434b94e8bSAlfred Perlstein 	struct mbuf *n;
11534b94e8bSAlfred Perlstein 
11634b94e8bSAlfred Perlstein 	for (;m != NULL; m = n) {
11734b94e8bSAlfred Perlstein 		n = npkt;
11834b94e8bSAlfred Perlstein 		if (npkt)
11934b94e8bSAlfred Perlstein 			npkt = npkt->m_nextpkt;
12034b94e8bSAlfred Perlstein 		for (; m; m = m->m_next) {
12134b94e8bSAlfred Perlstein 			for (; offset < m->m_len; offset++, cmp++) {
12234b94e8bSAlfred Perlstein 				if (*cmp == '\0') {
12334b94e8bSAlfred Perlstein 					return (1);
12434b94e8bSAlfred Perlstein 				} else if (*cmp != *(mtod(m, char *) + offset)) {
12534b94e8bSAlfred Perlstein 					return (0);
126a79b7128SAlfred Perlstein 				}
127a79b7128SAlfred Perlstein 			}
12834b94e8bSAlfred Perlstein 			offset = 0;
129a79b7128SAlfred Perlstein 		}
13034b94e8bSAlfred Perlstein 	}
13134b94e8bSAlfred Perlstein 	return (0);
13234b94e8bSAlfred Perlstein }
13334b94e8bSAlfred Perlstein 
13434b94e8bSAlfred Perlstein /*
13534b94e8bSAlfred Perlstein  * start at mbuf m, (must provide npkt if exists)
13634b94e8bSAlfred Perlstein  * starting at offset in m compare characters in mbuf chain for 'cmp'
13734b94e8bSAlfred Perlstein  * stop at 'max' characters
13834b94e8bSAlfred Perlstein  */
13934b94e8bSAlfred Perlstein static int
14034b94e8bSAlfred Perlstein mbufstrncmp(struct mbuf *m, struct mbuf *npkt, int offset, int max, char *cmp)
14134b94e8bSAlfred Perlstein {
14234b94e8bSAlfred Perlstein 	struct mbuf *n;
14334b94e8bSAlfred Perlstein 
14434b94e8bSAlfred Perlstein 	for (;m != NULL; m = n) {
14534b94e8bSAlfred Perlstein 		n = npkt;
14634b94e8bSAlfred Perlstein 		if (npkt)
14734b94e8bSAlfred Perlstein 			npkt = npkt->m_nextpkt;
14834b94e8bSAlfred Perlstein 		for (; m; m = m->m_next) {
14934b94e8bSAlfred Perlstein 			for (; offset < m->m_len; offset++, cmp++, max--) {
15034b94e8bSAlfred Perlstein 				if (max == 0 || *cmp == '\0') {
15134b94e8bSAlfred Perlstein 					return (1);
15234b94e8bSAlfred Perlstein 				} else if (*cmp != *(mtod(m, char *) + offset)) {
15334b94e8bSAlfred Perlstein 					return (0);
15434b94e8bSAlfred Perlstein 				}
15534b94e8bSAlfred Perlstein 			}
15634b94e8bSAlfred Perlstein 			offset = 0;
15734b94e8bSAlfred Perlstein 		}
15834b94e8bSAlfred Perlstein 	}
15934b94e8bSAlfred Perlstein 	return (0);
16034b94e8bSAlfred Perlstein }
16134b94e8bSAlfred Perlstein 
16234b94e8bSAlfred Perlstein #define STRSETUP(sptr, slen, str) \
16334b94e8bSAlfred Perlstein 	do {	\
16434b94e8bSAlfred Perlstein 		sptr = str;	\
16534b94e8bSAlfred Perlstein 		slen = sizeof(str) - 1;	\
16634b94e8bSAlfred Perlstein 	} while(0)
167a79b7128SAlfred Perlstein 
168a79b7128SAlfred Perlstein static void
169a79b7128SAlfred Perlstein sohashttpget(struct socket *so, void *arg, int waitflag)
170a79b7128SAlfred Perlstein {
171a79b7128SAlfred Perlstein 
17234b94e8bSAlfred Perlstein 	if ((so->so_state & SS_CANTRCVMORE) == 0 || !sbfull(&so->so_rcv)) {
173a79b7128SAlfred Perlstein 		struct mbuf *m;
17434b94e8bSAlfred Perlstein 		char *cmp;
17534b94e8bSAlfred Perlstein 		int	cmplen, cc;
176a79b7128SAlfred Perlstein 
177a79b7128SAlfred Perlstein 		m = so->so_rcv.sb_mb;
17834b94e8bSAlfred Perlstein 		cc = so->so_rcv.sb_cc - 1;
17934b94e8bSAlfred Perlstein 		if (cc < 1)
18034b94e8bSAlfred Perlstein 			return;
18134b94e8bSAlfred Perlstein 		switch (*mtod(m, char *)) {
18234b94e8bSAlfred Perlstein 		case 'G':
18334b94e8bSAlfred Perlstein 			STRSETUP(cmp, cmplen, "ET ");
18434b94e8bSAlfred Perlstein 			break;
18534b94e8bSAlfred Perlstein 		case 'H':
18634b94e8bSAlfred Perlstein 			STRSETUP(cmp, cmplen, "EAD ");
18734b94e8bSAlfred Perlstein 			break;
18834b94e8bSAlfred Perlstein 		default:
18934b94e8bSAlfred Perlstein 			goto fallout;
19034b94e8bSAlfred Perlstein 		}
19134b94e8bSAlfred Perlstein 		if (cc < cmplen) {
19234b94e8bSAlfred Perlstein 			if (mbufstrncmp(m, m->m_nextpkt, 1, cc, cmp) == 1) {
19334b94e8bSAlfred Perlstein 				DPRINT("short cc (%d) but mbufstrncmp ok", cc);
19434b94e8bSAlfred Perlstein 				return;
19534b94e8bSAlfred Perlstein 			} else {
19634b94e8bSAlfred Perlstein 				DPRINT("short cc (%d) mbufstrncmp failed", cc);
19734b94e8bSAlfred Perlstein 				goto fallout;
19834b94e8bSAlfred Perlstein 			}
19934b94e8bSAlfred Perlstein 		}
20034b94e8bSAlfred Perlstein 		if (mbufstrcmp(m, m->m_nextpkt, 1, cmp) == 1) {
20134b94e8bSAlfred Perlstein 			DPRINT("mbufstrcmp ok");
20234b94e8bSAlfred Perlstein 			if (parse_http_version == 0)
203a79b7128SAlfred Perlstein 				soishttpconnected(so, arg, waitflag);
20434b94e8bSAlfred Perlstein 			else
20534b94e8bSAlfred Perlstein 				soparsehttpvers(so, arg, waitflag);
206a79b7128SAlfred Perlstein 			return;
207a79b7128SAlfred Perlstein 		}
20834b94e8bSAlfred Perlstein 		DPRINT("mbufstrcmp bad");
209a79b7128SAlfred Perlstein 	}
210a79b7128SAlfred Perlstein 
21134b94e8bSAlfred Perlstein fallout:
21234b94e8bSAlfred Perlstein 	DPRINT("fallout");
213a79b7128SAlfred Perlstein 	so->so_upcall = NULL;
214a79b7128SAlfred Perlstein 	so->so_rcv.sb_flags &= ~SB_UPCALL;
215a79b7128SAlfred Perlstein 	soisconnected(so);
216a79b7128SAlfred Perlstein 	return;
217a79b7128SAlfred Perlstein }
218a79b7128SAlfred Perlstein 
219a79b7128SAlfred Perlstein static void
22034b94e8bSAlfred Perlstein soparsehttpvers(struct socket *so, void *arg, int waitflag)
22134b94e8bSAlfred Perlstein {
22234b94e8bSAlfred Perlstein 	struct mbuf *m, *n;
22334b94e8bSAlfred Perlstein 	int	i, cc, spaces, inspaces;
22434b94e8bSAlfred Perlstein 
22534b94e8bSAlfred Perlstein 	if ((so->so_state & SS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv))
22634b94e8bSAlfred Perlstein 		goto fallout;
22734b94e8bSAlfred Perlstein 
22834b94e8bSAlfred Perlstein 	m = so->so_rcv.sb_mb;
22934b94e8bSAlfred Perlstein 	cc = so->so_rcv.sb_cc;
23034b94e8bSAlfred Perlstein 	inspaces = spaces = 0;
23134b94e8bSAlfred Perlstein 	for (m = so->so_rcv.sb_mb; m; m = n) {
23234b94e8bSAlfred Perlstein 		n = m->m_nextpkt;
23334b94e8bSAlfred Perlstein 		for (; m; m = m->m_next) {
23434b94e8bSAlfred Perlstein 			for (i = 0; i < m->m_len; i++, cc--) {
23534b94e8bSAlfred Perlstein 				switch (*(mtod(m, char *) + i)) {
23634b94e8bSAlfred Perlstein 				case ' ':
23734b94e8bSAlfred Perlstein 					if (!inspaces) {
23834b94e8bSAlfred Perlstein 						spaces++;
23934b94e8bSAlfred Perlstein 						inspaces = 1;
24034b94e8bSAlfred Perlstein 					}
24134b94e8bSAlfred Perlstein 					break;
24234b94e8bSAlfred Perlstein 				case '\r':
24334b94e8bSAlfred Perlstein 				case '\n':
24434b94e8bSAlfred Perlstein 					DPRINT("newline");
24534b94e8bSAlfred Perlstein 					goto fallout;
24634b94e8bSAlfred Perlstein 				default:
24734b94e8bSAlfred Perlstein 					if (spaces == 2) {
24834b94e8bSAlfred Perlstein 						/* make sure we have enough data left */
24934b94e8bSAlfred Perlstein 						if (cc < sizeof("HTTP/1.0") - 1) {
25034b94e8bSAlfred Perlstein 							if (mbufstrncmp(m, n, i, cc, "HTTP/1.") == 1) {
25134b94e8bSAlfred Perlstein 								DPRINT("mbufstrncmp ok");
25234b94e8bSAlfred Perlstein 								goto readmore;
25334b94e8bSAlfred Perlstein 							} else {
25434b94e8bSAlfred Perlstein 								DPRINT("mbufstrncmp bad");
25534b94e8bSAlfred Perlstein 								goto fallout;
25634b94e8bSAlfred Perlstein 							}
25734b94e8bSAlfred Perlstein 						} else if (mbufstrcmp(m, n, i, "HTTP/1.0") == 1 ||
25834b94e8bSAlfred Perlstein 									mbufstrcmp(m, n, i, "HTTP/1.1") == 1) {
25934b94e8bSAlfred Perlstein 								DPRINT("mbufstrcmp ok");
26034b94e8bSAlfred Perlstein 								soishttpconnected(so, arg, waitflag);
26134b94e8bSAlfred Perlstein 								return;
26234b94e8bSAlfred Perlstein 						} else {
26334b94e8bSAlfred Perlstein 							DPRINT("mbufstrcmp bad");
26434b94e8bSAlfred Perlstein 							goto fallout;
26534b94e8bSAlfred Perlstein 						}
26634b94e8bSAlfred Perlstein 					}
26734b94e8bSAlfred Perlstein 					inspaces = 0;
26834b94e8bSAlfred Perlstein 					break;
26934b94e8bSAlfred Perlstein 				}
27034b94e8bSAlfred Perlstein 			}
27134b94e8bSAlfred Perlstein 		}
27234b94e8bSAlfred Perlstein 	}
27334b94e8bSAlfred Perlstein readmore:
27434b94e8bSAlfred Perlstein 	DPRINT("readmore");
27534b94e8bSAlfred Perlstein 	/*
27634b94e8bSAlfred Perlstein 	 * if we hit here we haven't hit something
27734b94e8bSAlfred Perlstein 	 * we don't understand or a newline, so try again
27834b94e8bSAlfred Perlstein 	 */
27934b94e8bSAlfred Perlstein 	so->so_upcall = soparsehttpvers;
28034b94e8bSAlfred Perlstein 	so->so_rcv.sb_flags |= SB_UPCALL;
28134b94e8bSAlfred Perlstein 	return;
28234b94e8bSAlfred Perlstein 
28334b94e8bSAlfred Perlstein fallout:
28434b94e8bSAlfred Perlstein 	DPRINT("fallout");
28534b94e8bSAlfred Perlstein 	so->so_upcall = NULL;
28634b94e8bSAlfred Perlstein 	so->so_rcv.sb_flags &= ~SB_UPCALL;
28734b94e8bSAlfred Perlstein 	soisconnected(so);
28834b94e8bSAlfred Perlstein 	return;
28934b94e8bSAlfred Perlstein }
29034b94e8bSAlfred Perlstein 
29134b94e8bSAlfred Perlstein 
29234b94e8bSAlfred Perlstein #define NCHRS 3
29334b94e8bSAlfred Perlstein 
29434b94e8bSAlfred Perlstein static void
295a79b7128SAlfred Perlstein soishttpconnected(struct socket *so, void *arg, int waitflag)
296a79b7128SAlfred Perlstein {
297a79b7128SAlfred Perlstein 	char a, b, c;
29834b94e8bSAlfred Perlstein 	struct mbuf *m, *n;
29934b94e8bSAlfred Perlstein 	int ccleft, copied;
300a79b7128SAlfred Perlstein 
30134b94e8bSAlfred Perlstein 	DPRINT("start");
30234b94e8bSAlfred Perlstein 	if ((so->so_state & SS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv))
30334b94e8bSAlfred Perlstein 		goto gotit;
304a79b7128SAlfred Perlstein 
30534b94e8bSAlfred Perlstein 	/*
30634b94e8bSAlfred Perlstein 	 * Walk the socketbuffer and copy the last NCHRS (3) into a, b, and c
30734b94e8bSAlfred Perlstein 	 * copied - how much we've copied so far
30834b94e8bSAlfred Perlstein 	 * ccleft - how many bytes remaining in the socketbuffer
30934b94e8bSAlfred Perlstein 	 * just loop over the mbufs subtracting from 'ccleft' until we only
31034b94e8bSAlfred Perlstein 	 * have NCHRS left
31134b94e8bSAlfred Perlstein 	 */
31234b94e8bSAlfred Perlstein 	copied = 0;
31334b94e8bSAlfred Perlstein 	ccleft = so->so_rcv.sb_cc;
31434b94e8bSAlfred Perlstein 	if (ccleft < NCHRS)
31534b94e8bSAlfred Perlstein 		goto readmore;
31634b94e8bSAlfred Perlstein 	a = b = c = '\0';
31734b94e8bSAlfred Perlstein 	for (m = so->so_rcv.sb_mb; m; m = n) {
31834b94e8bSAlfred Perlstein 		n = m->m_nextpkt;
31934b94e8bSAlfred Perlstein 		for (; m; m = m->m_next) {
32034b94e8bSAlfred Perlstein 			ccleft -= m->m_len;
32134b94e8bSAlfred Perlstein 			if (ccleft <= NCHRS) {
32234b94e8bSAlfred Perlstein 				char *src;
32334b94e8bSAlfred Perlstein 				int tocopy;
324a79b7128SAlfred Perlstein 
32534b94e8bSAlfred Perlstein 				tocopy = (NCHRS - ccleft) - copied;
32634b94e8bSAlfred Perlstein 				src = mtod(m, char *) + (m->m_len - tocopy);
32734b94e8bSAlfred Perlstein 
32834b94e8bSAlfred Perlstein 				while (tocopy--) {
32934b94e8bSAlfred Perlstein 					switch (copied++) {
330a79b7128SAlfred Perlstein 					case 0:
33134b94e8bSAlfred Perlstein 						a = *src++;
332a79b7128SAlfred Perlstein 						break;
33334b94e8bSAlfred Perlstein 					case 1:
33434b94e8bSAlfred Perlstein 						b = *src++;
33534b94e8bSAlfred Perlstein 						break;
33634b94e8bSAlfred Perlstein 					case 2:
33734b94e8bSAlfred Perlstein 						c = *src++;
338a79b7128SAlfred Perlstein 						break;
339a79b7128SAlfred Perlstein 					}
340a79b7128SAlfred Perlstein 				}
34134b94e8bSAlfred Perlstein 			}
34234b94e8bSAlfred Perlstein 		}
34334b94e8bSAlfred Perlstein 	}
344a79b7128SAlfred Perlstein 	if (c == '\n' && (b == '\n' || (b == '\r' && a == '\n'))) {
345a79b7128SAlfred Perlstein 		/* we have all request headers */
34634b94e8bSAlfred Perlstein 		goto gotit;
34734b94e8bSAlfred Perlstein 	}
34834b94e8bSAlfred Perlstein 
34934b94e8bSAlfred Perlstein readmore:
350a79b7128SAlfred Perlstein 	so->so_upcall = soishttpconnected;
351a79b7128SAlfred Perlstein 	so->so_rcv.sb_flags |= SB_UPCALL;
352a79b7128SAlfred Perlstein 	return;
353a79b7128SAlfred Perlstein 
35434b94e8bSAlfred Perlstein gotit:
355a79b7128SAlfred Perlstein 	so->so_upcall = NULL;
356a79b7128SAlfred Perlstein 	so->so_rcv.sb_flags &= ~SB_UPCALL;
357a79b7128SAlfred Perlstein 	soisconnected(so);
358a79b7128SAlfred Perlstein 	return;
359a79b7128SAlfred Perlstein }
360