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

Cache object: 71ad8741b1227afeeb97e83c9c97f28f


[ 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.