The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

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

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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  *      $FreeBSD: releng/5.0/sys/netinet/accf_http.c 98385 2002-06-18 07:42:02Z tanimura $
   28  */
   29 
   30 #define ACCEPT_FILTER_MOD
   31 
   32 #include <sys/param.h>
   33 #include <sys/kernel.h>
   34 #include <sys/mbuf.h>
   35 #include <sys/signalvar.h>
   36 #include <sys/sysctl.h>
   37 #include <sys/socketvar.h>
   38 
   39 /* check for GET/HEAD */
   40 static void sohashttpget(struct socket *so, void *arg, int waitflag);
   41 /* check for HTTP/1.0 or HTTP/1.1 */
   42 static void soparsehttpvers(struct socket *so, void *arg, int waitflag);
   43 /* check for end of HTTP/1.x request */
   44 static void soishttpconnected(struct socket *so, void *arg, int waitflag);
   45 /* strcmp on an mbuf chain */
   46 static int mbufstrcmp(struct mbuf *m, struct mbuf *npkt, int offset, char *cmp);
   47 /* strncmp on an mbuf chain */
   48 static int mbufstrncmp(struct mbuf *m, struct mbuf *npkt, int offset,
   49         int max, char *cmp);
   50 /* socketbuffer is full */
   51 static int sbfull(struct sockbuf *sb);
   52 
   53 static struct accept_filter accf_http_filter = {
   54         "httpready",
   55         sohashttpget,
   56         NULL,
   57         NULL
   58 };
   59 
   60 static moduledata_t accf_http_mod = {
   61         "accf_http",
   62         accept_filt_generic_mod_event,
   63         &accf_http_filter
   64 };
   65 
   66 DECLARE_MODULE(accf_http, accf_http_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
   67 
   68 static int parse_http_version = 1;
   69 
   70 SYSCTL_NODE(_net_inet_accf, OID_AUTO, http, CTLFLAG_RW, 0,
   71 "HTTP accept filter");
   72 SYSCTL_INT(_net_inet_accf_http, OID_AUTO, parsehttpversion, CTLFLAG_RW,
   73 &parse_http_version, 1,
   74 "Parse http version so that non 1.x requests work");
   75 
   76 #ifdef ACCF_HTTP_DEBUG
   77 #define DPRINT(fmt, args...)                                            \
   78         do {                                                            \
   79                 printf("%s:%d: " fmt "\n", __func__, __LINE__, ##args); \
   80         } while (0)
   81 #else
   82 #define DPRINT(fmt, args...)
   83 #endif
   84 
   85 static int
   86 sbfull(struct sockbuf *sb)
   87 {
   88 
   89         DPRINT("sbfull, cc(%ld) >= hiwat(%ld): %d, "
   90             "mbcnt(%ld) >= mbmax(%ld): %d",
   91             sb->sb_cc, sb->sb_hiwat, sb->sb_cc >= sb->sb_hiwat,
   92             sb->sb_mbcnt, sb->sb_mbmax, sb->sb_mbcnt >= sb->sb_mbmax);
   93         return (sb->sb_cc >= sb->sb_hiwat || sb->sb_mbcnt >= sb->sb_mbmax);
   94 }
   95 
   96 /*
   97  * start at mbuf m, (must provide npkt if exists)
   98  * starting at offset in m compare characters in mbuf chain for 'cmp'
   99  */
  100 static int
  101 mbufstrcmp(struct mbuf *m, struct mbuf *npkt, int offset, char *cmp)
  102 {
  103         struct mbuf *n;
  104 
  105         for (; m != NULL; m = n) {
  106                 n = npkt;
  107                 if (npkt)
  108                         npkt = npkt->m_nextpkt;
  109                 for (; m; m = m->m_next) {
  110                         for (; offset < m->m_len; offset++, cmp++) {
  111                                 if (*cmp == '\0')
  112                                         return (1);
  113                                 else if (*cmp != *(mtod(m, char *) + offset))
  114                                         return (0);
  115                         }
  116                         if (*cmp == '\0')
  117                                 return (1);
  118                         offset = 0;
  119                 }
  120         }
  121         return (0);
  122 }
  123 
  124 /*
  125  * start at mbuf m, (must provide npkt if exists)
  126  * starting at offset in m compare characters in mbuf chain for 'cmp'
  127  * stop at 'max' characters
  128  */
  129 static int
  130 mbufstrncmp(struct mbuf *m, struct mbuf *npkt, int offset, int max, char *cmp)
  131 {
  132         struct mbuf *n;
  133 
  134         for (; m != NULL; m = n) {
  135                 n = npkt;
  136                 if (npkt)
  137                         npkt = npkt->m_nextpkt;
  138                 for (; m; m = m->m_next) {
  139                         for (; offset < m->m_len; offset++, cmp++, max--) {
  140                                 if (max == 0 || *cmp == '\0')
  141                                         return (1);
  142                                 else if (*cmp != *(mtod(m, char *) + offset))
  143                                         return (0);
  144                         }
  145                         if (max == 0 || *cmp == '\0')
  146                                 return (1);
  147                         offset = 0;
  148                 }
  149         }
  150         return (0);
  151 }
  152 
  153 #define STRSETUP(sptr, slen, str)                                       \
  154         do {                                                            \
  155                 sptr = str;                                             \
  156                 slen = sizeof(str) - 1;                                 \
  157         } while(0)
  158 
  159 static void
  160 sohashttpget(struct socket *so, void *arg, int waitflag)
  161 {
  162 
  163         if ((so->so_state & SS_CANTRCVMORE) == 0 && !sbfull(&so->so_rcv)) {
  164                 struct mbuf *m;
  165                 char *cmp;
  166                 int     cmplen, cc;
  167 
  168                 m = so->so_rcv.sb_mb;
  169                 cc = so->so_rcv.sb_cc - 1;
  170                 if (cc < 1)
  171                         return;
  172                 switch (*mtod(m, char *)) {
  173                 case 'G':
  174                         STRSETUP(cmp, cmplen, "ET ");
  175                         break;
  176                 case 'H':
  177                         STRSETUP(cmp, cmplen, "EAD ");
  178                         break;
  179                 default:
  180                         goto fallout;
  181                 }
  182                 if (cc < cmplen) {
  183                         if (mbufstrncmp(m, m->m_nextpkt, 1, cc, cmp) == 1) {
  184                                 DPRINT("short cc (%d) but mbufstrncmp ok", cc);
  185                                 return;
  186                         } else {
  187                                 DPRINT("short cc (%d) mbufstrncmp failed", cc);
  188                                 goto fallout;
  189                         }
  190                 }
  191                 if (mbufstrcmp(m, m->m_nextpkt, 1, cmp) == 1) {
  192                         DPRINT("mbufstrcmp ok");
  193                         if (parse_http_version == 0)
  194                                 soishttpconnected(so, arg, waitflag);
  195                         else
  196                                 soparsehttpvers(so, arg, waitflag);
  197                         return;
  198                 }
  199                 DPRINT("mbufstrcmp bad");
  200         }
  201 
  202 fallout:
  203         DPRINT("fallout");
  204         so->so_upcall = NULL;
  205         so->so_rcv.sb_flags &= ~SB_UPCALL;
  206         soisconnected(so);
  207         return;
  208 }
  209 
  210 static void
  211 soparsehttpvers(struct socket *so, void *arg, int waitflag)
  212 {
  213         struct mbuf *m, *n;
  214         int     i, cc, spaces, inspaces;
  215 
  216         if ((so->so_state & SS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv))
  217                 goto fallout;
  218 
  219         m = so->so_rcv.sb_mb;
  220         cc = so->so_rcv.sb_cc;
  221         inspaces = spaces = 0;
  222         for (m = so->so_rcv.sb_mb; m; m = n) {
  223                 n = m->m_nextpkt;
  224                 for (; m; m = m->m_next) {
  225                         for (i = 0; i < m->m_len; i++, cc--) {
  226                                 switch (*(mtod(m, char *) + i)) {
  227                                 case ' ':
  228                                         /* tabs? '\t' */
  229                                         if (!inspaces) {
  230                                                 spaces++;
  231                                                 inspaces = 1;
  232                                         }
  233                                         break;
  234                                 case '\r':
  235                                 case '\n':
  236                                         DPRINT("newline");
  237                                         goto fallout;
  238                                 default:
  239                                         if (spaces != 2) {
  240                                                 inspaces = 0;
  241                                                 break;
  242                                         }
  243 
  244                                         /*
  245                                          * if we don't have enough characters
  246                                          * left (cc < sizeof("HTTP/1.0") - 1)
  247                                          * then see if the remaining ones
  248                                          * are a request we can parse.
  249                                          */
  250                                         if (cc < sizeof("HTTP/1.0") - 1) {
  251                                                 if (mbufstrncmp(m, n, i, cc,
  252                                                         "HTTP/1.") == 1) {
  253                                                         DPRINT("ok");
  254                                                         goto readmore;
  255                                                 } else {
  256                                                         DPRINT("bad");
  257                                                         goto fallout;
  258                                                 }
  259                                         } else if (
  260                                             mbufstrcmp(m, n, i, "HTTP/1.0") ||
  261                                             mbufstrcmp(m, n, i, "HTTP/1.1")) {
  262                                                         DPRINT("ok");
  263                                                         soishttpconnected(so,
  264                                                             arg, waitflag);
  265                                                         return;
  266                                         } else {
  267                                                 DPRINT("bad");
  268                                                 goto fallout;
  269                                         }
  270                                 }
  271                         }
  272                 }
  273         }
  274 readmore:
  275         DPRINT("readmore");
  276         /*
  277          * if we hit here we haven't hit something
  278          * we don't understand or a newline, so try again
  279          */
  280         so->so_upcall = soparsehttpvers;
  281         so->so_rcv.sb_flags |= SB_UPCALL;
  282         return;
  283 
  284 fallout:
  285         DPRINT("fallout");
  286         so->so_upcall = NULL;
  287         so->so_rcv.sb_flags &= ~SB_UPCALL;
  288         soisconnected(so);
  289         return;
  290 }
  291 
  292 
  293 #define NCHRS 3
  294 
  295 static void
  296 soishttpconnected(struct socket *so, void *arg, int waitflag)
  297 {
  298         char a, b, c;
  299         struct mbuf *m, *n;
  300         int ccleft, copied;
  301 
  302         DPRINT("start");
  303         if ((so->so_state & SS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv))
  304                 goto gotit;
  305 
  306         /*
  307          * Walk the socketbuffer and copy the last NCHRS (3) into a, b, and c
  308          * copied - how much we've copied so far
  309          * ccleft - how many bytes remaining in the socketbuffer
  310          * just loop over the mbufs subtracting from 'ccleft' until we only
  311          * have NCHRS left
  312          */
  313         copied = 0;
  314         ccleft = so->so_rcv.sb_cc;
  315         if (ccleft < NCHRS)
  316                 goto readmore;
  317         a = b = c = '\0';
  318         for (m = so->so_rcv.sb_mb; m; m = n) {
  319                 n = m->m_nextpkt;
  320                 for (; m; m = m->m_next) {
  321                         ccleft -= m->m_len;
  322                         if (ccleft <= NCHRS) {
  323                                 char *src;
  324                                 int tocopy;
  325 
  326                                 tocopy = (NCHRS - ccleft) - copied;
  327                                 src = mtod(m, char *) + (m->m_len - tocopy);
  328 
  329                                 while (tocopy--) {
  330                                         switch (copied++) {
  331                                         case 0:
  332                                                 a = *src++;
  333                                                 break;
  334                                         case 1:
  335                                                 b = *src++;
  336                                                 break;
  337                                         case 2:
  338                                                 c = *src++;
  339                                                 break;
  340                                         }
  341                                 }
  342                         }
  343                 }
  344         }
  345         if (c == '\n' && (b == '\n' || (b == '\r' && a == '\n'))) {
  346                 /* we have all request headers */
  347                 goto gotit;
  348         }
  349 
  350 readmore:
  351         so->so_upcall = soishttpconnected;
  352         so->so_rcv.sb_flags |= SB_UPCALL;
  353         return;
  354 
  355 gotit:
  356         so->so_upcall = NULL;
  357         so->so_rcv.sb_flags &= ~SB_UPCALL;
  358         soisconnected(so);
  359         return;
  360 }

Cache object: 5eff0a5821516cde7ac075bdbb6398c0


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


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