accf_http.c revision 61837
1117395Skan/*- 2169689Skan * Copyright (c) 2000 Alfred Perlstein <alfred@FreeBSD.org> 3117395Skan * All rights reserved. 4117395Skan * 5117395Skan * Redistribution and use in source and binary forms, with or without 6169689Skan * modification, are permitted provided that the following conditions 7117395Skan * are met: 8132718Skan * 1. Redistributions of source code must retain the above copyright 9117395Skan * notice, this list of conditions and the following disclaimer. 10132718Skan * 2. Redistributions in binary form must reproduce the above copyright 11132718Skan * notice, this list of conditions and the following disclaimer in the 12132718Skan * documentation and/or other materials provided with the distribution. 13132718Skan * 14117395Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15132718Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16132718Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17132718Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18132718Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19117395Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20132718Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21132718Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22169689Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24117395Skan * SUCH DAMAGE. 25117395Skan * 26117395Skan * $FreeBSD: head/sys/netinet/accf_http.c 61837 2000-06-20 01:09:23Z alfred $ 27132718Skan */ 28132718Skan 29117395Skan#define ACCEPT_FILTER_MOD 30117395Skan 31169689Skan#include <sys/param.h> 32117395Skan#include <sys/systm.h> 33169689Skan#include <sys/sysproto.h> 34169689Skan#include <sys/kernel.h> 35117395Skan#include <sys/proc.h> 36169689Skan#include <sys/malloc.h> 37169689Skan#include <sys/unistd.h> 38117395Skan#include <sys/file.h> 39169689Skan#include <sys/fcntl.h> 40169689Skan#include <sys/protosw.h> 41117395Skan#include <sys/socket.h> 42117395Skan#include <sys/socketvar.h> 43117395Skan#include <sys/stat.h> 44117395Skan#include <sys/mbuf.h> 45117395Skan#include <sys/resource.h> 46117395Skan#include <sys/sysent.h> 47117395Skan#include <sys/resourcevar.h> 48117395Skan 49117395Skan/* 50117395Skan * XXX: doesn't work with 0.9 requests, make a seperate filter 51169689Skan * based on this one if you want to decode those. 52169689Skan */ 53169689Skan 54169689Skan/* check for GET */ 55117395Skanstatic void sohashttpget(struct socket *so, void *arg, int waitflag); 56117395Skan/* check for end of HTTP request */ 57117395Skanstatic void soishttpconnected(struct socket *so, void *arg, int waitflag); 58132718Skanstatic char sbindex(struct mbuf **mp, int *begin, int end); 59117395Skan 60117395Skanstatic struct accept_filter accf_http_filter = { 61117395Skan "httpready", 62117395Skan sohashttpget, 63117395Skan NULL, 64117395Skan NULL 65169689Skan}; 66117395Skan 67169689Skanstatic moduledata_t accf_http_mod = { 68117395Skan "accf_http", 69169689Skan accept_filt_generic_mod_event, 70117395Skan &accf_http_filter 71117395Skan}; 72169689Skan 73117395SkanDECLARE_MODULE(accf_http, accf_http_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 74117395Skan 75169689Skan 76169689Skanstatic char 77117395Skansbindex(struct mbuf **mp, int *begin, int end) 78169689Skan{ 79117395Skan struct mbuf *m = *mp; 80117395Skan int diff = end - *begin + 1; 81117395Skan 82117395Skan while (m->m_len < diff) { 83117395Skan *begin += m->m_len; 84117395Skan diff -= m->m_len; 85117395Skan if (m->m_next) { 86117395Skan m = m->m_next; 87117395Skan } else if (m->m_nextpkt) { 88117395Skan m = m->m_nextpkt; 89132718Skan } else { 90117395Skan /* only happens if end > data in socket buffer */ 91117395Skan panic("sbindex: not enough data"); 92117395Skan } 93117395Skan } 94117395Skan *mp = m; 95117395Skan return *(mtod(m, char *) + diff - 1); 96117395Skan} 97169689Skan 98169689Skanstatic void 99169689Skansohashttpget(struct socket *so, void *arg, int waitflag) 100169689Skan{ 101117395Skan 102117395Skan if ((so->so_state & SS_CANTRCVMORE) == 0) { 103169689Skan struct mbuf *m; 104169689Skan 105169689Skan if (so->so_rcv.sb_cc < 6) 106169689Skan return; 107169689Skan m = so->so_rcv.sb_mb; 108169689Skan if (bcmp(mtod(m, char *), "GET ", 4) == 0) { 109117395Skan soishttpconnected(so, arg, waitflag); 110117395Skan return; 111117395Skan } 112146895Skan } 113146895Skan 114146895Skan so->so_upcall = NULL; 115146895Skan so->so_rcv.sb_flags &= ~SB_UPCALL; 116146895Skan soisconnected(so); 117146895Skan return; 118146895Skan} 119146895Skan 120146895Skanstatic void 121117395Skansoishttpconnected(struct socket *so, void *arg, int waitflag) 122117395Skan{ 123117395Skan char a, b, c; 124117395Skan struct mbuf *y, *z; 125117395Skan 126117395Skan if ((so->so_state & SS_CANTRCVMORE) == 0) { 127117395Skan /* seek to end and keep track of next to last mbuf */ 128169689Skan y = so->so_rcv.sb_mb; 129169689Skan while (y->m_nextpkt) 130169689Skan y = y->m_nextpkt; 131117395Skan z = y; 132117395Skan while (y->m_next) { 133117395Skan z = y; 134117395Skan y = y->m_next; 135117395Skan } 136117395Skan 137117395Skan if (z->m_len + y->m_len > 2) { 138117395Skan int index = y->m_len - 1; 139117395Skan 140117395Skan c = *(mtod(y, char *) + index--); 141117395Skan switch (index) { 142117395Skan case -1: 143117395Skan y = z; 144117395Skan index = y->m_len - 1; 145117395Skan b = *(mtod(y, char *) + index--); 146117395Skan break; 147117395Skan case 0: 148117395Skan b = *(mtod(y, char *) + index--); 149117395Skan y = z; 150117395Skan index = y->m_len - 1; 151117395Skan break; 152117395Skan default: 153169689Skan b = *(mtod(y, char *) + index--); 154169689Skan break; 155169689Skan } 156169689Skan a = *(mtod(y, char *) + index--); 157117395Skan } else { 158169689Skan int begin = 0; 159169689Skan int end = so->so_rcv.sb_cc - 3; 160169689Skan 161169689Skan y = so->so_rcv.sb_mb; 162169689Skan a = sbindex(&y, &begin, end++); 163169689Skan b = sbindex(&y, &begin, end++); 164169689Skan c = sbindex(&y, &begin, end++); 165169689Skan } 166169689Skan 167169689Skan if (c == '\n' && (b == '\n' || (b == '\r' && a == '\n'))) { 168169689Skan /* we have all request headers */ 169169689Skan goto done; 170169689Skan } else { 171169689Skan /* still need more data */ 172169689Skan so->so_upcall = soishttpconnected; 173169689Skan so->so_rcv.sb_flags |= SB_UPCALL; 174169689Skan return; 175169689Skan } 176169689Skan } 177169689Skan 178169689Skandone: 179169689Skan so->so_upcall = NULL; 180169689Skan so->so_rcv.sb_flags &= ~SB_UPCALL; 181169689Skan soisconnected(so); 182169689Skan return; 183169689Skan} 184169689Skan