accf_http.c revision 1.6.6.3 1 1.6.6.3 yamt /* $NetBSD: accf_http.c,v 1.6.6.3 2009/09/16 13:38:02 yamt Exp $ */
2 1.6.6.2 yamt
3 1.6.6.2 yamt /*-
4 1.6.6.2 yamt * Copyright (c) 2000 Paycounter, Inc.
5 1.6.6.2 yamt * Author: Alfred Perlstein <alfred (at) paycounter.com>, <alfred (at) FreeBSD.org>
6 1.6.6.2 yamt * All rights reserved.
7 1.6.6.2 yamt *
8 1.6.6.2 yamt * Redistribution and use in source and binary forms, with or without
9 1.6.6.2 yamt * modification, are permitted provided that the following conditions
10 1.6.6.2 yamt * are met:
11 1.6.6.2 yamt * 1. Redistributions of source code must retain the above copyright
12 1.6.6.2 yamt * notice, this list of conditions and the following disclaimer.
13 1.6.6.2 yamt * 2. Redistributions in binary form must reproduce the above copyright
14 1.6.6.2 yamt * notice, this list of conditions and the following disclaimer in the
15 1.6.6.2 yamt * documentation and/or other materials provided with the distribution.
16 1.6.6.2 yamt *
17 1.6.6.2 yamt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 1.6.6.2 yamt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 1.6.6.2 yamt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 1.6.6.2 yamt * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 1.6.6.2 yamt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 1.6.6.2 yamt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 1.6.6.2 yamt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 1.6.6.2 yamt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 1.6.6.2 yamt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 1.6.6.2 yamt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 1.6.6.2 yamt * SUCH DAMAGE.
28 1.6.6.2 yamt */
29 1.6.6.2 yamt
30 1.6.6.2 yamt #include <sys/cdefs.h>
31 1.6.6.3 yamt __KERNEL_RCSID(0, "$NetBSD: accf_http.c,v 1.6.6.3 2009/09/16 13:38:02 yamt Exp $");
32 1.6.6.2 yamt
33 1.6.6.2 yamt #define ACCEPT_FILTER_MOD
34 1.6.6.2 yamt
35 1.6.6.2 yamt #include <sys/param.h>
36 1.6.6.2 yamt #include <sys/kernel.h>
37 1.6.6.2 yamt #include <sys/mbuf.h>
38 1.6.6.2 yamt #include <sys/module.h>
39 1.6.6.2 yamt #include <sys/signalvar.h>
40 1.6.6.2 yamt #include <sys/sysctl.h>
41 1.6.6.2 yamt #include <sys/socket.h>
42 1.6.6.2 yamt #include <sys/socketvar.h>
43 1.6.6.2 yamt
44 1.6.6.2 yamt #include <netinet/accept_filter.h>
45 1.6.6.2 yamt
46 1.6.6.2 yamt MODULE(MODULE_CLASS_MISC, accf_httpready, NULL);
47 1.6.6.2 yamt
48 1.6.6.2 yamt /* check for GET/HEAD */
49 1.6.6.3 yamt static void sohashttpget(struct socket *so, void *arg, int events, int waitflag);
50 1.6.6.2 yamt /* check for HTTP/1.0 or HTTP/1.1 */
51 1.6.6.3 yamt static void soparsehttpvers(struct socket *so, void *arg, int events, int waitflag);
52 1.6.6.2 yamt /* check for end of HTTP/1.x request */
53 1.6.6.3 yamt static void soishttpconnected(struct socket *so, void *arg, int events, int waitflag);
54 1.6.6.2 yamt /* strcmp on an mbuf chain */
55 1.6.6.2 yamt static int mbufstrcmp(struct mbuf *m, struct mbuf *npkt, int offset, const char *cmp);
56 1.6.6.2 yamt /* strncmp on an mbuf chain */
57 1.6.6.2 yamt static int mbufstrncmp(struct mbuf *m, struct mbuf *npkt, int offset,
58 1.6.6.2 yamt int len, const char *cmp);
59 1.6.6.2 yamt /* socketbuffer is full */
60 1.6.6.2 yamt static int sbfull(struct sockbuf *sb);
61 1.6.6.2 yamt
62 1.6.6.2 yamt static struct accept_filter accf_http_filter = {
63 1.6.6.2 yamt .accf_name = "httpready",
64 1.6.6.2 yamt .accf_callback = sohashttpget,
65 1.6.6.2 yamt };
66 1.6.6.2 yamt
67 1.6.6.2 yamt /*
68 1.6.6.2 yamt * Names of HTTP Accept filter sysctl objects
69 1.6.6.2 yamt */
70 1.6.6.2 yamt
71 1.6.6.2 yamt #define ACCFCTL_PARSEVER 1 /* Parse HTTP version */
72 1.6.6.2 yamt
73 1.6.6.2 yamt static int parse_http_version = 1;
74 1.6.6.2 yamt
75 1.6.6.2 yamt /* XXX pseudo-device */
76 1.6.6.2 yamt void accf_httpattach(int);
77 1.6.6.2 yamt
78 1.6.6.2 yamt void
79 1.6.6.2 yamt accf_httpattach(int junk)
80 1.6.6.2 yamt {
81 1.6.6.2 yamt
82 1.6.6.2 yamt }
83 1.6.6.2 yamt
84 1.6.6.2 yamt static int
85 1.6.6.2 yamt accf_httpready_modcmd(modcmd_t cmd, void *arg)
86 1.6.6.2 yamt {
87 1.6.6.2 yamt static struct sysctllog *clog;
88 1.6.6.2 yamt int error;
89 1.6.6.2 yamt
90 1.6.6.2 yamt switch (cmd) {
91 1.6.6.2 yamt case MODULE_CMD_INIT:
92 1.6.6.2 yamt error = accept_filt_add(&accf_http_filter);
93 1.6.6.2 yamt if (error != 0) {
94 1.6.6.2 yamt return error;
95 1.6.6.2 yamt }
96 1.6.6.2 yamt sysctl_createv(&clog, 0, NULL, NULL,
97 1.6.6.2 yamt CTLFLAG_PERMANENT,
98 1.6.6.2 yamt CTLTYPE_NODE, "net", NULL,
99 1.6.6.2 yamt NULL, 0, NULL, 0,
100 1.6.6.2 yamt CTL_NET, CTL_EOL);
101 1.6.6.2 yamt sysctl_createv(&clog, 0, NULL, NULL,
102 1.6.6.2 yamt CTLFLAG_PERMANENT,
103 1.6.6.2 yamt CTLTYPE_NODE, "inet", NULL,
104 1.6.6.2 yamt NULL, 0, NULL, 0,
105 1.6.6.2 yamt CTL_NET, PF_INET, CTL_EOL);
106 1.6.6.2 yamt sysctl_createv(&clog, 0, NULL, NULL,
107 1.6.6.2 yamt CTLFLAG_PERMANENT,
108 1.6.6.2 yamt CTLTYPE_NODE, "accf", NULL,
109 1.6.6.2 yamt NULL, 0, NULL, 0,
110 1.6.6.2 yamt CTL_NET, PF_INET, SO_ACCEPTFILTER, CTL_EOL);
111 1.6.6.2 yamt sysctl_createv(&clog, 0, NULL, NULL,
112 1.6.6.2 yamt CTLFLAG_PERMANENT,
113 1.6.6.2 yamt CTLTYPE_NODE, "http",
114 1.6.6.2 yamt SYSCTL_DESCR("HTTP accept filter"),
115 1.6.6.2 yamt NULL, 0, NULL, 0,
116 1.6.6.2 yamt CTL_NET, PF_INET, SO_ACCEPTFILTER, ACCF_HTTP, CTL_EOL);
117 1.6.6.2 yamt sysctl_createv(&clog, 0, NULL, NULL,
118 1.6.6.2 yamt CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
119 1.6.6.2 yamt CTLTYPE_INT, "parsehttpversion",
120 1.6.6.2 yamt SYSCTL_DESCR("Parse http version so that non "
121 1.6.6.2 yamt "1.x requests work"),
122 1.6.6.2 yamt NULL, 0, &parse_http_version, 0,
123 1.6.6.2 yamt CTL_NET, PF_INET, SO_ACCEPTFILTER, ACCF_HTTP,
124 1.6.6.2 yamt ACCFCTL_PARSEVER, CTL_EOL);
125 1.6.6.2 yamt return 0;
126 1.6.6.2 yamt
127 1.6.6.2 yamt case MODULE_CMD_FINI:
128 1.6.6.2 yamt error = accept_filt_del(&accf_http_filter);
129 1.6.6.2 yamt if (error != 0) {
130 1.6.6.2 yamt return error;
131 1.6.6.2 yamt }
132 1.6.6.2 yamt sysctl_teardown(&clog);
133 1.6.6.2 yamt return 0;
134 1.6.6.2 yamt
135 1.6.6.2 yamt default:
136 1.6.6.2 yamt return ENOTTY;
137 1.6.6.2 yamt }
138 1.6.6.2 yamt }
139 1.6.6.2 yamt
140 1.6.6.2 yamt #ifdef ACCF_HTTP_DEBUG
141 1.6.6.2 yamt #define DPRINT(fmt, args...) \
142 1.6.6.2 yamt do { \
143 1.6.6.2 yamt printf("%s:%d: " fmt "\n", __func__, __LINE__, ##args); \
144 1.6.6.2 yamt } while (0)
145 1.6.6.2 yamt #else
146 1.6.6.2 yamt #define DPRINT(fmt, args...)
147 1.6.6.2 yamt #endif
148 1.6.6.2 yamt
149 1.6.6.2 yamt static int
150 1.6.6.2 yamt sbfull(struct sockbuf *sb)
151 1.6.6.2 yamt {
152 1.6.6.2 yamt
153 1.6.6.2 yamt DPRINT("sbfull, cc(%ld) >= hiwat(%ld): %d, "
154 1.6.6.2 yamt "mbcnt(%ld) >= mbmax(%ld): %d",
155 1.6.6.2 yamt sb->sb_cc, sb->sb_hiwat, sb->sb_cc >= sb->sb_hiwat,
156 1.6.6.2 yamt sb->sb_mbcnt, sb->sb_mbmax, sb->sb_mbcnt >= sb->sb_mbmax);
157 1.6.6.2 yamt return (sb->sb_cc >= sb->sb_hiwat || sb->sb_mbcnt >= sb->sb_mbmax);
158 1.6.6.2 yamt }
159 1.6.6.2 yamt
160 1.6.6.2 yamt /*
161 1.6.6.2 yamt * start at mbuf m, (must provide npkt if exists)
162 1.6.6.2 yamt * starting at offset in m compare characters in mbuf chain for 'cmp'
163 1.6.6.2 yamt */
164 1.6.6.2 yamt static int
165 1.6.6.2 yamt mbufstrcmp(struct mbuf *m, struct mbuf *npkt, int offset, const char *cmp)
166 1.6.6.2 yamt {
167 1.6.6.2 yamt struct mbuf *n;
168 1.6.6.2 yamt
169 1.6.6.2 yamt for (; m != NULL; m = n) {
170 1.6.6.2 yamt n = npkt;
171 1.6.6.2 yamt if (npkt)
172 1.6.6.2 yamt npkt = npkt->m_nextpkt;
173 1.6.6.2 yamt for (; m; m = m->m_next) {
174 1.6.6.2 yamt for (; offset < m->m_len; offset++, cmp++) {
175 1.6.6.2 yamt if (*cmp == '\0')
176 1.6.6.2 yamt return (1);
177 1.6.6.2 yamt else if (*cmp != *(mtod(m, char *) + offset))
178 1.6.6.2 yamt return (0);
179 1.6.6.2 yamt }
180 1.6.6.2 yamt if (*cmp == '\0')
181 1.6.6.2 yamt return (1);
182 1.6.6.2 yamt offset = 0;
183 1.6.6.2 yamt }
184 1.6.6.2 yamt }
185 1.6.6.2 yamt return (0);
186 1.6.6.2 yamt }
187 1.6.6.2 yamt
188 1.6.6.2 yamt /*
189 1.6.6.2 yamt * start at mbuf m, (must provide npkt if exists)
190 1.6.6.2 yamt * starting at offset in m compare characters in mbuf chain for 'cmp'
191 1.6.6.2 yamt * stop at 'max' characters
192 1.6.6.2 yamt */
193 1.6.6.2 yamt static int
194 1.6.6.2 yamt mbufstrncmp(struct mbuf *m, struct mbuf *npkt, int offset, int len, const char *cmp)
195 1.6.6.2 yamt {
196 1.6.6.2 yamt struct mbuf *n;
197 1.6.6.2 yamt
198 1.6.6.2 yamt for (; m != NULL; m = n) {
199 1.6.6.2 yamt n = npkt;
200 1.6.6.2 yamt if (npkt)
201 1.6.6.2 yamt npkt = npkt->m_nextpkt;
202 1.6.6.2 yamt for (; m; m = m->m_next) {
203 1.6.6.2 yamt for (; offset < m->m_len; offset++, cmp++, len--) {
204 1.6.6.2 yamt if (len == 0 || *cmp == '\0')
205 1.6.6.2 yamt return (1);
206 1.6.6.2 yamt else if (*cmp != *(mtod(m, char *) + offset))
207 1.6.6.2 yamt return (0);
208 1.6.6.2 yamt }
209 1.6.6.2 yamt if (len == 0 || *cmp == '\0')
210 1.6.6.2 yamt return (1);
211 1.6.6.2 yamt offset = 0;
212 1.6.6.2 yamt }
213 1.6.6.2 yamt }
214 1.6.6.2 yamt return (0);
215 1.6.6.2 yamt }
216 1.6.6.2 yamt
217 1.6.6.2 yamt #define STRSETUP(sptr, slen, str) \
218 1.6.6.2 yamt do { \
219 1.6.6.2 yamt sptr = str; \
220 1.6.6.2 yamt slen = sizeof(str) - 1; \
221 1.6.6.2 yamt } while(0)
222 1.6.6.2 yamt
223 1.6.6.2 yamt static void
224 1.6.6.3 yamt sohashttpget(struct socket *so, void *arg, int events, int waitflag)
225 1.6.6.2 yamt {
226 1.6.6.2 yamt
227 1.6.6.2 yamt if ((so->so_state & SS_CANTRCVMORE) == 0 && !sbfull(&so->so_rcv)) {
228 1.6.6.2 yamt struct mbuf *m;
229 1.6.6.2 yamt const char *cmp;
230 1.6.6.2 yamt int cmplen, cc;
231 1.6.6.2 yamt
232 1.6.6.2 yamt m = so->so_rcv.sb_mb;
233 1.6.6.2 yamt cc = so->so_rcv.sb_cc - 1;
234 1.6.6.2 yamt if (cc < 1)
235 1.6.6.2 yamt return;
236 1.6.6.2 yamt switch (*mtod(m, char *)) {
237 1.6.6.2 yamt case 'G':
238 1.6.6.2 yamt STRSETUP(cmp, cmplen, "ET ");
239 1.6.6.2 yamt break;
240 1.6.6.2 yamt case 'H':
241 1.6.6.2 yamt STRSETUP(cmp, cmplen, "EAD ");
242 1.6.6.2 yamt break;
243 1.6.6.2 yamt default:
244 1.6.6.2 yamt goto fallout;
245 1.6.6.2 yamt }
246 1.6.6.2 yamt if (cc < cmplen) {
247 1.6.6.2 yamt if (mbufstrncmp(m, m->m_nextpkt, 1, cc, cmp) == 1) {
248 1.6.6.2 yamt DPRINT("short cc (%d) but mbufstrncmp ok", cc);
249 1.6.6.2 yamt return;
250 1.6.6.2 yamt } else {
251 1.6.6.2 yamt DPRINT("short cc (%d) mbufstrncmp failed", cc);
252 1.6.6.2 yamt goto fallout;
253 1.6.6.2 yamt }
254 1.6.6.2 yamt }
255 1.6.6.2 yamt if (mbufstrcmp(m, m->m_nextpkt, 1, cmp) == 1) {
256 1.6.6.2 yamt DPRINT("mbufstrcmp ok");
257 1.6.6.2 yamt if (parse_http_version == 0)
258 1.6.6.3 yamt soishttpconnected(so, arg, events, waitflag);
259 1.6.6.2 yamt else
260 1.6.6.3 yamt soparsehttpvers(so, arg, events, waitflag);
261 1.6.6.2 yamt return;
262 1.6.6.2 yamt }
263 1.6.6.2 yamt DPRINT("mbufstrcmp bad");
264 1.6.6.2 yamt }
265 1.6.6.2 yamt
266 1.6.6.2 yamt fallout:
267 1.6.6.2 yamt DPRINT("fallout");
268 1.6.6.2 yamt so->so_upcall = NULL;
269 1.6.6.2 yamt so->so_rcv.sb_flags &= ~SB_UPCALL;
270 1.6.6.2 yamt soisconnected(so);
271 1.6.6.2 yamt return;
272 1.6.6.2 yamt }
273 1.6.6.2 yamt
274 1.6.6.2 yamt static void
275 1.6.6.3 yamt soparsehttpvers(struct socket *so, void *arg, int events, int waitflag)
276 1.6.6.2 yamt {
277 1.6.6.2 yamt struct mbuf *m, *n;
278 1.6.6.2 yamt int i, cc, spaces, inspaces;
279 1.6.6.2 yamt
280 1.6.6.2 yamt if ((so->so_state & SS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv))
281 1.6.6.2 yamt goto fallout;
282 1.6.6.2 yamt
283 1.6.6.2 yamt m = so->so_rcv.sb_mb;
284 1.6.6.2 yamt cc = so->so_rcv.sb_cc;
285 1.6.6.2 yamt inspaces = spaces = 0;
286 1.6.6.2 yamt for (m = so->so_rcv.sb_mb; m; m = n) {
287 1.6.6.2 yamt n = m->m_nextpkt;
288 1.6.6.2 yamt for (; m; m = m->m_next) {
289 1.6.6.2 yamt for (i = 0; i < m->m_len; i++, cc--) {
290 1.6.6.2 yamt switch (*(mtod(m, char *) + i)) {
291 1.6.6.2 yamt case ' ':
292 1.6.6.2 yamt /* tabs? '\t' */
293 1.6.6.2 yamt if (!inspaces) {
294 1.6.6.2 yamt spaces++;
295 1.6.6.2 yamt inspaces = 1;
296 1.6.6.2 yamt }
297 1.6.6.2 yamt break;
298 1.6.6.2 yamt case '\r':
299 1.6.6.2 yamt case '\n':
300 1.6.6.2 yamt DPRINT("newline");
301 1.6.6.2 yamt goto fallout;
302 1.6.6.2 yamt default:
303 1.6.6.2 yamt if (spaces != 2) {
304 1.6.6.2 yamt inspaces = 0;
305 1.6.6.2 yamt break;
306 1.6.6.2 yamt }
307 1.6.6.2 yamt
308 1.6.6.2 yamt /*
309 1.6.6.2 yamt * if we don't have enough characters
310 1.6.6.2 yamt * left (cc < sizeof("HTTP/1.0") - 1)
311 1.6.6.2 yamt * then see if the remaining ones
312 1.6.6.2 yamt * are a request we can parse.
313 1.6.6.2 yamt */
314 1.6.6.2 yamt if (cc < sizeof("HTTP/1.0") - 1) {
315 1.6.6.2 yamt if (mbufstrncmp(m, n, i, cc,
316 1.6.6.2 yamt "HTTP/1.") == 1) {
317 1.6.6.2 yamt DPRINT("ok");
318 1.6.6.2 yamt goto readmore;
319 1.6.6.2 yamt } else {
320 1.6.6.2 yamt DPRINT("bad");
321 1.6.6.2 yamt goto fallout;
322 1.6.6.2 yamt }
323 1.6.6.2 yamt } else if (
324 1.6.6.2 yamt mbufstrcmp(m, n, i, "HTTP/1.0") ||
325 1.6.6.2 yamt mbufstrcmp(m, n, i, "HTTP/1.1")) {
326 1.6.6.2 yamt DPRINT("ok");
327 1.6.6.2 yamt soishttpconnected(so,
328 1.6.6.3 yamt arg, events, waitflag);
329 1.6.6.2 yamt return;
330 1.6.6.2 yamt } else {
331 1.6.6.2 yamt DPRINT("bad");
332 1.6.6.2 yamt goto fallout;
333 1.6.6.2 yamt }
334 1.6.6.2 yamt }
335 1.6.6.2 yamt }
336 1.6.6.2 yamt }
337 1.6.6.2 yamt }
338 1.6.6.2 yamt readmore:
339 1.6.6.2 yamt DPRINT("readmore");
340 1.6.6.2 yamt /*
341 1.6.6.2 yamt * if we hit here we haven't hit something
342 1.6.6.2 yamt * we don't understand or a newline, so try again
343 1.6.6.2 yamt */
344 1.6.6.2 yamt so->so_upcall = soparsehttpvers;
345 1.6.6.2 yamt so->so_rcv.sb_flags |= SB_UPCALL;
346 1.6.6.2 yamt return;
347 1.6.6.2 yamt
348 1.6.6.2 yamt fallout:
349 1.6.6.2 yamt DPRINT("fallout");
350 1.6.6.2 yamt so->so_upcall = NULL;
351 1.6.6.2 yamt so->so_rcv.sb_flags &= ~SB_UPCALL;
352 1.6.6.2 yamt soisconnected(so);
353 1.6.6.2 yamt return;
354 1.6.6.2 yamt }
355 1.6.6.2 yamt
356 1.6.6.2 yamt
357 1.6.6.2 yamt #define NCHRS 3
358 1.6.6.2 yamt
359 1.6.6.2 yamt static void
360 1.6.6.3 yamt soishttpconnected(struct socket *so, void *arg, int events, int waitflag)
361 1.6.6.2 yamt {
362 1.6.6.2 yamt char a, b, c;
363 1.6.6.2 yamt struct mbuf *m, *n;
364 1.6.6.2 yamt int ccleft, copied;
365 1.6.6.2 yamt
366 1.6.6.2 yamt DPRINT("start");
367 1.6.6.2 yamt if ((so->so_state & SS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv))
368 1.6.6.2 yamt goto gotit;
369 1.6.6.2 yamt
370 1.6.6.2 yamt /*
371 1.6.6.2 yamt * Walk the socketbuffer and copy the last NCHRS (3) into a, b, and c
372 1.6.6.2 yamt * copied - how much we've copied so far
373 1.6.6.2 yamt * ccleft - how many bytes remaining in the socketbuffer
374 1.6.6.2 yamt * just loop over the mbufs subtracting from 'ccleft' until we only
375 1.6.6.2 yamt * have NCHRS left
376 1.6.6.2 yamt */
377 1.6.6.2 yamt copied = 0;
378 1.6.6.2 yamt ccleft = so->so_rcv.sb_cc;
379 1.6.6.2 yamt if (ccleft < NCHRS)
380 1.6.6.2 yamt goto readmore;
381 1.6.6.2 yamt a = b = c = '\0';
382 1.6.6.2 yamt for (m = so->so_rcv.sb_mb; m; m = n) {
383 1.6.6.2 yamt n = m->m_nextpkt;
384 1.6.6.2 yamt for (; m; m = m->m_next) {
385 1.6.6.2 yamt ccleft -= m->m_len;
386 1.6.6.2 yamt if (ccleft <= NCHRS) {
387 1.6.6.2 yamt char *src;
388 1.6.6.2 yamt int tocopy;
389 1.6.6.2 yamt
390 1.6.6.2 yamt tocopy = (NCHRS - ccleft) - copied;
391 1.6.6.2 yamt src = mtod(m, char *) + (m->m_len - tocopy);
392 1.6.6.2 yamt
393 1.6.6.2 yamt while (tocopy--) {
394 1.6.6.2 yamt switch (copied++) {
395 1.6.6.2 yamt case 0:
396 1.6.6.2 yamt a = *src++;
397 1.6.6.2 yamt break;
398 1.6.6.2 yamt case 1:
399 1.6.6.2 yamt b = *src++;
400 1.6.6.2 yamt break;
401 1.6.6.2 yamt case 2:
402 1.6.6.2 yamt c = *src++;
403 1.6.6.2 yamt break;
404 1.6.6.2 yamt }
405 1.6.6.2 yamt }
406 1.6.6.2 yamt }
407 1.6.6.2 yamt }
408 1.6.6.2 yamt }
409 1.6.6.2 yamt if (c == '\n' && (b == '\n' || (b == '\r' && a == '\n'))) {
410 1.6.6.2 yamt /* we have all request headers */
411 1.6.6.2 yamt goto gotit;
412 1.6.6.2 yamt }
413 1.6.6.2 yamt
414 1.6.6.2 yamt readmore:
415 1.6.6.2 yamt so->so_upcall = soishttpconnected;
416 1.6.6.2 yamt so->so_rcv.sb_flags |= SB_UPCALL;
417 1.6.6.2 yamt return;
418 1.6.6.2 yamt
419 1.6.6.2 yamt gotit:
420 1.6.6.2 yamt so->so_upcall = NULL;
421 1.6.6.2 yamt so->so_rcv.sb_flags &= ~SB_UPCALL;
422 1.6.6.2 yamt soisconnected(so);
423 1.6.6.2 yamt return;
424 1.6.6.2 yamt }
425