bb8862dd951f08cf769222c5760017c5ac08b030
[sdk] / samples / net / httpserver / http.ec
1 import "ecere"
2
3 static char * indexNames[] =
4 {
5    "index.html",
6    "index.htm",
7    "home.html",
8    "home.htm",
9    "welcome.html",
10    "welcome.htm",
11    "default.html",
12    "default.htm"
13 };
14
15 #define NUM_INDEX    (sizeof(indexNames) / sizeof(char *))
16
17 static void WriteFileName(File f, char * fileName)
18 {
19    byte ch;
20    int c;
21    for(c = 0; (ch = fileName[c]); c++)
22    {
23       if(ch <= 32 || ch > 128)
24       {
25          byte nibble;
26          f.Putc('%');
27          nibble = (ch & 0xF0) >> 4;
28          f.Putc((nibble > 9) ? (nibble - 10 + 'a') : (nibble + '0'));
29          nibble = ch & 0x0F;
30          f.Putc((nibble > 9) ? (nibble - 10 + 'a') : (nibble + '0'));
31       }
32       else
33          f.Putc(ch);
34    }
35 }
36
37 #define CONTENT_PATH   "."
38
39 static void CreateDirectoryListing(File f, char * directory)
40 {
41    FileListing listing { directory };
42
43    f.Puts("<HTML><HEAD></HEAD><BODY>\r\n");
44
45    if(directory[0] && directory[1] && (directory[1] != ':' || (directory[2] && directory[3])))
46       f.Puts("<A HREF=../>../</A><BR>\r\n");
47
48    while(listing.Find())
49    {
50       f.Puts("<A HREF=");
51       WriteFileName(f, listing.name);
52       if(listing.stats.attribs.isDirectory)
53          f.Puts("/");
54       f.Puts(">");
55       f.Puts(listing.name);
56       f.Puts("</A><BR>\r\n");
57    }
58
59    f.Puts("\r\n</BODY></HTML>\r\n");
60 }
61
62 static char * GetString(char * string, char * what, int count)
63 {
64    int c;
65    bool result = true;
66    for(c = 0; what[c]; c++)
67    {
68       if((count && c >= count) || (string[c] != what[c] && tolower(string[c]) != tolower(what[c])))
69          return null;
70    }
71    return string + c;
72 }
73
74 class HTTPClient : Socket
75 {
76    File f;
77    bool close;
78
79    #define ishexdigit(x) (isdigit(x) || (x >= 'a' && x<='f') || (x >= 'A' && x <= 'F'))
80
81    uint OnReceive(const byte * buffer, uint count)
82    {
83       int c;
84       for(c = 0; c<count-1; c++)
85       {
86          if(buffer[c] == '\r' && buffer[c+1] == '\n')
87             break;
88       }   
89       if(c<count)
90       {
91          char * string = (char *)buffer;
92
93          if((string = GetString((char *)buffer, "GET ", count)))
94          {
95             char reply[1024];
96             char path[MAX_LOCATION];
97             char addedPath[MAX_LOCATION];
98             int d, i;
99             FileAttribs attribs;
100             int len = 0;
101
102             strcpy(path, CONTENT_PATH);
103
104             for(d = c; d > 0 && string[d] != ' '; d--);
105             for(i = 0; i<d; i++)
106             {
107                if(string[i] == '%' && ishexdigit(string[i+1]) && ishexdigit(string[i+2]))
108                {
109                   char digits[3];
110                   digits[0] = string[i+1];
111                   digits[1] = string[i+2];
112                   digits[2] = '\0';
113                   addedPath[len++] = (byte)strtol(digits, null, 16);
114                   i += 2;
115                }
116                else
117                   addedPath[len++] = string[i];
118                addedPath[len] = '\0';
119             }
120
121             PathCat(path, addedPath+1);
122
123             attribs = FileExists(path);
124
125             if(attribs.isDirectory)
126             {
127                if(addedPath[len-1] != '/')
128                {
129                   strcpy(reply, "HTTP/1.1 301 Moved Permantently\r\n");
130
131                   strcat(reply, "Location: ");
132                   strcat(reply, addedPath);
133                   strcat(reply, "/\r\n");
134                   strcat(reply, "Content-Length: 0\r\n\r\n");
135                }
136                else
137                {
138                   int i;
139                   char indexFile[MAX_LOCATION];
140                   for(i = 0; i<NUM_INDEX; i++)
141                   {
142                      strcpy(indexFile, path);
143                      PathCat(indexFile, indexNames[i]);
144                      if(FileExists(indexFile).isFile)
145                      {
146                         f = FileOpen(indexFile, read);
147                         break;
148                      }               
149                   }
150                   // List contents if we didn't find an index
151                   if(i == NUM_INDEX)
152                   {
153                      f = TempFile {};
154                      if(f)
155                      {
156                         CreateDirectoryListing(f, path);
157                         f.Seek(0, start);
158                      }
159                   }
160                }
161             }
162             else if(attribs.isFile)
163                f = FileOpen(path, read);
164             else
165                strcpy(reply, "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n");
166
167             if(f)
168             {
169                char extension[MAX_EXTENSION];
170                uint size = f.GetSize();
171                sprintf(reply, "HTTP/1.1 200 OK\r\n");
172
173                GetExtension(addedPath, extension);
174                if(attribs.isDirectory || !strcmp(extension, "html") || !strcmp(extension, "htm"))
175                   strcat(reply, "Content-Type: text/html\r\n");
176                else
177                   strcat(reply, "Content-Type: text/plain\r\n");
178                sprintf(strchr(reply, 0), "Content-Length: %d\r\n\r\n", size);
179             }
180             SendString(reply);
181          }
182          return c+2;
183       }
184       return count;
185    }
186 }
187
188 class HTTPServer : Service
189 {
190    void OnAccept()
191    {
192       HTTPClient { this };
193    }
194 }
195
196 class HTTPApplication : GuiApplication
197 {
198    bool Init()
199    {
200       httpServer.Start();
201       return true;
202    }
203
204    bool Cycle(bool idle)
205    {
206       bool result = true;
207       HTTPClient client, next;
208       for(client = (HTTPClient)httpServer.firstClient; client; client = next)
209       {
210          next = (HTTPClient)client.next;
211          if(client.f)
212          {
213             #define PACKETSIZE      65536
214
215             static byte buffer[PACKETSIZE];
216             int read = client.f.Read(buffer, 1, PACKETSIZE);
217             
218             if(read)
219                client.Send(buffer, read);
220             if(client.f.Eof())
221             {
222                delete client.f;
223                if(client.close)
224                   client.Disconnect(0);
225             }
226
227             result = true;
228          }
229       }
230       return result;
231    }
232 }
233
234 HTTPServer httpServer { port = 8080 };
235
236 Window serverWindow { size = Size { 320, 200 }, text = "ECERE HTTP Server", hasMinimize = true, hasClose = true };