| /* |
| |
| 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/slab.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 |
| transferred. |
| |
| */ |
| { |
| __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_t(unsigned int, 255, tmp - Buffer + PrefixLen); |
| |
| strncat(Head->FileName,Buffer,min_t(unsigned int, 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_t(unsigned int, 127,EOL-Buffer-1)); |
| |
| Buffer=EOL+1; |
| continue; |
| } |
| |
| if (strncmp("User-Agent: ",Buffer,12)==0) |
| { |
| Buffer+=12; |
| |
| strncpy(Head->Agent,Buffer,min_t(unsigned int, 127,EOL-Buffer-1)); |
| |
| Buffer=EOL+1; |
| continue; |
| } |
| |
| |
| if (strncmp("Host: ",Buffer,6)==0) |
| { |
| Buffer+=6; |
| |
| strncpy(Head->Host,Buffer,min_t(unsigned int, 127,EOL-Buffer-1)); |
| |
| Buffer=EOL+1; |
| continue; |
| } |
| #endif |
| Buffer = EOL+1; /* Skip line */ |
| } |
| LeaveFunction("ParseHeader"); |
| } |