summaryrefslogtreecommitdiffstats
path: root/net/khttpd/rfc.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/khttpd/rfc.c')
-rw-r--r--net/khttpd/rfc.c374
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");
+}