ed647c2e0811e113ee32af099b8f930acfa367ba
Stefan Schuermans header fix

Stefan Schuermans authored 12 years ago

1) /* flaneth - flash and ethernet
2)    Copyright (C) 2007-2012 Stefan Schuermans <stefan@schuermans.info>
3)    Copyleft: GNU public license V2 - http://www.gnu.org/copyleft/gpl.html
4)    a BlinkenArea project - http://www.blinkenarea.org/ */
Stefan Schuermans initial commit after making...

Stefan Schuermans authored 12 years ago

5) 
6) #include <string.h>
7) #include <avr/pgmspace.h>
8) 
9) #include "debug.h"
10) #include "http.h"
11) #include "macros.h"
12) #include "tcp.h"
13) 
14) // receive states while parsing HTTP request
15) #define HTTP_RCV_CMD 0  // receiving HTTP command (e.g. GET)
16) #define HTTP_RCV_FILE 1 // receiving filename
17) #define HTTP_RCV_HDR_END 2      // receiving header until end
18) #define HTTP_RCV_DONE 3 // receiving completed
19) 
20) // knwon HTTP commands
21) #define HTTP_CMD_UNKNOWN 0      // unknown HTTP command
22) #define HTTP_CMD_GET 1  // GET command
23) 
24) // files available using HTTP
25) #define HTTP_FILE_NOT_FOUND 0   // file not found file
26) #define HTTP_FILE_INDEX 1       // index file
27) #define HTTP_FILE_ON_ALL 2      // turn on all link
28) #define HTTP_FILE_ON_SINGLE 3   // turn on single links (+0..+7)
29) #define HTTP_FILE_OFF_ALL 11    // turn off all link
30) #define HTTP_FILE_OFF_SINGLE 12 // turn off single links (+0..+7)
31) #define HTTP_FILE_IMG1 20       // image: on
32) #define HTTP_FILE_IMG0 21       // image: off
33) 
34) // content of webpages and strings to fill in for variables
35) #include "http_content.inc"
36) 
37) // table with HTTP connections
38) struct HttpConnection {
39)   unsigned char ConnNo; // number of the TCP connection, 0xFF is unused
40)   unsigned long RcvCnt; // number of received bytes on connection
41)   unsigned char RcvState;       // what is being received at the moment
42)   unsigned char RcvBuf[16];     // receive buffer
43)   unsigned char RcvBufLen;      // length of data in receive buffer
44)   unsigned char Command;        // the command the client issued
45)   char PreHttp1;        // flag if a HTTP version before 1.0 is used
46)   unsigned char File;   // the file the client requested
47)   uint16_t pSndData;    // the data to send (progmem pointer)
48)   unsigned short SndDataLen;    // the length of the data to send
49)   char Vars;    // flag if to interpret variables
Stefan Schuermans save memory, to avoid stack...

Stefan Schuermans authored 12 years ago

50) } HttpConns[2];
Stefan Schuermans initial commit after making...

Stefan Schuermans authored 12 years ago

