diff options
Diffstat (limited to 'net/khttpd/rfc.c')
-rw-r--r-- | net/khttpd/rfc.c | 374 |
1 files changed, 374 insertions, 0 deletions
diff --git a/net/khttpd/rfc.c b/net/khttpd/rfc.c new file mode 100644 index 000000000..ff5e25451 --- /dev/null +++ b/net/khttpd/rfc.c @@ -0,0 +1,374 @@ +/* + +kHTTPd -- the next generation + +RFC related functions (headers and stuff) + +*/ + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + + +#include <linux/kernel.h> + +#include <linux/ctype.h> +#include <linux/errno.h> +#include <linux/malloc.h> +#include <linux/net.h> +#include <linux/sched.h> +#include <linux/skbuff.h> +#include <linux/unistd.h> +#include <linux/file.h> +#include <linux/smp_lock.h> + +#include <net/ip.h> +#include <net/sock.h> + +#include <asm/atomic.h> +#include <asm/semaphore.h> +#include <asm/processor.h> +#include <asm/uaccess.h> + + +#include "prototypes.h" +#include "structure.h" +#include "sysctl.h" + + +#define KHTTPD_NUMMIMETYPES 40 + +static atomic_t MimeCount; + +struct MimeType +{ + __u32 identifier; + char type[64-sizeof(__u32)-sizeof(__kernel_size_t)]; + __kernel_size_t len; +}; + +static struct MimeType MimeTypes[KHTTPD_NUMMIMETYPES]; + + +void AddMimeType(const char *Ident,const char *Type) +{ + __u32 *I; + + EnterFunction("AddMimeType"); + + if (strlen(Ident)!=4) + { + (void)printk(KERN_ERR "httpd: Only 4-byte mime-identifiers are accepted\n"); + return; + } + + if (strlen(Type)>(64-sizeof(__u32)-sizeof(__kernel_size_t) ) ) + { + (void)printk(KERN_ERR "httpd: Mime-string too long.\n"); + return; + } + + I=(__u32*)Ident; + + /* FIXME: Need to lock-down all access to the mime-structure here */ + /* For now, just don't add mime-types after initialisation */ + + + MimeTypes[atomic_read(&MimeCount)].identifier=*I; + strncpy(MimeTypes[atomic_read(&MimeCount)].type,Type,(64-sizeof(__u32)-sizeof(__kernel_size_t))); + MimeTypes[atomic_read(&MimeCount)].len = strlen(Type); + + atomic_inc(&MimeCount); + LeaveFunction("AddMimeType"); +} + + +char *ResolveMimeType(const char *File,__kernel_size_t *Len) +/* + + The returned string is for READ ONLY, ownership of the memory is NOT + transfered. + +*/ +{ + __u32 *I; + int pos,lc,filelen; + + EnterFunction("ResolveMimeType"); + + *Len = 0; + + if (File==NULL) + return NULL; + + filelen = (int)strlen(File); + + if (filelen<4) + { + return NULL; + } + + /* The Merced-people are NOT going to like this! So this has to be fixed + in a later stage. */ + + pos = filelen-4; + I=(__u32*)(File+pos); + + lc=0; + + while (lc<atomic_read(&MimeCount)) + { + if (MimeTypes[lc].identifier == *I) + { + *Len = MimeTypes[lc].len; + LeaveFunction("ResolveMimeType - success"); + return MimeTypes[lc].type; + } + lc++; + } + + if (sysctl_khttpd_sloppymime) + { + *Len = MimeTypes[0].len; + LeaveFunction("ResolveMimeType - unknown"); + return MimeTypes[0].type; + } + else + { + LeaveFunction("ResolveMimeType - failure"); + return NULL; + } +} + + +static char HeaderPart1[] = "HTTP/1.0 200 OK\r\nServer: kHTTPd/0.1.6\r\nDate: "; +#ifdef BENCHMARK +static char HeaderPart1b[] ="HTTP/1.0 200 OK"; +#endif +static char HeaderPart3[] = "\r\nContent-type: "; +static char HeaderPart5[] = "\r\nLast-modified: "; +static char HeaderPart7[] = "\r\nContent-length: "; +static char HeaderPart9[] = "\r\n\r\n"; + +#ifdef BENCHMARK +/* In BENCHMARK-mode, just send the bare essentials */ +void SendHTTPHeader(struct http_request *Request) +{ + struct msghdr msg; + mm_segment_t oldfs; + struct iovec iov[9]; + int len,len2; + + + EnterFunction("SendHTTPHeader"); + + msg.msg_name = 0; + msg.msg_namelen = 0; + msg.msg_iov = &iov[0]; + msg.msg_iovlen = 6; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; /* Synchronous for now */ + + iov[0].iov_base = HeaderPart1b; + iov[0].iov_len = 15; + iov[1].iov_base = HeaderPart3; + iov[1].iov_len = 16; + iov[2].iov_base = Request->MimeType; + iov[2].iov_len = Request->MimeLength; + + iov[3].iov_base = HeaderPart7; + iov[3].iov_len = 18; + + + sprintf(Request->LengthS,"%i",Request->FileLength); + iov[4].iov_base = Request->LengthS; + iov[4].iov_len = strlen(Request->LengthS); + iov[5].iov_base = HeaderPart9; + iov[5].iov_len = 4; + + len2=15+16+18+iov[2].iov_len+iov[4].iov_len+4; + + + len = 0; + + + oldfs = get_fs(); set_fs(KERNEL_DS); + len = sock_sendmsg(Request->sock,&msg,len2); + set_fs(oldfs); + + + return; +} +#else +void SendHTTPHeader(struct http_request *Request) +{ + struct msghdr msg; + mm_segment_t oldfs; + struct iovec iov[9]; + int len,len2; + __kernel_size_t slen; + + EnterFunction("SendHTTPHeader"); + + msg.msg_name = 0; + msg.msg_namelen = 0; + msg.msg_iov = &(iov[0]); + msg.msg_iovlen = 9; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; /* Synchronous for now */ + + iov[0].iov_base = HeaderPart1; + iov[0].iov_len = 45; + iov[1].iov_base = CurrentTime; + iov[1].iov_len = 29; + iov[2].iov_base = HeaderPart3; + iov[2].iov_len = 16; + + iov[3].iov_base = Request->MimeType; + iov[3].iov_len = Request->MimeLength; + + iov[4].iov_base = HeaderPart5; + iov[4].iov_len = 17; + iov[5].iov_base = &(Request->TimeS[0]); + iov[5].iov_len = 29; + iov[6].iov_base = HeaderPart7; + iov[6].iov_len = 18; + iov[7].iov_base = &(Request->LengthS[0]); + slen = strlen(Request->LengthS); + iov[7].iov_len = slen; + iov[8].iov_base = HeaderPart9; + iov[8].iov_len = 4; + + len2=45+2*29+16+17+18+slen+4+iov[3].iov_len; + + len = 0; + + oldfs = get_fs(); set_fs(KERNEL_DS); + len = sock_sendmsg(Request->sock,&msg,len2); + set_fs(oldfs); + LeaveFunction("SendHTTPHeader"); + + + return; +} +#endif + + + +/* + +Parse a HTTP-header. Be careful for buffer-overflows here, this is the most important +place for this, since the remote-user controls the data. + +*/ +void ParseHeader(char *Buffer,const int length, struct http_request *Head) +{ + char *Endval,*EOL,*tmp; + + EnterFunction("ParseHeader"); + Endval = Buffer + length; + + /* We want to parse only the first header if multiple headers are present */ + tmp = strstr(Buffer,"\r\n\r\n"); + if (tmp!=NULL) + Endval = tmp; + + + while (Buffer<Endval) + { + if (isspace(Buffer[0])) + { + Buffer++; + continue; + } + + + EOL=strchr(Buffer,'\n'); + + if (EOL==NULL) EOL=Endval; + + if (EOL-Buffer<4) + { + Buffer++; + continue; + } + + if (strncmp("GET ",Buffer,4)==0) + { + int PrefixLen; + Buffer+=4; + + tmp=strchr(Buffer,' '); + if (tmp==0) + { + tmp=EOL-1; + Head->HTTPVER = 9; + } else + Head->HTTPVER = 10; + + if (tmp>Endval) continue; + + strncpy(Head->FileName,sysctl_khttpd_docroot,sizeof(Head->FileName)); + PrefixLen = strlen(sysctl_khttpd_docroot); + Head->FileNameLength = min(255,tmp-Buffer+PrefixLen); + + strncat(Head->FileName,Buffer,min(255-PrefixLen,tmp-Buffer)); + + Buffer=EOL+1; +#ifdef BENCHMARK + break; +#endif + continue; + } +#ifndef BENCHMARK + if (strncmp("If-Modified-Since: ",Buffer,19)==0) + { + Buffer+=19; + + strncpy(Head->IMS,Buffer,min(127,EOL-Buffer-1)); + + Buffer=EOL+1; + continue; + } + + if (strncmp("User-Agent: ",Buffer,12)==0) + { + Buffer+=12; + + strncpy(Head->Agent,Buffer,min(127,EOL-Buffer-1)); + + Buffer=EOL+1; + continue; + } + + + if (strncmp("Host: ",Buffer,6)==0) + { + Buffer+=6; + + strncpy(Head->Host,Buffer,min(127,EOL-Buffer-1)); + + Buffer=EOL+1; + continue; + } +#endif + Buffer = EOL+1; /* Skip line */ + } + LeaveFunction("ParseHeader"); +} |