A simple web server that can be bound to either the EthernetInterface or the WiflyInterface.
Dependents: Smart-WiFly-WebServer WattEye X10Svr SSDP_Server
Diff: SW_HTTPServer.cpp
- Revision:
- 8:262583f054f6
- Parent:
- 7:99ad7a67f05e
- Child:
- 9:2ea342765c9d
diff -r 99ad7a67f05e -r 262583f054f6 SW_HTTPServer.cpp --- a/SW_HTTPServer.cpp Thu Jun 27 17:08:25 2013 +0000 +++ b/SW_HTTPServer.cpp Mon Jul 01 04:36:54 2013 +0000 @@ -14,17 +14,17 @@ #include "SW_HTTPServer.h" #include "Utility.h" -#define DEBUG +//#define DEBUG const char * DEFAULT_FILENAME = "index.htm"; -// Header information to always send -const char hdr_httpver[] = "HTTP/1.1"; // typically HTTP/1.0 or HTTP/1.1 -const char hdr_age[] = "Max-age: 0\r\n"; // expires right away (must be \r\n terminated) -const char hdr_server[] = "Server: Smart_Server v0.1\r\n"; // Server (must be \r\n terminated) -const char hdr_dnt[] = "DNT: 1\r\n"; // Do Not Track -const char hdr_close[] = "Connection: close\r\n"; // tell the client to close the connection (must be \r\n terminated) -const char nl[] = "\r\n"; // final \r\n for the termination of the header +// Header information to always send (must be \r\n terminated) +const char hdr_httpver[] = "HTTP/1.0"; // typically HTTP/1.0 or HTTP/1.1 +const char hdr_age[] = "Max-age: 0\r\n"; // expires right away +const char hdr_server[] = "Server: Smart_Server v0.1\r\n"; // Server +const char hdr_dnt[] = "DNT: 1\r\n"; // Do Not Track +const char hdr_close[] = "Connection: close\r\n"; // tell the client to close the connection +const char nl[] = "\r\n"; // final \r\n for the termination of the header static const struct { char *ext; @@ -45,6 +45,21 @@ {0,0} }; +#ifdef DEBUG +static void * MyMalloc(int x, int y) +{ + std::printf("[%04d] malloc(%d)\r\n", y, x); + return malloc(x); +} +#define mymalloc(x) MyMalloc(x, __LINE__) +#define myfree(x) \ + pc->printf("[%04d] free(%02x %02x %02x %02x ...\r\n", __LINE__, *x, *(x+1), *(x+2), *(x+3)); \ + free(x); +#else +#define mymalloc(x) malloc(x) +#define myfree(x) free(x) +#endif + HTTPServer::HTTPServer( Wifly * _wf, int port, @@ -77,16 +92,23 @@ server = new TCPSocketServer(); server->bind(port); server->listen(); - server->set_blocking(false, 0); - client.set_blocking(false, 0); - server->accept(client); +// server->set_blocking(false, 0); +// client.set_blocking(false, 0); +// server->accept(client); ResetPerformanceData(); timer.start(); } HTTPServer::~HTTPServer() { - free(webroot); + int i; + + for (i=0; i<handlercount; i++) + myfree(handlers[i].path); + myfree(headerbuffer); + myfree(handlers); + myfree(params); + myfree(webroot); webroot = NULL; } @@ -98,7 +120,7 @@ bool HTTPServer::RegisterHandler(const char * path, Handler callback) { if (handlercount < maxdynamicpages && path && callback) { - handlers[handlercount].path = (char *)malloc(strlen(path)+1); + handlers[handlercount].path = (char *)mymalloc(strlen(path)+1); memcpy(handlers[handlercount].path, path, strlen(path)+1); handlers[handlercount].callback = callback; handlercount++; @@ -128,33 +150,39 @@ Reset } state; static state op = Idle; - static state lastOp = Reset; static char * bPtr = headerbuffer; int n; static int t_ref; // reference point for the timer - #ifdef DEBUG +#ifdef DEBUG + static state lastOp = Reset; if (lastOp != op) { - pc->printf("%d", op); + char *states[] = {"Idle", "Receiving", "Sending", "WaitingToClose", "Reset"}; + pc->printf("Poll: %s\r\n", states[op]); lastOp = op; } - #endif +#endif switch(op) { default: // not expected to arrive here op = Idle; break; + case Idle: timer.reset(); bPtr = headerbuffer; - if (0 == client.receive(bPtr, 0)) { // server->accept(client) == 0) { + if (0 == server->accept(client)) { // client.receive(bPtr, 0)) { // server->accept(client) == 0) { op = Receiving; t_ref = timer.read_us(); +#ifdef DEBUG + pc->printf("Accept at %d\r\n", t_ref); +#endif } break; + case Receiving: n = client.receive(bPtr, headerbuffersize - (bPtr - headerbuffer)); if (n < 0) { - ; // pc->printf("*** client.receive error: %d\r\n", n); + pc->printf("*** client.receive() => %d\r\n", n); } else if (n) { bPtr[n] = '\0'; if (ParseHeader(headerbuffer)) { @@ -164,6 +192,7 @@ bPtr += n; } break; + case Sending: SendResponse(); op = WaitingToClose; @@ -207,7 +236,7 @@ fp = fopen(filename,"rb"); if (fp) { // can open it - char *fbuffer = (char *)malloc(FILESEND_BUF_SIZE); + char *fbuffer = (char *)mymalloc(FILESEND_BUF_SIZE); int bytes; if (fbuffer) { @@ -217,7 +246,7 @@ send(fbuffer, bytes); bytes = fread(fbuffer,sizeof(char),FILESEND_BUF_SIZE,fp); } - free(fbuffer); + myfree(fbuffer); } else { header(500, "Server Error", "Pragma: err - insufficient memory\r\n"); } @@ -383,19 +412,23 @@ char * get = strstr(haystack, needle); // what if not at the front? if (get) { // Seems to be a valid "...GET /QueryString HTTP/1.1" + // or "...<needle>param..." qs = get + strlen(needle); // in case the needle didn't have space delimiters while (*qs == ' ') qs++; // /QueryString\0HTTP/1.1\0\0 if (*string) // recycle old string when working a new one - free(*string); - container = (char *)malloc(strlen(qs)); + myfree(*string); + container = (char *)mymalloc(strlen(qs)); if (container) { strcpy(container, qs); eqs = strchr(container, ' '); if (eqs) *eqs = '\0'; *string = container; +#ifdef DEBUG + pc->printf("Extract(%s) = %s\r\n", needle, container); +#endif ret = true; } else { *string = NULL; // something bad happened... no memory @@ -406,13 +439,13 @@ char * HTTPServer::rewriteWithDefaultFile(char * queryString) { - char * temp = (char *)malloc(strlen(queryString) + strlen(DEFAULT_FILENAME) + 1); + char * temp = (char *)mymalloc(strlen(queryString) + strlen(DEFAULT_FILENAME) + 1); if (temp) { *temp = '\0'; strcpy(temp, queryString); strcat(temp, DEFAULT_FILENAME); - free(queryString); + myfree(queryString); return temp; } else { return queryString; @@ -421,7 +454,7 @@ char * HTTPServer::rewritePrependWebroot(char * queryString) { - char * temp = (char *)malloc(strlen(webroot) + strlen(queryString) + 1); + char * temp = (char *)mymalloc(strlen(webroot) + strlen(queryString) + 1); if (temp) { *temp = '\0'; @@ -429,7 +462,7 @@ if (temp[strlen(temp)-1] == '/' && *queryString == '/') temp[strlen(temp)-1] = '\0'; strcat(temp, queryString); - free(queryString); + myfree(queryString); return temp; } else { return queryString; @@ -453,10 +486,16 @@ void HTTPServer::SendResponse() { +#ifdef DEBUG + pc->printf("SendResponse(%s) [%d]\r\n", queryType, __LINE__); +#endif if (strcmp(queryType, "GET") == 0 || strcmp(queryType, "POST") == 0) { if (!(queryString[0] == '.' && queryString[1] == '.')) { const char * fType; +#ifdef DEBUG + pc->printf(" SendResponse() [%d]\r\n", __LINE__); +#endif if (!CheckDynamicHandlers()) { // Otherwise, this queryString must be trying to reference a static file if (queryString[strlen(queryString)-1] == '/') { @@ -481,27 +520,27 @@ header(400, "Bad Request", "Pragma: err - Unsupported query type\r\n"); } if (queryType) { - free(queryType); + myfree(queryType); queryType = NULL; } if (queryString) { - free(queryString); + myfree(queryString); queryString = NULL; } if (hostString) { - free(hostString); + myfree(hostString); hostString = NULL; } if (contentLength) { - free(contentLength); + myfree(contentLength); contentLength = NULL; } if (contentType) { - free(contentType); + myfree(contentType); contentType = NULL; } if (postQueryString) { - free(postQueryString); + myfree(postQueryString); postQueryString = NULL; } } @@ -517,15 +556,13 @@ // when it is done. wifly->setConnectionState(true); // Buffer could have partial, but the double \r\n is the key - // *OPEN*QueryType QueryString HTTP/1.1.... - // QueryType:= GET - // *OPEN*GET /QueryString HTTP/1.1\r\n - // *OPEN*GET /QueryString HTTP/1.1\r\nHeader stuf - // *OPEN*GET /QueryString HTTP/1.1\r\nHeader stuff...\r\n\r\n + // GET /QueryString HTTP/1.1\r\n + // GET /QueryString HTTP/1.1\r\nHost: 192.168.1.140\r\nCache-Con + // GET /QueryString HTTP/1.1\r\nHost: 192.168.1.140\r\nCache-Control: max-age=0\r\n\r\n dblCR = strstr(buffer,"\r\n\r\n"); if (dblCR) { // Have to scan from the beginning in case split on \r -#if 0 - pc->printf("\r\n\r\nThe Header:\r\n%s\r\n\r\n", buffer); +#ifdef DEBUG + pc->printf("==\r\n%s==\r\n", buffer); #endif char * soRec = buffer; // start of the next record of text char * eoRec = strchr(soRec, '\n'); // search for end of a record @@ -537,10 +574,24 @@ *eoRec = '\0'; if (*(eoRec-1) == '\r') *(eoRec-1) = '\0'; - if (!Extract(soRec, "*OPEN*", &queryType)) - Extract(soRec, "*CLOS*", &queryType); - if (queryType) - Extract(soRec, queryType, &queryString); + #ifdef DEBUG + pc->printf("rec {%s}\r\n", soRec); + #endif + // Inspect the supported query types (GET, POST) and ignore (HEAD, PUT, OPTION, DELETE, TRACE, CONNECT] + // This is very clumsy + if (strstr(soRec, "GET ") == soRec) { + Extract(soRec, "GET", &queryString); + if (queryString) { + queryType = (char *)mymalloc(strlen("GET")+1); + strcpy(queryType, "GET"); + } + } else if (strstr(soRec, "POST ") == soRec) { + Extract(soRec, "POST", &queryString); + if (queryString) { + queryType = (char *)mymalloc(strlen("POST")+1); + strcpy(queryType, "POST"); + } + } Extract(soRec, "Host: ", &hostString); Extract(soRec, "Content-Length: ", &contentLength); Extract(soRec, "Content-Type: ", &contentType); @@ -549,7 +600,9 @@ } if (queryString) { // We have enough to try to reply - //pc->printf("create reply queryType{%s}, queryString{%s}\r\n", queryType, queryString); + #ifdef DEBUG + pc->printf("create reply queryType{%s}, queryString{%s}\r\n", "GET", queryString); + #endif // parse params - if any // /file.htm?name1=value1&name2=value2... // /file.htm?name1&name2=value2... @@ -563,7 +616,7 @@ //for (int i=0; i<paramcount; i++) // pc->printf("param %d '%s'='%s'\r\n", i, params[i].name, params[i].value); } else { - pc->printf("not found\r\n"); + pc->printf("ERROR: queryString not found\r\n"); } advanceState = true; buffer[0] = 0; @@ -593,7 +646,7 @@ if (regHandled && acceptIt) { // If so, we'll make space for it - postQueryString = (char *)malloc(postBytes + 1); + postQueryString = (char *)mymalloc(postBytes + 1); if (postQueryString) { char * offset; int len; @@ -618,7 +671,7 @@ } else { // Simply copy it to the bitbucket int bytesToDump = postBytes; - char * bitbucket = (char *)malloc(201); + char * bitbucket = (char *)mymalloc(201); dblCR += 4; while (*dblCR && *dblCR <= ' ') dblCR++; @@ -628,7 +681,7 @@ n = client.receive(bitbucket, n); bytesToDump -= n; } - free(bitbucket); + myfree(bitbucket); } } }