File: /usr/src/linux/net/khttpd/rfc.c

1     /*
2     
3     kHTTPd -- the next generation
4     
5     RFC related functions (headers and stuff)
6     
7     */
8     
9     /****************************************************************
10      *	This program is free software; you can redistribute it and/or modify
11      *	it under the terms of the GNU General Public License as published by
12      *	the Free Software Foundation; either version 2, or (at your option)
13      *	any later version.
14      *
15      *	This program is distributed in the hope that it will be useful,
16      *	but WITHOUT ANY WARRANTY; without even the implied warranty of
17      *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18      *	GNU General Public License for more details.
19      *
20      *	You should have received a copy of the GNU General Public License
21      *	along with this program; if not, write to the Free Software
22      *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23      *
24      ****************************************************************/
25     
26     
27     #include <linux/kernel.h>
28     
29     #include <linux/ctype.h>
30     #include <linux/errno.h>
31     #include <linux/slab.h>
32     #include <linux/net.h>
33     #include <linux/sched.h>
34     #include <linux/skbuff.h>
35     #include <linux/unistd.h>
36     #include <linux/file.h>
37     #include <linux/smp_lock.h>
38     
39     #include <net/ip.h>
40     #include <net/sock.h>
41     
42     #include <asm/atomic.h>
43     #include <asm/semaphore.h>
44     #include <asm/processor.h>
45     #include <asm/uaccess.h>
46     
47     
48     #include "prototypes.h"
49     #include "structure.h"
50     #include "sysctl.h"
51     
52     
53     #define KHTTPD_NUMMIMETYPES 	40
54     
55     static atomic_t	MimeCount;
56     
57     struct MimeType
58     {
59     	__u32 	identifier;
60     	char	type[64-sizeof(__u32)-sizeof(__kernel_size_t)];  
61     	__kernel_size_t	len;
62     };
63     
64     static struct MimeType	MimeTypes[KHTTPD_NUMMIMETYPES];
65     
66     
67     void AddMimeType(const char *Ident,const char *Type)
68     {	
69     	__u32	*I;
70     	
71     	EnterFunction("AddMimeType");
72     	
73     	if (strlen(Ident)!=4) 
74        	{	
75        		(void)printk(KERN_ERR "httpd: Only 4-byte mime-identifiers are accepted\n");
76        		return;
77        	}
78     
79     	if (strlen(Type)>(64-sizeof(__u32)-sizeof(__kernel_size_t) ) )  
80        	{	
81        		(void)printk(KERN_ERR "httpd: Mime-string too long.\n");
82        		return;
83        	}
84        	
85        	I=(__u32*)Ident;
86        	
87        	/* FIXME: Need to lock-down all access to the mime-structure here */
88        	/*        For now, just don't add mime-types after initialisation */
89        	
90        	
91        	MimeTypes[atomic_read(&MimeCount)].identifier=*I;
92        	strncpy(MimeTypes[atomic_read(&MimeCount)].type,Type,(64-sizeof(__u32)-sizeof(__kernel_size_t)));
93        	MimeTypes[atomic_read(&MimeCount)].len = strlen(Type);
94        	
95        	atomic_inc(&MimeCount);
96        	LeaveFunction("AddMimeType");
97     }
98     
99     
100     char *ResolveMimeType(const char *File,__kernel_size_t *Len)
101     /*
102     
103     	The returned string is for READ ONLY, ownership of the memory is NOT
104     	transferred.
105     
106     */
107     {	
108     	__u32	*I;
109     	int pos,lc,filelen;
110     	
111     	EnterFunction("ResolveMimeType");
112     	
113     	*Len = 0;
114     	
115     	if (File==NULL)
116     		return NULL;
117     	
118     	filelen = (int)strlen(File);
119     	
120     	if (filelen<4) 
121        	{	
122        		return NULL;
123        	}
124        	
125        	/* The Merced-people are NOT going to like this! So this has to be fixed
126        	   in a later stage. */
127     
128     	pos = filelen-4;
129        	I=(__u32*)(File+pos);
130        	
131        	lc=0;
132        	
133        	while (lc<atomic_read(&MimeCount))
134      	{
135        		if (MimeTypes[lc].identifier == *I)
136        		{
137        			*Len = MimeTypes[lc].len;
138        			LeaveFunction("ResolveMimeType - success");
139        	  		return MimeTypes[lc].type;
140        	  	}
141        	  	lc++;
142        	} 	
143        	
144     	if (sysctl_khttpd_sloppymime)
145     	{
146     		*Len = MimeTypes[0].len;  
147     		LeaveFunction("ResolveMimeType - unknown");
148     	   	return MimeTypes[0].type;
149     	}
150     	else
151     	{
152     		LeaveFunction("ResolveMimeType - failure");
153     	   	return NULL;
154     	}
155     }
156     
157     
158     static char HeaderPart1[] = "HTTP/1.0 200 OK\r\nServer: kHTTPd/0.1.6\r\nDate: ";
159     #ifdef BENCHMARK
160     static char HeaderPart1b[] ="HTTP/1.0 200 OK";
161     #endif
162     static char HeaderPart3[] = "\r\nContent-type: ";
163     static char HeaderPart5[] = "\r\nLast-modified: ";
164     static char HeaderPart7[] = "\r\nContent-length: ";
165     static char HeaderPart9[] = "\r\n\r\n";
166     
167     #ifdef BENCHMARK
168     /* In BENCHMARK-mode, just send the bare essentials */
169     void SendHTTPHeader(struct http_request *Request)
170     {
171     	struct msghdr	msg;
172     	mm_segment_t	oldfs;
173     	struct iovec	iov[9];
174     	int 		len,len2;
175     	
176     	
177     	EnterFunction("SendHTTPHeader");
178     		
179     	msg.msg_name     = 0;
180     	msg.msg_namelen  = 0;
181     	msg.msg_iov	 = &iov[0];
182     	msg.msg_iovlen   = 6;
183     	msg.msg_control  = NULL;
184     	msg.msg_controllen = 0;
185     	msg.msg_flags    = 0;  /* Synchronous for now */
186     	
187     	iov[0].iov_base = HeaderPart1b;
188     	iov[0].iov_len  = 15;
189     	iov[1].iov_base = HeaderPart3;
190     	iov[1].iov_len  = 16;
191     	iov[2].iov_base = Request->MimeType;
192     	iov[2].iov_len  = Request->MimeLength;
193     	
194     	iov[3].iov_base = HeaderPart7;
195     	iov[3].iov_len  = 18;
196     	
197     	
198     	sprintf(Request->LengthS,"%i",Request->FileLength);
199     	iov[4].iov_base = Request->LengthS;
200     	iov[4].iov_len  = strlen(Request->LengthS);
201     	iov[5].iov_base = HeaderPart9;
202     	iov[5].iov_len  = 4;
203     	
204     	len2=15+16+18+iov[2].iov_len+iov[4].iov_len+4;
205     	
206     	
207     	len = 0;
208     	
209     
210     	oldfs = get_fs(); set_fs(KERNEL_DS);
211     	len = sock_sendmsg(Request->sock,&msg,len2);
212     	set_fs(oldfs);
213     
214     	
215     	return;	
216     }
217     #else
218     void SendHTTPHeader(struct http_request *Request)
219     {
220     	struct msghdr	msg;
221     	mm_segment_t	oldfs;
222     	struct iovec	iov[9];
223     	int 		len,len2;
224     	__kernel_size_t	slen;
225     	
226     	EnterFunction("SendHTTPHeader");
227     	
228     	msg.msg_name     = 0;
229     	msg.msg_namelen  = 0;
230     	msg.msg_iov	 = &(iov[0]);
231     	msg.msg_iovlen   = 9;
232     	msg.msg_control  = NULL;
233     	msg.msg_controllen = 0;
234     	msg.msg_flags    = 0;  /* Synchronous for now */
235     	
236     	iov[0].iov_base = HeaderPart1;
237     	iov[0].iov_len  = 45;
238     	iov[1].iov_base = CurrentTime;
239     	iov[1].iov_len  = 29;
240     	iov[2].iov_base = HeaderPart3;
241     	iov[2].iov_len  = 16;
242     	
243     	iov[3].iov_base = Request->MimeType;
244     	iov[3].iov_len  = Request->MimeLength;
245     	
246     	iov[4].iov_base = HeaderPart5;
247     	iov[4].iov_len  = 17;
248     	iov[5].iov_base = &(Request->TimeS[0]);
249     	iov[5].iov_len  = 29;
250     	iov[6].iov_base = HeaderPart7;
251     	iov[6].iov_len  = 18;
252     	iov[7].iov_base = &(Request->LengthS[0]);
253     	slen = strlen(Request->LengthS); 
254     	iov[7].iov_len  = slen;
255     	iov[8].iov_base = HeaderPart9;
256     	iov[8].iov_len  = 4;
257     	
258     	len2=45+2*29+16+17+18+slen+4+iov[3].iov_len;
259     	
260     	len = 0;
261     
262     	oldfs = get_fs(); set_fs(KERNEL_DS);
263     	len = sock_sendmsg(Request->sock,&msg,len2);
264     	set_fs(oldfs);
265     	LeaveFunction("SendHTTPHeader");
266     	
267     
268     	return;	
269     }
270     #endif
271     
272     
273     
274     /* 
275     
276     Parse a HTTP-header. Be careful for buffer-overflows here, this is the most important
277     place for this, since the remote-user controls the data.
278     
279     */
280     void ParseHeader(char *Buffer,const int length, struct http_request *Head)
281     {
282     	char *Endval,*EOL,*tmp;
283     	
284     	EnterFunction("ParseHeader");
285     	Endval = Buffer + length;
286     	
287     	/* We want to parse only the first header if multiple headers are present */
288     	tmp = strstr(Buffer,"\r\n\r\n"); 
289     	if (tmp!=NULL)
290     	    Endval = tmp;
291     	
292     	
293     	while (Buffer<Endval)
294     	{
295     		if (isspace(Buffer[0]))
296     		{
297     			Buffer++;
298     			continue;
299     		}
300     			
301     		
302     		EOL=strchr(Buffer,'\n');
303     		
304     		if (EOL==NULL) EOL=Endval;
305     		
306     		if (EOL-Buffer<4) 
307     		{
308     			Buffer++;
309     			continue;
310     		}
311     		
312     		if (strncmp("GET ",Buffer,4)==0)
313     		{
314     			int PrefixLen;
315     			Buffer+=4;
316     			
317     			tmp=strchr(Buffer,' ');
318     			if (tmp==0) 
319     			{
320     				tmp=EOL-1;
321     				Head->HTTPVER = 9;
322     			} else
323     				Head->HTTPVER = 10;
324     			
325     			if (tmp>Endval) continue;
326     			
327     			strncpy(Head->FileName,sysctl_khttpd_docroot,sizeof(Head->FileName));
328     			PrefixLen = strlen(sysctl_khttpd_docroot);
329     			Head->FileNameLength = min_t(unsigned int, 255, tmp - Buffer + PrefixLen);		
330     			
331     			strncat(Head->FileName,Buffer,min_t(unsigned int, 255 - PrefixLen, tmp - Buffer));
332     					
333     			Buffer=EOL+1;	
334     #ifdef BENCHMARK
335     			break;
336     #endif						
337     			continue;
338     		}
339     #ifndef BENCHMARK		
340     		if (strncmp("If-Modified-Since: ",Buffer,19)==0)
341     		{
342     			Buffer+=19;
343     			
344     			strncpy(Head->IMS,Buffer,min_t(unsigned int, 127,EOL-Buffer-1));
345     					
346     			Buffer=EOL+1;	
347     			continue;
348     		}
349     
350     		if (strncmp("User-Agent: ",Buffer,12)==0)
351     		{
352     			Buffer+=12;
353     			
354     			strncpy(Head->Agent,Buffer,min_t(unsigned int, 127,EOL-Buffer-1));
355     					
356     			Buffer=EOL+1;	
357     			continue;
358     		}
359     		
360     
361     		if (strncmp("Host: ",Buffer,6)==0)
362     		{
363     			Buffer+=6;
364     			
365     			strncpy(Head->Host,Buffer,min_t(unsigned int, 127,EOL-Buffer-1));
366     					
367     			Buffer=EOL+1;	
368     			continue;
369     		}
370     #endif		
371     		Buffer = EOL+1;  /* Skip line */
372     	}
373     	LeaveFunction("ParseHeader");
374     }
375