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
50) } HttpConns[4];
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;
|