Rev Author Line No. Line
3328 povik 1 /**
2 * \addtogroup exampleapps
3 * @{
4 */
5  
6 /**
7 * \defgroup httpd Web server
8 * @{
9 *
10 * The uIP web server is a very simplistic implementation of an HTTP
11 * server. It can serve web pages and files from a read-only ROM
12 * filesystem, and provides a very small scripting language.
13 *
14 * The script language is very simple and works as follows. Each
15 * script line starts with a command character, either "i", "t", "c",
16 * "#" or ".". The "i" command tells the script interpreter to
17 * "include" a file from the virtual file system and output it to the
18 * web browser. The "t" command should be followed by a line of text
19 * that is to be output to the browser. The "c" command is used to
20 * call one of the C functions from the httpd-cgi.c file. A line that
21 * starts with a "#" is ignored (i.e., the "#" denotes a comment), and
22 * the "." denotes the last script line.
23 *
24 * The script that produces the file statistics page looks somewhat
25 * like this:
26 *
27 \code
28 i /header.html
29 t <h1>File statistics</h1><br><table width="100%">
30 t <tr><td><a href="/index.html">/index.html</a></td><td>
31 c a /index.html
32 t </td></tr> <tr><td><a href="/cgi/files">/cgi/files</a></td><td>
33 c a /cgi/files
34 t </td></tr> <tr><td><a href="/cgi/tcp">/cgi/tcp</a></td><td>
35 c a /cgi/tcp
36 t </td></tr> <tr><td><a href="/404.html">/404.html</a></td><td>
37 c a /404.html
38 t </td></tr></table>
39 i /footer.plain
40 .
41 \endcode
42 *
43 */
44  
45  
46 /**
47 * \file
48 * HTTP server.
49 * \author Adam Dunkels <adam@dunkels.com>
50 */
51  
52 /*
53 * Copyright (c) 2001, Adam Dunkels.
54 * All rights reserved.
55 *
56 * Redistribution and use in source and binary forms, with or without
57 * modification, are permitted provided that the following conditions
58 * are met:
59 * 1. Redistributions of source code must retain the above copyright
60 * notice, this list of conditions and the following disclaimer.
61 * 2. Redistributions in binary form must reproduce the above copyright
62 * notice, this list of conditions and the following disclaimer in the
63 * documentation and/or other materials provided with the distribution.
64 * 3. The name of the author may not be used to endorse or promote
65 * products derived from this software without specific prior
66 * written permission.
67 *
68 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
69 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
70 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
71 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
72 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
73 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
74 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
75 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
76 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
77 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
78 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
79 *
80 * This file is part of the uIP TCP/IP stack.
81 *
82 * $Id: httpd.c,v 1.28.2.6 2003/10/07 13:22:27 adam Exp $
83 *
84 */
85  
86 #include "stm32f10x.h"
87 #include "stm32_eval.h"
88 #include "uip.h"
89 #include "httpd.h"
90 #include "fs.h"
91 #include "fsdata.h"
92 #include "cgi.h"
93  
94 #define NULL (void *)0
95  
96 /* The HTTP server states: */
97 #define HTTP_NOGET 0
98 #define HTTP_FILE 1
99 #define HTTP_TEXT 2
100 #define HTTP_FUNC 3
101 #define HTTP_END 4
102  
103 #ifdef UIP_DEBUG
104 #include <stdio.h>
105 #define PRINT(x) printf("%s", x)
106 #define PRINTLN(x) printf("%s\n", x)
107 #else /* UIP_DEBUG */
108 #define PRINT(x)
109 #define PRINTLN(x)
110 #endif /* DEBUG */
111  
112 struct httpd_state *hs;
113  
114 extern const struct fsdata_file file_index_html;
115 extern const struct fsdata_file file_404_html;
116 extern const struct fsdata_file_noconst file_STM32_LED_html;
117 extern const struct fsdata_file_noconst file_STM32_StatusBar_html;
118  
119  
120 static void next_scriptline(void);
121 static void next_scriptstate(void);
122  
123 #define ISO_G 0x47
124 #define ISO_E 0x45
125 #define ISO_T 0x54
126 #define ISO_slash 0x2f
127 #define ISO_c 0x63
128 #define ISO_g 0x67
129 #define ISO_i 0x69
130 #define ISO_space 0x20
131 #define ISO_nl 0x0a
132 #define ISO_cr 0x0d
133 #define ISO_a 0x61
134 #define ISO_t 0x74
135 #define ISO_hash 0x23
136 #define ISO_period 0x2e
137  
138 char dataPresent;
139 char Digit1=0, Digit2=0, Digit3=0;
140 int ADCVal = 0;
141  
142 /*-----------------------------------------------------------------------------------*/
143 /**
144 * Initialize the web server.
145 *
146 * Starts to listen for incoming connection requests on TCP port 80.
147 */
148 /*-----------------------------------------------------------------------------------*/
149 void
150 httpd_init(void)
151 {
152 fs_init();
153  
154 /* Listen to port 80. */
155 uip_listen(HTONS(80));
156  
157 dataPresent = 0;
158 }
159 /*-----------------------------------------------------------------------------------*/
160 void
161 httpd_appcall(void)
162 {
163 struct fs_file fsfile;
164  
165 u8_t i;
166  
167 switch(uip_conn->lport) {
168 /* This is the web server: */
169 case HTONS(80):
170 /* Pick out the application state from the uip_conn structure. */
171 hs = (struct httpd_state *)(uip_conn->appstate);
172  
173 /* We use the uip_ test functions to deduce why we were
174 called. If uip_connected() is non-zero, we were called
175 because a remote host has connected to us. If
176 uip_newdata() is non-zero, we were called because the
177 remote host has sent us new data, and if uip_acked() is
178 non-zero, the remote host has acknowledged the data we
179 previously sent to it. */
180 if(uip_connected()) {
181 /* Since we have just been connected with the remote host, we
182 reset the state for this connection. The ->count variable
183 contains the amount of data that is yet to be sent to the
184 remote host, and the ->state is set to HTTP_NOGET to signal
185 that we haven't received any HTTP GET request for this
186 connection yet. */
187 hs->state = HTTP_NOGET;
188 hs->count = 0;
189 return;
190  
191 } else if(uip_poll()) {
192 /* If we are polled 200 times, we abort the connection. This is
193 because we don't want connections lingering indefinately in
194 the system. */
195 if(hs->count++ >= 200) {
196 // uip_abort();
197 }
198 return;
199 }
200 else
201 if(uip_newdata() && hs->state == HTTP_NOGET)
202 {
203 /* This is the first data we receive, and it should contain a
204 GET. */
205  
206 /* Check for GET. */
207 if(uip_appdata[0] != ISO_G ||
208 uip_appdata[1] != ISO_E ||
209 uip_appdata[2] != ISO_T ||
210 uip_appdata[3] != ISO_space) {
211 /* If it isn't a GET, we abort the connection. */
212 uip_abort();
213 return;
214 }
215  
216 /* Find the file we are looking for. */
217 for(i = 4; i < 40; ++i) {
218 if(uip_appdata[i] == ISO_space ||
219 uip_appdata[i] == ISO_cr ||
220 uip_appdata[i] == ISO_nl) {
221 uip_appdata[i] = 0;
222 break;
223 }
224 }
225  
226 PRINT("request for file ");
227 PRINTLN(&uip_appdata[4]);
228  
229 /* Check for a request for "/". */
230 if(uip_appdata[4] == ISO_slash &&
231 uip_appdata[5] == 0) {
232  
233 fs_open(file_index_html.name, &fsfile);
234  
235 }
236 else
237 {
238 if(!fs_open((const char *)&uip_appdata[4], &fsfile)) {
239 PRINTLN("couldn't open file");
240 fs_open(file_404_html.name, &fsfile);
241 }
242 }
243  
244 /* LED command -------------------------------------------*/
245 if(uip_appdata[4] == ISO_slash &&
246 uip_appdata[5] == 0x6D /*m*/ &&
247 uip_appdata[12] == 0x67 /*g*/)
248 {
249 i = 16;
250  
251 STM_EVAL_LEDOff(LED1);
252 STM_EVAL_LEDOff(LED2);
253 STM_EVAL_LEDOff(LED3);
254 STM_EVAL_LEDOff(LED4);
255  
256 while(uip_appdata[i]!=0x48/*H*/)
257 {
258 if(uip_appdata[i]==0x31 /*LED1*/)
259 {
260  
261 STM_EVAL_LEDOn(LED1);
262 }
263  
264 if(uip_appdata[i]==0x32 /*LED2*/)
265 {
266  
267 STM_EVAL_LEDOn(LED2);
268 }
269  
270 if(uip_appdata[i]==0x33 /*LED3*/)
271 {
272  
273 STM_EVAL_LEDOn(LED3);
274 }
275  
276 if(uip_appdata[i]==0x34 /*LED4*/)
277 {
278  
279 STM_EVAL_LEDOn(LED4);
280 }
281 i++;
282 }
283  
284 fs_open(file_STM32_LED_html.name, &fsfile);
285 }
286  
287 /* ADC Status Bar -------------------------------------------*/
288 if(uip_appdata[4] == ISO_slash &&
289 uip_appdata[5] == 0x53 /*S*/ &&
290 uip_appdata[11] == 0x53 /*S*/ &&
291 uip_appdata[12] == 0x74 /*t*/)
292 {
293 ADCVal = ADC_GetConversionValue(ADC1);
294 ADCVal = ADCVal/8;
295 Digit1= ADCVal/100;
296 Digit2= (ADCVal-(Digit1*100))/10;
297 Digit3= ADCVal-(Digit1*100)-(Digit2*10);
298 /* These are the "VAL" characters positions in the STM32_StatusBar.html
299 starting from file_STM32_StatusBar_html.name position */
300 *((file_STM32_StatusBar_html.name)+1768) = 0x30 + Digit1; /* ADC value */
301 *((file_STM32_StatusBar_html.name)+1769) = 0x30 + Digit2; /* ADC value */
302 *((file_STM32_StatusBar_html.name)+1770) = 0x30 + Digit3; /* ADC value */
303 fs_open(file_STM32_StatusBar_html.name, &fsfile);
304 }
305  
306 if(uip_appdata[4] == ISO_slash &&
307 uip_appdata[5] == ISO_c &&
308 uip_appdata[6] == ISO_g &&
309 uip_appdata[7] == ISO_i &&
310 uip_appdata[8] == ISO_slash)
311 {
312 /* If the request is for a file that starts with "/cgi/", we
313 prepare for invoking a script. */
314 hs->script = fsfile.data;
315 next_scriptstate();
316 }
317 else
318 {
319 hs->script = NULL;
320 /* The web server is now no longer in the HTTP_NOGET state, but
321 in the HTTP_FILE state since is has now got the GET from
322 the client and will start transmitting the file. */
323 hs->state = HTTP_FILE;
324  
325  
326  
327 /* Point the file pointers in the connection state to point to
328 the first byte of the file. */
329 hs->dataptr = fsfile.data;
330 hs->count = fsfile.len;
331 }
332 }
333  
334 if(hs->state != HTTP_FUNC) {
335 /* Check if the client (remote end) has acknowledged any data that
336 we've previously sent. If so, we move the file pointer further
337 into the file and send back more data. If we are out of data to
338 send, we close the connection. */
339 if(uip_acked()) {
340 if(hs->count >= uip_conn->len) {
341 hs->count -= uip_conn->len;
342 hs->dataptr += uip_conn->len;
343 } else {
344 hs->count = 0;
345 }
346  
347 if(hs->count == 0) {
348 if(hs->script != NULL) {
349 next_scriptline();
350 next_scriptstate();
351 } else {
352 uip_close();
353 }
354 }
355 }
356 } else
357 {
358 /* Call the CGI function. */
359 if(cgitab[hs->script[2] - ISO_a](uip_acked())) {
360 /* If the function returns non-zero, we jump to the next line
361 in the script. */
362 next_scriptline();
363 next_scriptstate();
364 }
365 }
366  
367 if(hs->state != HTTP_FUNC && !uip_poll()) {
368 /* Send a piece of data, but not more than the MSS of the
369 connection. */
370 uip_send((u8_t*)hs->dataptr, hs->count);
371  
372 dataPresent = 1;
373 }
374  
375 /* Finally, return to uIP. Our outgoing packet will soon be on its
376 way... */
377 return;
378  
379 default:
380 /* Should never happen. */
381 uip_abort();
382 break;
383 }
384 }
385 /*-----------------------------------------------------------------------------------*/
386 /* next_scriptline():
387 *
388 * Reads the script until it finds a newline. */
389 static void
390 next_scriptline(void)
391 {
392 /* Loop until we find a newline character. */
393 do {
394 ++(hs->script);
395 } while(hs->script[0] != ISO_nl);
396  
397 /* Eat up the newline as well. */
398 ++(hs->script);
399 }
400 /*-----------------------------------------------------------------------------------*/
401 /* next_sciptstate:
402 *
403 * Reads one line of script and decides what to do next.
404 */
405 static void
406 next_scriptstate(void)
407 {
408 struct fs_file fsfile;
409 u8_t i;
410  
411 again:
412 switch(hs->script[0]) {
413 case ISO_t:
414 /* Send a text string. */
415 hs->state = HTTP_TEXT;
416 hs->dataptr = &hs->script[2];
417  
418 /* Calculate length of string. */
419 for(i = 0; hs->dataptr[i] != ISO_nl; ++i);
420 hs->count = i;
421 break;
422 case ISO_c:
423 /* Call a function. */
424 hs->state = HTTP_FUNC;
425 hs->dataptr = NULL;
426 hs->count = 0;
427 cgitab[hs->script[2] - ISO_a](0);
428 break;
429 case ISO_i:
430 /* Include a file. */
431 hs->state = HTTP_FILE;
432 if(!fs_open(&hs->script[2], &fsfile)) {
433 uip_abort();
434 }
435 hs->dataptr = fsfile.data;
436 hs->count = fsfile.len;
437 break;
438 case ISO_hash:
439 /* Comment line. */
440 next_scriptline();
441 goto again;
442 //break;
443 case ISO_period:
444 /* End of script. */
445 hs->state = HTTP_END;
446 uip_close();
447 break;
448 default:
449 uip_abort();
450 break;
451 }
452 }
453 /*-----------------------------------------------------------------------------------*/
454 /** @} */
455 /** @} */