51) 
52) // parse HTTP command
53) static void HttpParseCommand(struct HttpConnection *pConn)
54) {
55)   // GET command
56)   if (pConn->RcvBufLen == 3
57)       && strncasecmp((const char *)pConn->RcvBuf, "GET", 3) == 0)
58)     pConn->Command = HTTP_CMD_GET;
59)   // unknown command is the default
60)   else
61)     pConn->Command = HTTP_CMD_UNKNOWN;
62) }
63) 
64) // parse HTTP file
65) static void HttpParseFile(struct HttpConnection *pConn)
66) {
67)   // index file
68)   if ((pConn->RcvBufLen == 1
69)        && strncasecmp((const char *)pConn->RcvBuf, "/", 1) == 0)
70)       || (pConn->RcvBufLen == 2
71)           && strncasecmp((const char *)pConn->RcvBuf, "/i", 2) == 0))
72)     pConn->File = HTTP_FILE_INDEX;
73)   // turn on all link
74)   else if (pConn->RcvBufLen == 3
75)            && strncasecmp((const char *)pConn->RcvBuf, "/on", 3) == 0)
76)     pConn->File = HTTP_FILE_ON_ALL;
77)   // turn on single link
78)   else if (pConn->RcvBufLen == 4
79)            && strncasecmp((const char *)pConn->RcvBuf, "/on", 3) == 0
80)            && pConn->RcvBuf[3] >= '1' && pConn->RcvBuf[3] <= '8')
81)     pConn->File = HTTP_FILE_ON_SINGLE + pConn->RcvBuf[3] - '1';
82)   // turn off all link
83)   else if (pConn->RcvBufLen == 4
84)            && strncasecmp((const char *)pConn->RcvBuf, "/off", 4) == 0)
85)     pConn->File = HTTP_FILE_OFF_ALL;
86)   // turn off single link
87)   else if (pConn->RcvBufLen == 5
88)            && strncasecmp((const char *)pConn->RcvBuf, "/off", 4) == 0
89)            && pConn->RcvBuf[4] >= '1' && pConn->RcvBuf[4] <= '8')
90)     pConn->File = HTTP_FILE_OFF_SINGLE + pConn->RcvBuf[4] - '1';
91)   // image: on
92)   else if (pConn->RcvBufLen == 5
93)            && strncasecmp((const char *)pConn->RcvBuf, "/img1", 5) == 0)
94)     pConn->File = HTTP_FILE_IMG1;
95)   // image: off
96)   else if (pConn->RcvBufLen == 5
97)            && strncasecmp((const char *)pConn->RcvBuf, "/img0", 5) == 0)
98)     pConn->File = HTTP_FILE_IMG0;
99)   // error file is the default
100)   else
101)     pConn->File = HTTP_FILE_NOT_FOUND;
102) }
103) 
104) // process HTTP request
105) static void HttpProcessRequest(struct HttpConnection *pConn)
106) {
107)   // different commands
108)   switch (pConn->Command) {
109) 
110)   case HTTP_CMD_GET:
111)     // different actions
112)     switch (pConn->File) {
113) 
114)     case HTTP_FILE_ON_ALL:
115)       pConn->File = HTTP_FILE_INDEX;    // "symlink" to index file
116)       break;
117) 
118)     case HTTP_FILE_ON_SINGLE + 0:
119)     case HTTP_FILE_ON_SINGLE + 1:
120)     case HTTP_FILE_ON_SINGLE + 2:
121)     case HTTP_FILE_ON_SINGLE + 3:
122)     case HTTP_FILE_ON_SINGLE + 4:
123)     case HTTP_FILE_ON_SINGLE + 5:
124)     case HTTP_FILE_ON_SINGLE + 6:
125)     case HTTP_FILE_ON_SINGLE + 7:
126)       pConn->File = HTTP_FILE_INDEX;    // "symlink" to index file
127)       break;
128) 
129)     case HTTP_FILE_OFF_ALL:
130)       pConn->File = HTTP_FILE_INDEX;    // "symlink" to index file
131)       break;
132) 
133)     case HTTP_FILE_OFF_SINGLE + 0:
134)     case HTTP_FILE_OFF_SINGLE + 1:
135)     case HTTP_FILE_OFF_SINGLE + 2:
136)     case HTTP_FILE_OFF_SINGLE + 3:
137)     case HTTP_FILE_OFF_SINGLE + 4:
138)     case HTTP_FILE_OFF_SINGLE + 5:
139)     case HTTP_FILE_OFF_SINGLE + 6:
140)     case HTTP_FILE_OFF_SINGLE + 7:
141)       pConn->File = HTTP_FILE_INDEX;    // "symlink" to index file
142)       break;
143) 
144)     }   // switch( pConn->File )
145) 
146)     // different files
147)     switch (pConn->File) {
148) 
149)     case HTTP_FILE_INDEX:
150)       if (pConn->PreHttp1) {
151)         pConn->pSndData = (uint16_t) HttpIndex + HttpIndexHeaderSize;
152)         pConn->SndDataLen = sizeof(HttpIndex) - 1 - HttpIndexHeaderSize;
153)       } else {
154)         pConn->pSndData = (uint16_t) HttpIndex;
155)         pConn->SndDataLen = sizeof(HttpIndex) - 1;
156)       }
157)       pConn->Vars = 1;
158)       break;
159) 
160)     case HTTP_FILE_IMG1:
161)       if (pConn->PreHttp1) {
162)         pConn->pSndData = (uint16_t) HttpImg1 + HttpImg1HeaderSize;
163)         pConn->SndDataLen = sizeof(HttpImg1) - 1 - HttpImg1HeaderSize;
164)       } else {
165)         pConn->pSndData = (uint16_t) HttpImg1;
166)         pConn->SndDataLen = sizeof(HttpImg1) - 1;
167)       }
168)       pConn->Vars = 0;
169)       break;
170) 
171)     case HTTP_FILE_IMG0:
172)       if (pConn->PreHttp1) {
173)         pConn->pSndData = (uint16_t) HttpImg0 + HttpImg0HeaderSize;
174)         pConn->SndDataLen = sizeof(HttpImg0) - 1 - HttpImg0HeaderSize;
175)       } else {
176)         pConn->pSndData = (uint16_t) HttpImg0;
177)         pConn->SndDataLen = sizeof(HttpImg0) - 1;
178)       }
179)       pConn->Vars = 0;
180)       break;
181) 
182)     case HTTP_FILE_NOT_FOUND:
183)     default:
184)       if (pConn->PreHttp1) {
185)         pConn->pSndData = (uint16_t) HttpNotFound + HttpNotFoundHeaderSize;
186)         pConn->SndDataLen = sizeof(HttpNotFound) - 1 - HttpNotFoundHeaderSize;
187)       } else {
188)         pConn->pSndData = (uint16_t) HttpNotFound;
189)         pConn->SndDataLen = sizeof(HttpNotFound) - 1;
190)       }
191)       pConn->Vars = 0;
192) 
193)     }   // switch( pConn->File )
194)     break;
195) 
196)   case HTTP_CMD_UNKNOWN:
197)   default:
198)     if (pConn->PreHttp1) {
199)       pConn->pSndData = (uint16_t) HttpBadRequest + HttpBadRequestHeaderSize;
200)       pConn->SndDataLen =
201)           sizeof(HttpBadRequest) - 1 - HttpBadRequestHeaderSize;
202)     } else {
203)       pConn->pSndData = (uint16_t) HttpBadRequest;
204)       pConn->SndDataLen = sizeof(HttpBadRequest) - 1;
205)     }
206)     pConn->Vars = 0;
207) 
208)   }     // switch( pConn->Command )
209) }
210) 
211) // get a variable
212) // returns progmem pointer to variable and the length of the variable
213) static void HttpGetVariable(unsigned char VarNo, uint16_t * ppVar,
214)                             unsigned char *pVarLen)
215) {
216)   switch (VarNo) {
217) 
218)     // current state of output 1..8 ("ON" or "off")
219)   case 0x81:
220)   case 0x82:
221)   case 0x83:
222)   case 0x84:
223)   case 0x85:
224)   case 0x86:
225)   case 0x87:
226)   case 0x88:
227)     *ppVar = (uint16_t) HttpVarOff;
228)     *pVarLen = sizeof(HttpVarOff);
229)     break;
230) 
231)     // current state of output 1..8 ("1" or "0")
232)   case 0x91:
233)   case 0x92:
234)   case 0x93:
235)   case 0x94:
236)   case 0x95:
237)   case 0x96:
238)   case 0x97:
239)   case 0x98:
240)     *ppVar = (uint16_t) HttpVar0;
241)     *pVarLen = sizeof(HttpVar0);
242)     break;
243) 
244)     // unknown variable
245)   default:
246)     *ppVar = (uint16_t) HttpVarUnknown;
247)     *pVarLen = sizeof(HttpVarUnknown);
248)     break;
249) 
250)   }     // switch( VarNo );
251) }
252) 
253) // called when connection is established
254) void HttpConnect(unsigned char ConnNo)
255) {
256)   unsigned char i;
257)   struct HttpConnection *pConn;
258) 
259)   // find connection in table (in case TCP calls us twice, this should never
260)   // happen)
261)   for (i = 0; i < count(HttpConns); i++)
262)     if (HttpConns[i].ConnNo == ConnNo)
263)       break;
264)   // connection not found
265)   if (i >= count(HttpConns)) {
266)     // find a free entry
267)     for (i = 0; i < count(HttpConns); i++)
268)       if (HttpConns[i].ConnNo == 0xFF)
269)         break;
270)     if (i >= count(HttpConns))  // no free entry found
271)       return;   // ignore this connection (will be closed in first call of
272)                 // HttpSend)
273)   }
274)   // get pointer to connection
275)   pConn = &HttpConns[i];
276) 
277)   debug_http_printf("accept no=%u", ConnNo);
278) 
279)   // put new connection into table
280)   pConn->ConnNo = ConnNo;
281)   pConn->RcvCnt = 0;
282)   pConn->RcvState = HTTP_RCV_CMD;
283)   pConn->RcvBufLen = 0;
284) }
285) 
286) // called when connection is closed / reset
287) // (after this, the connection number may not be used any more)
288) void HttpClose(unsigned char ConnNo)
289) {
290)   unsigned char i;
291)   struct HttpConnection *pConn;
292) 
293)   // find connection in table
294)   for (i = 0; i < count(HttpConns); i++)
295)     if (HttpConns[i].ConnNo == ConnNo)
296)       break;
297)   if (i >= count(HttpConns))    // connection not found
298)     return;     // ignore this (now already closed) connection
299)   // get pointer to connection
300)   pConn = &HttpConns[i];
301) 
302)   debug_http_printf("close no=%u", ConnNo);
303) 
304)   // drop connection from table
305)   pConn->ConnNo = 0xFF;
306) }
307) 
308) // called when sending data is possible
309) // (return length of available data, 0xFFFF to close connection)
310) unsigned short HttpSend(unsigned char ConnNo, unsigned long Pos,
311)                         unsigned char *pBuffer, unsigned short MaxLen)
312) {
313)   unsigned char i, var, VarLen, VarPos;
314)   struct HttpConnection *pConn;
315)   unsigned short len, j;
316)   uint16_t src, srcTmp, pVar;   // progmem pointer
317)   char chr, *dest;
318) 
319)   // find connection in table
320)   for (i = 0; i < count(HttpConns); i++)
321)     if (HttpConns[i].ConnNo == ConnNo)
322)       break;
323)   if (i >= count(HttpConns))    // connection not found
324)     return 0xFFFF;      // close connection
325)   // get pointer to connection
326)   pConn = &HttpConns[i];
327) 
328)   // not done with receiving
329)   if (pConn->RcvState != HTTP_RCV_DONE)
330)     return 0;   // do not send anything yet
331) 
332)   // at or behind end of data
333)   if (Pos >= (unsigned long)pConn->SndDataLen)
334)     return 0xFFFF;      // request to close connection
335) 
336)   // get number of bytes to send
337)   len = min(pConn->SndDataLen - (unsigned short)Pos, MaxLen);
338)   if (len == 0) // nothing to send
339)     return 0;
340) 
341)   // no variable in variable buffer
342)   var = 0;
343)   VarLen = 0;
344)   VarPos = 0;
Stefan Schuermans keep compiler happy - initi...

