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
AddMimeType(const char * Ident,const char * Type)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
ResolveMimeType(const char * File,__kernel_size_t * Len)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 */
SendHTTPHeader(struct http_request * Request)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
SendHTTPHeader(struct http_request * Request)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 */
ParseHeader(char * Buffer,const int length,struct http_request * Head)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