[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/accf_http.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

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

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.