Stefan Schuermans authored 12 years ago

345)   pVar = 0; // keep compiler happy - initialize
Stefan Schuermans initial commit after making...

Stefan Schuermans authored 12 years ago

346)   // if part that should be sent starts with variable
347)   src = pConn->pSndData + (uint16_t) Pos;
348)   chr = (char)pgm_read_byte_near(src);  // read first character
349)   if (pConn->Vars && (unsigned char)chr >= 0x80) {
350)     // get variable
351)     var = chr;
352)     HttpGetVariable(var, &pVar, &VarLen);
353)     // get position in variable
354)     for (VarPos = 0, srcTmp = src - 1; srcTmp > pConn->pSndData;
355)          VarPos++, srcTmp--)
356)       if ((char)pgm_read_byte_near(srcTmp) != var)      // if normal
357)                                                         // character or other 
358)                                                         // variable, we found 
359)                                                         // the begin of the
360)                                                         // variable
361)         break;
362)   }
363)   // copy data to buffer
364)   dest = (char *)pBuffer;
365)   for (j = 0; j < len; j++) {
366)     // read current character
367)     chr = (char)pgm_read_byte_near(src);
368)     // variable
369)     if (pConn->Vars && (unsigned char)chr >= 0x80) {
370)       // new variable
371)       if (var != chr) {
372)         // get variable
373)         var = chr;
374)         HttpGetVariable(var, &pVar, &VarLen);
375)         VarPos = 0;
376)       }
377)       // copy next character of variable
378)       if (VarPos < VarLen)      // get next character of variable
379)         *dest = (char)pgm_read_byte_near(pVar + VarPos++);
380)       else
381)         *dest = ' ';    // fill rest of variable with spaces
382)     }
383)     // normal character
384)     else {
385)       var = 0;  // not a variable
386)       *dest = chr;      // copy character
387)     }
388)     // next character
389)     src++;
390)     dest++;
391)   }     // for( j ...
392) 
393)   // return length of data in buffer
394)   debug_http_printf("send no=%u pos=%lu len=%u", ConnNo, Pos, len);
395)   return len;
396) }
397) 
398) // called when data was sent and ACKed
399) void HttpSent(unsigned char ConnNo, unsigned long Pos)
400) {
401)   // nothing needs to be done here
Stefan Schuermans make more warnings visible...

Stefan Schuermans authored 12 years ago

402)   (void)ConnNo;
403)   (void)Pos;