Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of SW_HTTPServer by
SW_HTTPServer.cpp@28:f93ef41b78e1, 2013-10-11 (annotated)
- Committer:
- WiredHome
- Date:
- Fri Oct 11 02:33:46 2013 +0000
- Revision:
- 28:f93ef41b78e1
- Parent:
- 27:90a1f5a5392f
- Child:
- 29:00116fc9da74
Revised the return value from the callback in preparation for more complex transactions.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
WiredHome | 0:729320f63c5c | 1 | // |
WiredHome | 2:a29c32190037 | 2 | // @note Copyright © 2013 by Smartware Computing, all rights reserved. |
WiredHome | 0:729320f63c5c | 3 | // Individuals may use this application for evaluation or non-commercial |
WiredHome | 0:729320f63c5c | 4 | // purposes. Within this restriction, changes may be made to this application |
WiredHome | 0:729320f63c5c | 5 | // as long as this copyright notice is retained. The user shall make |
WiredHome | 0:729320f63c5c | 6 | // clear that their work is a derived work, and not the original. |
WiredHome | 0:729320f63c5c | 7 | // Users of this application and sources accept this application "as is" and |
WiredHome | 0:729320f63c5c | 8 | // shall hold harmless Smartware Computing, for any undesired results while |
WiredHome | 0:729320f63c5c | 9 | // using this application - whether real or imagined. |
WiredHome | 0:729320f63c5c | 10 | // |
WiredHome | 0:729320f63c5c | 11 | // author David Smart, Smartware Computing |
WiredHome | 0:729320f63c5c | 12 | // |
WiredHome | 0:729320f63c5c | 13 | #include "mbed.h" |
WiredHome | 0:729320f63c5c | 14 | #include "SW_HTTPServer.h" |
WiredHome | 0:729320f63c5c | 15 | #include "Utility.h" |
WiredHome | 0:729320f63c5c | 16 | |
WiredHome | 27:90a1f5a5392f | 17 | #define DEBUG "HTTP" |
WiredHome | 27:90a1f5a5392f | 18 | |
WiredHome | 27:90a1f5a5392f | 19 | #if (defined(DEBUG) && !defined(TARGET_LPC11U24)) |
WiredHome | 27:90a1f5a5392f | 20 | #define DBG(x, ...) std::printf("[DBG %s%4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); |
WiredHome | 27:90a1f5a5392f | 21 | #define WARN(x, ...) std::printf("[WRN %s%4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); |
WiredHome | 27:90a1f5a5392f | 22 | #define ERR(x, ...) std::printf("[ERR %s%4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); |
WiredHome | 27:90a1f5a5392f | 23 | #define INFO(x, ...) std::printf("[INF %s%4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); |
WiredHome | 27:90a1f5a5392f | 24 | #else |
WiredHome | 27:90a1f5a5392f | 25 | #define DBG(x, ...) |
WiredHome | 27:90a1f5a5392f | 26 | #define WARN(x, ...) |
WiredHome | 27:90a1f5a5392f | 27 | #define ERR(x, ...) |
WiredHome | 27:90a1f5a5392f | 28 | #define INFO(x, ...) |
WiredHome | 27:90a1f5a5392f | 29 | #endif |
WiredHome | 27:90a1f5a5392f | 30 | |
WiredHome | 0:729320f63c5c | 31 | |
WiredHome | 0:729320f63c5c | 32 | const char * DEFAULT_FILENAME = "index.htm"; |
WiredHome | 0:729320f63c5c | 33 | |
WiredHome | 8:262583f054f6 | 34 | // Header information to always send (must be \r\n terminated) |
WiredHome | 17:69ff00ce39f4 | 35 | const char hdr_httpver[] = "HTTP/1.0"; // Wifly may not be able to support HTTP/1.1 protocol |
WiredHome | 8:262583f054f6 | 36 | const char hdr_age[] = "Max-age: 0\r\n"; // expires right away |
WiredHome | 8:262583f054f6 | 37 | const char hdr_server[] = "Server: Smart_Server v0.1\r\n"; // Server |
WiredHome | 17:69ff00ce39f4 | 38 | const char hdr_close[] = "Connection: close\r\n"; // tell the client the server closes the connection immediately |
WiredHome | 8:262583f054f6 | 39 | const char nl[] = "\r\n"; // final \r\n for the termination of the header |
WiredHome | 0:729320f63c5c | 40 | |
WiredHome | 14:19c5f6151319 | 41 | |
WiredHome | 0:729320f63c5c | 42 | static const struct { |
WiredHome | 0:729320f63c5c | 43 | char *ext; |
WiredHome | 0:729320f63c5c | 44 | char *filetype; |
WiredHome | 0:729320f63c5c | 45 | } extensions [] = { |
WiredHome | 3:17928786bdb5 | 46 | {".gif", "Content-Type: image/gif\r\n" }, |
WiredHome | 3:17928786bdb5 | 47 | {".jpg", "Content-Type: image/jpeg\r\n" }, |
WiredHome | 3:17928786bdb5 | 48 | {".jpeg","Content-Type: image/jpeg\r\n" }, |
WiredHome | 3:17928786bdb5 | 49 | {".ico", "Content-Type: image/x-icon\r\n" }, |
WiredHome | 3:17928786bdb5 | 50 | {".png", "Content-Type: image/png\r\n" }, |
WiredHome | 3:17928786bdb5 | 51 | {".zip", "Content-Type: image/zip\r\n" }, |
WiredHome | 3:17928786bdb5 | 52 | {".gz", "Content-Type: image/gz\r\n" }, |
WiredHome | 3:17928786bdb5 | 53 | {".tar", "Content-Type: image/tar\r\n" }, |
WiredHome | 3:17928786bdb5 | 54 | {".txt", "Content-Type: plain/text\r\n" }, |
WiredHome | 3:17928786bdb5 | 55 | {".pdf", "Content-Type: application/pdf\r\n" }, |
WiredHome | 3:17928786bdb5 | 56 | {".htm", "Content-Type: text/html\r\n" }, |
WiredHome | 3:17928786bdb5 | 57 | {".html","Content-Type: text/html\r\n" }, |
WiredHome | 0:729320f63c5c | 58 | {0,0} |
WiredHome | 0:729320f63c5c | 59 | }; |
WiredHome | 0:729320f63c5c | 60 | |
WiredHome | 8:262583f054f6 | 61 | #ifdef DEBUG |
WiredHome | 12:109bf1558300 | 62 | // This uses standard library dynamic memory management, but for an |
WiredHome | 9:2ea342765c9d | 63 | // embedded system there are alternates that may make better sense - |
WiredHome | 9:2ea342765c9d | 64 | // search the web for embedded system malloc alternates. |
WiredHome | 8:262583f054f6 | 65 | static void * MyMalloc(int x, int y) |
WiredHome | 8:262583f054f6 | 66 | { |
WiredHome | 25:f7d6df7a700a | 67 | std::printf("[INF HTTP%4d] malloc(%d)\r\n", y, x); |
WiredHome | 8:262583f054f6 | 68 | return malloc(x); |
WiredHome | 8:262583f054f6 | 69 | } |
WiredHome | 11:17d84c41a7b3 | 70 | static char toP(void * x) |
WiredHome | 11:17d84c41a7b3 | 71 | { |
WiredHome | 11:17d84c41a7b3 | 72 | char * c = (char *) x; |
WiredHome | 11:17d84c41a7b3 | 73 | if (*c >= ' ' && *c < 0x7F) |
WiredHome | 11:17d84c41a7b3 | 74 | return *c; |
WiredHome | 11:17d84c41a7b3 | 75 | else |
WiredHome | 11:17d84c41a7b3 | 76 | return '.'; |
WiredHome | 11:17d84c41a7b3 | 77 | } |
WiredHome | 8:262583f054f6 | 78 | #define mymalloc(x) MyMalloc(x, __LINE__) |
WiredHome | 8:262583f054f6 | 79 | #define myfree(x) \ |
WiredHome | 25:f7d6df7a700a | 80 | pc->printf("[INF HTTP%4d] free(%02x %02x %02x %02x %02x ... %c%c%c%c%c)\r\n", __LINE__, \ |
WiredHome | 11:17d84c41a7b3 | 81 | *x, *(x+1), *(x+2), *(x+3), *(x+4), \ |
WiredHome | 11:17d84c41a7b3 | 82 | toP(x), toP(x+1), toP(x+2), toP(x+3), toP(x+4) ); \ |
WiredHome | 8:262583f054f6 | 83 | free(x); |
WiredHome | 8:262583f054f6 | 84 | #else |
WiredHome | 8:262583f054f6 | 85 | #define mymalloc(x) malloc(x) |
WiredHome | 8:262583f054f6 | 86 | #define myfree(x) free(x) |
WiredHome | 8:262583f054f6 | 87 | #endif |
WiredHome | 8:262583f054f6 | 88 | |
WiredHome | 3:17928786bdb5 | 89 | HTTPServer::HTTPServer( |
WiredHome | 7:99ad7a67f05e | 90 | Wifly * _wf, |
WiredHome | 7:99ad7a67f05e | 91 | int port, |
WiredHome | 7:99ad7a67f05e | 92 | const char * _webroot, |
WiredHome | 13:8975d7928678 | 93 | int maxheaderParams, |
WiredHome | 13:8975d7928678 | 94 | int _maxqueryParams, |
WiredHome | 7:99ad7a67f05e | 95 | int _maxdynamicpages, |
WiredHome | 7:99ad7a67f05e | 96 | PC * _pc, |
WiredHome | 7:99ad7a67f05e | 97 | int _allocforheader, |
WiredHome | 3:17928786bdb5 | 98 | int _allocforfile) |
WiredHome | 0:729320f63c5c | 99 | { |
WiredHome | 0:729320f63c5c | 100 | wifly = _wf; |
WiredHome | 0:729320f63c5c | 101 | webroot = (char *)malloc(strlen(_webroot)+1); |
WiredHome | 0:729320f63c5c | 102 | strcpy(webroot, _webroot); |
WiredHome | 27:90a1f5a5392f | 103 | if (strlen(webroot)>1 && webroot[strlen(webroot)-1] == '/') // remove trailing '/' |
WiredHome | 27:90a1f5a5392f | 104 | webroot[strlen(webroot)-1] = '\0'; |
WiredHome | 13:8975d7928678 | 105 | maxqueryParams = _maxqueryParams; |
WiredHome | 0:729320f63c5c | 106 | maxdynamicpages = _maxdynamicpages; |
WiredHome | 13:8975d7928678 | 107 | headerParams = (namevalue *)malloc(maxheaderParams * sizeof(namevalue)); |
WiredHome | 13:8975d7928678 | 108 | queryParams = (namevalue *)malloc(maxqueryParams * sizeof(namevalue)); |
WiredHome | 0:729320f63c5c | 109 | handlers = (handler *)malloc(maxdynamicpages * sizeof(handler)); |
WiredHome | 3:17928786bdb5 | 110 | headerbuffersize = _allocforheader; |
WiredHome | 3:17928786bdb5 | 111 | headerbuffer = (char *)malloc(headerbuffersize); |
WiredHome | 0:729320f63c5c | 112 | pc = _pc; |
WiredHome | 3:17928786bdb5 | 113 | queryType = NULL; |
WiredHome | 3:17928786bdb5 | 114 | queryString = NULL; |
WiredHome | 3:17928786bdb5 | 115 | postQueryString = NULL; |
WiredHome | 13:8975d7928678 | 116 | queryParamCount = 0; |
WiredHome | 0:729320f63c5c | 117 | handlercount = 0; |
WiredHome | 3:17928786bdb5 | 118 | maxheaderbytes = 0; |
WiredHome | 0:729320f63c5c | 119 | server = new TCPSocketServer(); |
WiredHome | 0:729320f63c5c | 120 | server->bind(port); |
WiredHome | 0:729320f63c5c | 121 | server->listen(); |
WiredHome | 16:6ebacf2946d8 | 122 | server->set_blocking(false, 10); |
WiredHome | 3:17928786bdb5 | 123 | ResetPerformanceData(); |
WiredHome | 10:9c8d2c6a3469 | 124 | PerformanceTimer.start(); |
WiredHome | 0:729320f63c5c | 125 | } |
WiredHome | 0:729320f63c5c | 126 | |
WiredHome | 0:729320f63c5c | 127 | HTTPServer::~HTTPServer() |
WiredHome | 0:729320f63c5c | 128 | { |
WiredHome | 8:262583f054f6 | 129 | int i; |
WiredHome | 8:262583f054f6 | 130 | |
WiredHome | 8:262583f054f6 | 131 | for (i=0; i<handlercount; i++) |
WiredHome | 8:262583f054f6 | 132 | myfree(handlers[i].path); |
WiredHome | 8:262583f054f6 | 133 | myfree(headerbuffer); |
WiredHome | 8:262583f054f6 | 134 | myfree(handlers); |
WiredHome | 13:8975d7928678 | 135 | myfree(queryParams); |
WiredHome | 8:262583f054f6 | 136 | myfree(webroot); |
WiredHome | 0:729320f63c5c | 137 | webroot = NULL; |
WiredHome | 0:729320f63c5c | 138 | } |
WiredHome | 0:729320f63c5c | 139 | |
WiredHome | 3:17928786bdb5 | 140 | int HTTPServer::GetMaxHeaderSize() |
WiredHome | 3:17928786bdb5 | 141 | { |
WiredHome | 3:17928786bdb5 | 142 | return maxheaderbytes; |
WiredHome | 3:17928786bdb5 | 143 | } |
WiredHome | 3:17928786bdb5 | 144 | |
WiredHome | 0:729320f63c5c | 145 | bool HTTPServer::RegisterHandler(const char * path, Handler callback) |
WiredHome | 0:729320f63c5c | 146 | { |
WiredHome | 0:729320f63c5c | 147 | if (handlercount < maxdynamicpages && path && callback) { |
WiredHome | 8:262583f054f6 | 148 | handlers[handlercount].path = (char *)mymalloc(strlen(path)+1); |
WiredHome | 0:729320f63c5c | 149 | memcpy(handlers[handlercount].path, path, strlen(path)+1); |
WiredHome | 0:729320f63c5c | 150 | handlers[handlercount].callback = callback; |
WiredHome | 0:729320f63c5c | 151 | handlercount++; |
WiredHome | 0:729320f63c5c | 152 | return true; |
WiredHome | 0:729320f63c5c | 153 | } else { |
WiredHome | 0:729320f63c5c | 154 | return false; |
WiredHome | 0:729320f63c5c | 155 | } |
WiredHome | 0:729320f63c5c | 156 | } |
WiredHome | 0:729320f63c5c | 157 | |
WiredHome | 2:a29c32190037 | 158 | // Poll() |
WiredHome | 0:729320f63c5c | 159 | // |
WiredHome | 0:729320f63c5c | 160 | // *OPEN*GET /x=1 HTTP/1.1 |
WiredHome | 0:729320f63c5c | 161 | // Host: 192.168.1.140 |
WiredHome | 0:729320f63c5c | 162 | // Connection: keep-alive |
WiredHome | 0:729320f63c5c | 163 | // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 |
WiredHome | 0:729320f63c5c | 164 | // User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36 |
WiredHome | 0:729320f63c5c | 165 | // Accept-Encoding: gzip,deflate,sdch |
WiredHome | 0:729320f63c5c | 166 | // Accept-Language: en-US,en;q=0.8 |
WiredHome | 0:729320f63c5c | 167 | // |
WiredHome | 2:a29c32190037 | 168 | void HTTPServer::Poll() |
WiredHome | 0:729320f63c5c | 169 | { |
WiredHome | 3:17928786bdb5 | 170 | typedef enum { |
WiredHome | 3:17928786bdb5 | 171 | Idle, // waiting for a connection |
WiredHome | 3:17928786bdb5 | 172 | Receiving, // receiving data |
WiredHome | 3:17928786bdb5 | 173 | Sending, // send the response |
WiredHome | 7:99ad7a67f05e | 174 | WaitingToClose, // small timeout to close |
WiredHome | 7:99ad7a67f05e | 175 | Reset |
WiredHome | 3:17928786bdb5 | 176 | } state; |
WiredHome | 0:729320f63c5c | 177 | static state op = Idle; |
WiredHome | 3:17928786bdb5 | 178 | static char * bPtr = headerbuffer; |
WiredHome | 0:729320f63c5c | 179 | int n; |
WiredHome | 16:6ebacf2946d8 | 180 | static unsigned int t_ref; // reference point for the PerformanceTimer |
WiredHome | 0:729320f63c5c | 181 | |
WiredHome | 20:786aa5749007 | 182 | #if defined(DEBUG) |
WiredHome | 8:262583f054f6 | 183 | static state lastOp = Reset; |
WiredHome | 7:99ad7a67f05e | 184 | if (lastOp != op) { |
WiredHome | 9:2ea342765c9d | 185 | const char *states[] = {"Idle", "Receiving", "Sending", "WaitingToClose", "Reset"}; |
WiredHome | 27:90a1f5a5392f | 186 | INFO("Poll: %s", states[op]); |
WiredHome | 7:99ad7a67f05e | 187 | lastOp = op; |
WiredHome | 7:99ad7a67f05e | 188 | } |
WiredHome | 8:262583f054f6 | 189 | #endif |
WiredHome | 0:729320f63c5c | 190 | switch(op) { |
WiredHome | 3:17928786bdb5 | 191 | default: // not expected to arrive here |
WiredHome | 3:17928786bdb5 | 192 | op = Idle; |
WiredHome | 3:17928786bdb5 | 193 | break; |
WiredHome | 8:262583f054f6 | 194 | |
WiredHome | 3:17928786bdb5 | 195 | case Idle: |
WiredHome | 10:9c8d2c6a3469 | 196 | PerformanceTimer.reset(); |
WiredHome | 17:69ff00ce39f4 | 197 | t_ref = (unsigned int)PerformanceTimer.read_us(); |
WiredHome | 3:17928786bdb5 | 198 | bPtr = headerbuffer; |
WiredHome | 11:17d84c41a7b3 | 199 | if (0 == server->accept(client)) { |
WiredHome | 3:17928786bdb5 | 200 | op = Receiving; |
WiredHome | 17:69ff00ce39f4 | 201 | t_ref = RecordPerformanceData(&perfData.ConnectionAccepted, t_ref); |
WiredHome | 27:90a1f5a5392f | 202 | INFO("Accepted at %u", (unsigned int)PerformanceTimer.read_us()); |
WiredHome | 3:17928786bdb5 | 203 | } |
WiredHome | 0:729320f63c5c | 204 | break; |
WiredHome | 8:262583f054f6 | 205 | |
WiredHome | 3:17928786bdb5 | 206 | case Receiving: |
WiredHome | 3:17928786bdb5 | 207 | n = client.receive(bPtr, headerbuffersize - (bPtr - headerbuffer)); |
WiredHome | 3:17928786bdb5 | 208 | if (n < 0) { |
WiredHome | 27:90a1f5a5392f | 209 | INFO("*** client.receive() => %d", n); |
WiredHome | 3:17928786bdb5 | 210 | } else if (n) { |
WiredHome | 3:17928786bdb5 | 211 | bPtr[n] = '\0'; |
WiredHome | 3:17928786bdb5 | 212 | if (ParseHeader(headerbuffer)) { |
WiredHome | 3:17928786bdb5 | 213 | op = Sending; |
WiredHome | 17:69ff00ce39f4 | 214 | t_ref = RecordPerformanceData(&perfData.HeaderParsed, t_ref); |
WiredHome | 27:90a1f5a5392f | 215 | INFO("Header Parsed at %u", (unsigned int)PerformanceTimer.read_us()); |
WiredHome | 3:17928786bdb5 | 216 | } |
WiredHome | 3:17928786bdb5 | 217 | bPtr += n; |
WiredHome | 0:729320f63c5c | 218 | } |
WiredHome | 0:729320f63c5c | 219 | break; |
WiredHome | 8:262583f054f6 | 220 | |
WiredHome | 0:729320f63c5c | 221 | case Sending: |
WiredHome | 3:17928786bdb5 | 222 | SendResponse(); |
WiredHome | 0:729320f63c5c | 223 | op = WaitingToClose; |
WiredHome | 17:69ff00ce39f4 | 224 | t_ref = RecordPerformanceData(&perfData.ResponseSent, t_ref); |
WiredHome | 27:90a1f5a5392f | 225 | INFO("Response Sent at %u", (unsigned int)PerformanceTimer.read_us()); |
WiredHome | 0:729320f63c5c | 226 | break; |
WiredHome | 9:2ea342765c9d | 227 | |
WiredHome | 0:729320f63c5c | 228 | case WaitingToClose: |
WiredHome | 27:90a1f5a5392f | 229 | INFO("Connection closed entry %u", (unsigned int)PerformanceTimer.read_us()); |
WiredHome | 3:17928786bdb5 | 230 | close_connection(); |
WiredHome | 0:729320f63c5c | 231 | op = Idle; |
WiredHome | 17:69ff00ce39f4 | 232 | RecordPerformanceData(&perfData.ConnectionClosed, t_ref); |
WiredHome | 27:90a1f5a5392f | 233 | INFO("Connection closed exit %u", (unsigned int)PerformanceTimer.read_us()); |
WiredHome | 0:729320f63c5c | 234 | break; |
WiredHome | 0:729320f63c5c | 235 | } |
WiredHome | 0:729320f63c5c | 236 | } |
WiredHome | 0:729320f63c5c | 237 | |
WiredHome | 0:729320f63c5c | 238 | |
WiredHome | 0:729320f63c5c | 239 | const char * HTTPServer::GetSupportedType(const char * filename) |
WiredHome | 0:729320f63c5c | 240 | { |
WiredHome | 0:729320f63c5c | 241 | int i; |
WiredHome | 0:729320f63c5c | 242 | int buflen = strlen(filename); |
WiredHome | 0:729320f63c5c | 243 | int extlen; |
WiredHome | 0:729320f63c5c | 244 | |
WiredHome | 0:729320f63c5c | 245 | for (i=0; extensions[i].ext != 0; i++) { |
WiredHome | 0:729320f63c5c | 246 | extlen = strlen(extensions[i].ext); |
WiredHome | 0:729320f63c5c | 247 | if ( !strncmp(&filename[buflen-extlen], extensions[i].ext, extlen)) { |
WiredHome | 0:729320f63c5c | 248 | return extensions[i].filetype; |
WiredHome | 0:729320f63c5c | 249 | } |
WiredHome | 0:729320f63c5c | 250 | } |
WiredHome | 0:729320f63c5c | 251 | return NULL; |
WiredHome | 0:729320f63c5c | 252 | } |
WiredHome | 0:729320f63c5c | 253 | |
WiredHome | 3:17928786bdb5 | 254 | |
WiredHome | 0:729320f63c5c | 255 | void HTTPServer::send(const char * msg, int bytes) |
WiredHome | 0:729320f63c5c | 256 | { |
WiredHome | 0:729320f63c5c | 257 | if (bytes == -1) |
WiredHome | 0:729320f63c5c | 258 | bytes = strlen(msg); |
WiredHome | 20:786aa5749007 | 259 | client.send((char *)msg, bytes); |
WiredHome | 0:729320f63c5c | 260 | } |
WiredHome | 0:729320f63c5c | 261 | |
WiredHome | 3:17928786bdb5 | 262 | |
WiredHome | 0:729320f63c5c | 263 | bool HTTPServer::SendFile(const char * filename, const char * filetype) |
WiredHome | 0:729320f63c5c | 264 | { |
WiredHome | 0:729320f63c5c | 265 | FILE * fp; |
WiredHome | 3:17928786bdb5 | 266 | |
WiredHome | 0:729320f63c5c | 267 | fp = fopen(filename,"rb"); |
WiredHome | 0:729320f63c5c | 268 | if (fp) { // can open it |
WiredHome | 8:262583f054f6 | 269 | char *fbuffer = (char *)mymalloc(FILESEND_BUF_SIZE); |
WiredHome | 0:729320f63c5c | 270 | int bytes; |
WiredHome | 0:729320f63c5c | 271 | |
WiredHome | 3:17928786bdb5 | 272 | if (fbuffer) { |
WiredHome | 3:17928786bdb5 | 273 | header(200, "OK", filetype); |
WiredHome | 0:729320f63c5c | 274 | bytes = fread(fbuffer,sizeof(char),FILESEND_BUF_SIZE,fp); |
WiredHome | 3:17928786bdb5 | 275 | while (bytes > 0) { |
WiredHome | 3:17928786bdb5 | 276 | send(fbuffer, bytes); |
WiredHome | 3:17928786bdb5 | 277 | bytes = fread(fbuffer,sizeof(char),FILESEND_BUF_SIZE,fp); |
WiredHome | 3:17928786bdb5 | 278 | } |
WiredHome | 8:262583f054f6 | 279 | myfree(fbuffer); |
WiredHome | 3:17928786bdb5 | 280 | } else { |
WiredHome | 3:17928786bdb5 | 281 | header(500, "Server Error", "Pragma: err - insufficient memory\r\n"); |
WiredHome | 0:729320f63c5c | 282 | } |
WiredHome | 0:729320f63c5c | 283 | fclose(fp); |
WiredHome | 0:729320f63c5c | 284 | return true; |
WiredHome | 0:729320f63c5c | 285 | } else { |
WiredHome | 3:17928786bdb5 | 286 | header(404, "Not Found", "Pragma: err - Can't open file\r\n"); |
WiredHome | 0:729320f63c5c | 287 | return false; |
WiredHome | 0:729320f63c5c | 288 | } |
WiredHome | 0:729320f63c5c | 289 | } |
WiredHome | 0:729320f63c5c | 290 | |
WiredHome | 0:729320f63c5c | 291 | int HTTPServer::HexCharToInt(char c) |
WiredHome | 0:729320f63c5c | 292 | { |
WiredHome | 0:729320f63c5c | 293 | if (c >= 'a' && c <= 'f') |
WiredHome | 0:729320f63c5c | 294 | return (c - 'a' + 10); |
WiredHome | 0:729320f63c5c | 295 | else if (c >= 'A' && c <= 'F') |
WiredHome | 0:729320f63c5c | 296 | return (c - 'A' + 10); |
WiredHome | 0:729320f63c5c | 297 | else if (c >= '0' && c <= '9') |
WiredHome | 0:729320f63c5c | 298 | return c - '0'; |
WiredHome | 0:729320f63c5c | 299 | else |
WiredHome | 0:729320f63c5c | 300 | return 0; |
WiredHome | 0:729320f63c5c | 301 | } |
WiredHome | 0:729320f63c5c | 302 | |
WiredHome | 0:729320f63c5c | 303 | char HTTPServer::HexPairToChar(char * p) |
WiredHome | 0:729320f63c5c | 304 | { |
WiredHome | 0:729320f63c5c | 305 | return 16 * HexCharToInt(*p) + HexCharToInt(*(p+1)); |
WiredHome | 0:729320f63c5c | 306 | } |
WiredHome | 0:729320f63c5c | 307 | |
WiredHome | 0:729320f63c5c | 308 | void HTTPServer::UnescapeString(char * encoded) |
WiredHome | 0:729320f63c5c | 309 | { |
WiredHome | 0:729320f63c5c | 310 | char *p; |
WiredHome | 0:729320f63c5c | 311 | |
WiredHome | 0:729320f63c5c | 312 | // first convert '+' to ' ' |
WiredHome | 0:729320f63c5c | 313 | p = strchr(encoded, '+'); |
WiredHome | 0:729320f63c5c | 314 | while (p) { |
WiredHome | 0:729320f63c5c | 315 | *p = ' '; |
WiredHome | 0:729320f63c5c | 316 | p = strchr(encoded, '+'); |
WiredHome | 0:729320f63c5c | 317 | } |
WiredHome | 0:729320f63c5c | 318 | // then convert hex '%xx' to char 'x' |
WiredHome | 0:729320f63c5c | 319 | p = strchr(encoded, '%'); |
WiredHome | 0:729320f63c5c | 320 | while (p) { |
WiredHome | 0:729320f63c5c | 321 | if (strchr("0123456789ABCDEFabcdef", *(p+1)) |
WiredHome | 0:729320f63c5c | 322 | && strchr("0123456789ABCDEFabcdef", *(p+2)) ) { |
WiredHome | 0:729320f63c5c | 323 | *p = HexPairToChar(p+1); |
WiredHome | 0:729320f63c5c | 324 | p++; // advance past the % |
WiredHome | 0:729320f63c5c | 325 | char * a = p; |
WiredHome | 0:729320f63c5c | 326 | char * b = p + 2; |
WiredHome | 0:729320f63c5c | 327 | do { |
WiredHome | 0:729320f63c5c | 328 | *a++ = *b++; |
WiredHome | 0:729320f63c5c | 329 | } while (*b); |
WiredHome | 0:729320f63c5c | 330 | *a = '\0'; |
WiredHome | 0:729320f63c5c | 331 | } |
WiredHome | 0:729320f63c5c | 332 | p = strchr(p, '%'); |
WiredHome | 0:729320f63c5c | 333 | } |
WiredHome | 0:729320f63c5c | 334 | } |
WiredHome | 0:729320f63c5c | 335 | |
WiredHome | 0:729320f63c5c | 336 | const char * HTTPServer::GetParameter(const char * name) |
WiredHome | 0:729320f63c5c | 337 | { |
WiredHome | 13:8975d7928678 | 338 | for (int i=0; i<queryParamCount; i++) { |
WiredHome | 13:8975d7928678 | 339 | if (strcmp(queryParams[i].name, name) == 0) { |
WiredHome | 13:8975d7928678 | 340 | return queryParams[i].value; |
WiredHome | 0:729320f63c5c | 341 | } |
WiredHome | 0:729320f63c5c | 342 | } |
WiredHome | 0:729320f63c5c | 343 | return NULL; |
WiredHome | 0:729320f63c5c | 344 | } |
WiredHome | 0:729320f63c5c | 345 | |
WiredHome | 0:729320f63c5c | 346 | // this=that&who=what&more=stuff... |
WiredHome | 0:729320f63c5c | 347 | // ^ ^ ^ |
WiredHome | 3:17928786bdb5 | 348 | void HTTPServer::ParseParameters(char * pName) |
WiredHome | 0:729320f63c5c | 349 | { |
WiredHome | 0:729320f63c5c | 350 | char * pVal; |
WiredHome | 0:729320f63c5c | 351 | char * pNextName; |
WiredHome | 0:729320f63c5c | 352 | |
WiredHome | 13:8975d7928678 | 353 | // Parse queryParams |
WiredHome | 0:729320f63c5c | 354 | pVal = strchr(pName, '#'); // If there is a '#fragment_id', we can ignore it |
WiredHome | 0:729320f63c5c | 355 | if (pVal) |
WiredHome | 3:17928786bdb5 | 356 | *pVal = '\0'; |
WiredHome | 0:729320f63c5c | 357 | do { |
WiredHome | 13:8975d7928678 | 358 | queryParams[queryParamCount].name = pName; |
WiredHome | 0:729320f63c5c | 359 | pVal = strchr(pName, '='); |
WiredHome | 0:729320f63c5c | 360 | pNextName = strchr(pName,'&'); |
WiredHome | 0:729320f63c5c | 361 | if (pVal) { |
WiredHome | 0:729320f63c5c | 362 | if (pNextName == NULL || (pNextName && pNextName > pVal)) { |
WiredHome | 0:729320f63c5c | 363 | *pVal++ = '\0'; |
WiredHome | 13:8975d7928678 | 364 | queryParams[queryParamCount].value = pVal; |
WiredHome | 0:729320f63c5c | 365 | pName = pVal; |
WiredHome | 0:729320f63c5c | 366 | } |
WiredHome | 0:729320f63c5c | 367 | } |
WiredHome | 13:8975d7928678 | 368 | queryParamCount++; |
WiredHome | 0:729320f63c5c | 369 | if (pNextName) { |
WiredHome | 0:729320f63c5c | 370 | pName = pNextName; |
WiredHome | 0:729320f63c5c | 371 | *pName++ = '\0'; |
WiredHome | 0:729320f63c5c | 372 | } else { |
WiredHome | 0:729320f63c5c | 373 | pName = NULL; |
WiredHome | 0:729320f63c5c | 374 | } |
WiredHome | 13:8975d7928678 | 375 | } while (pName && queryParamCount < maxqueryParams); |
WiredHome | 0:729320f63c5c | 376 | } |
WiredHome | 0:729320f63c5c | 377 | |
WiredHome | 0:729320f63c5c | 378 | |
WiredHome | 0:729320f63c5c | 379 | void HTTPServer::header(int code, const char * code_text, const char * content_type, const char * optional_text) |
WiredHome | 0:729320f63c5c | 380 | { |
WiredHome | 0:729320f63c5c | 381 | char http[100]; |
WiredHome | 0:729320f63c5c | 382 | |
WiredHome | 0:729320f63c5c | 383 | sprintf(http, "%s %i %s\r\n", hdr_httpver, code, code_text); |
WiredHome | 0:729320f63c5c | 384 | send(http); |
WiredHome | 0:729320f63c5c | 385 | send(hdr_age); |
WiredHome | 0:729320f63c5c | 386 | send(hdr_server); |
WiredHome | 0:729320f63c5c | 387 | if (content_type) { |
WiredHome | 0:729320f63c5c | 388 | send(content_type); |
WiredHome | 0:729320f63c5c | 389 | } |
WiredHome | 0:729320f63c5c | 390 | if (optional_text) { |
WiredHome | 0:729320f63c5c | 391 | send(optional_text); |
WiredHome | 0:729320f63c5c | 392 | } |
WiredHome | 0:729320f63c5c | 393 | send(hdr_close); |
WiredHome | 0:729320f63c5c | 394 | send(nl); |
WiredHome | 0:729320f63c5c | 395 | } |
WiredHome | 0:729320f63c5c | 396 | |
WiredHome | 14:19c5f6151319 | 397 | |
WiredHome | 7:99ad7a67f05e | 398 | bool HTTPServer::close_connection() |
WiredHome | 0:729320f63c5c | 399 | { |
WiredHome | 7:99ad7a67f05e | 400 | bool res; |
WiredHome | 7:99ad7a67f05e | 401 | |
WiredHome | 14:19c5f6151319 | 402 | res = server->close(); |
WiredHome | 27:90a1f5a5392f | 403 | INFO("close connection returned %d", res); |
WiredHome | 7:99ad7a67f05e | 404 | return res; |
WiredHome | 0:729320f63c5c | 405 | } |
WiredHome | 0:729320f63c5c | 406 | |
WiredHome | 14:19c5f6151319 | 407 | |
WiredHome | 0:729320f63c5c | 408 | bool HTTPServer::Extract(char * haystack, char * needle, char ** string) |
WiredHome | 0:729320f63c5c | 409 | { |
WiredHome | 0:729320f63c5c | 410 | bool ret = false; // assume failure until proven otherwise |
WiredHome | 0:729320f63c5c | 411 | char * qs = NULL; |
WiredHome | 0:729320f63c5c | 412 | char * eqs = NULL; |
WiredHome | 0:729320f63c5c | 413 | char * container = NULL; |
WiredHome | 0:729320f63c5c | 414 | char * get = strstr(haystack, needle); // what if not at the front? |
WiredHome | 0:729320f63c5c | 415 | if (get) { |
WiredHome | 0:729320f63c5c | 416 | // Seems to be a valid "...GET /QueryString HTTP/1.1" |
WiredHome | 8:262583f054f6 | 417 | // or "...<needle>param..." |
WiredHome | 0:729320f63c5c | 418 | qs = get + strlen(needle); // in case the needle didn't have space delimiters |
WiredHome | 0:729320f63c5c | 419 | while (*qs == ' ') |
WiredHome | 0:729320f63c5c | 420 | qs++; |
WiredHome | 0:729320f63c5c | 421 | // /QueryString\0HTTP/1.1\0\0 |
WiredHome | 0:729320f63c5c | 422 | if (*string) // recycle old string when working a new one |
WiredHome | 8:262583f054f6 | 423 | myfree(*string); |
WiredHome | 8:262583f054f6 | 424 | container = (char *)mymalloc(strlen(qs)); |
WiredHome | 0:729320f63c5c | 425 | if (container) { |
WiredHome | 0:729320f63c5c | 426 | strcpy(container, qs); |
WiredHome | 0:729320f63c5c | 427 | eqs = strchr(container, ' '); |
WiredHome | 0:729320f63c5c | 428 | if (eqs) |
WiredHome | 0:729320f63c5c | 429 | *eqs = '\0'; |
WiredHome | 0:729320f63c5c | 430 | *string = container; |
WiredHome | 27:90a1f5a5392f | 431 | INFO("Extract(%s) = %s", needle, container); |
WiredHome | 0:729320f63c5c | 432 | ret = true; |
WiredHome | 0:729320f63c5c | 433 | } else { |
WiredHome | 0:729320f63c5c | 434 | *string = NULL; // something bad happened... no memory |
WiredHome | 0:729320f63c5c | 435 | } |
WiredHome | 0:729320f63c5c | 436 | } |
WiredHome | 0:729320f63c5c | 437 | return ret; |
WiredHome | 0:729320f63c5c | 438 | } |
WiredHome | 0:729320f63c5c | 439 | |
WiredHome | 14:19c5f6151319 | 440 | |
WiredHome | 0:729320f63c5c | 441 | char * HTTPServer::rewriteWithDefaultFile(char * queryString) |
WiredHome | 0:729320f63c5c | 442 | { |
WiredHome | 8:262583f054f6 | 443 | char * temp = (char *)mymalloc(strlen(queryString) + strlen(DEFAULT_FILENAME) + 1); |
WiredHome | 0:729320f63c5c | 444 | |
WiredHome | 0:729320f63c5c | 445 | if (temp) { |
WiredHome | 0:729320f63c5c | 446 | *temp = '\0'; |
WiredHome | 0:729320f63c5c | 447 | strcpy(temp, queryString); |
WiredHome | 0:729320f63c5c | 448 | strcat(temp, DEFAULT_FILENAME); |
WiredHome | 8:262583f054f6 | 449 | myfree(queryString); |
WiredHome | 0:729320f63c5c | 450 | return temp; |
WiredHome | 0:729320f63c5c | 451 | } else { |
WiredHome | 0:729320f63c5c | 452 | return queryString; |
WiredHome | 0:729320f63c5c | 453 | } |
WiredHome | 0:729320f63c5c | 454 | } |
WiredHome | 0:729320f63c5c | 455 | |
WiredHome | 14:19c5f6151319 | 456 | |
WiredHome | 0:729320f63c5c | 457 | char * HTTPServer::rewritePrependWebroot(char * queryString) |
WiredHome | 0:729320f63c5c | 458 | { |
WiredHome | 24:062431453abb | 459 | char * temp = (char *)mymalloc(strlen(webroot) + strlen(queryString) + 2); // save room for '/' |
WiredHome | 0:729320f63c5c | 460 | |
WiredHome | 0:729320f63c5c | 461 | if (temp) { |
WiredHome | 24:062431453abb | 462 | char *lastC; |
WiredHome | 0:729320f63c5c | 463 | *temp = '\0'; |
WiredHome | 0:729320f63c5c | 464 | strcpy(temp, webroot); |
WiredHome | 24:062431453abb | 465 | lastC = &temp[strlen(temp)-1]; |
WiredHome | 24:062431453abb | 466 | if (*lastC == '/' && *queryString == '/') |
WiredHome | 24:062431453abb | 467 | queryString++; // don't create two '/' |
WiredHome | 24:062431453abb | 468 | else if (*lastC != '/' && *queryString != '/') |
WiredHome | 24:062431453abb | 469 | strcat(temp, "/"); |
WiredHome | 0:729320f63c5c | 470 | strcat(temp, queryString); |
WiredHome | 8:262583f054f6 | 471 | myfree(queryString); |
WiredHome | 0:729320f63c5c | 472 | return temp; |
WiredHome | 0:729320f63c5c | 473 | } else { |
WiredHome | 0:729320f63c5c | 474 | return queryString; |
WiredHome | 0:729320f63c5c | 475 | } |
WiredHome | 0:729320f63c5c | 476 | } |
WiredHome | 0:729320f63c5c | 477 | |
WiredHome | 14:19c5f6151319 | 478 | |
WiredHome | 3:17928786bdb5 | 479 | bool HTTPServer::CheckDynamicHandlers() |
WiredHome | 3:17928786bdb5 | 480 | { |
WiredHome | 3:17928786bdb5 | 481 | bool regHandled = false; |
WiredHome | 0:729320f63c5c | 482 | |
WiredHome | 3:17928786bdb5 | 483 | // If this queryString is in the list of registered handlers, call that |
WiredHome | 3:17928786bdb5 | 484 | for (int i=0; i<handlercount; i++) { |
WiredHome | 3:17928786bdb5 | 485 | if (strcmp(handlers[i].path, queryString) == 0) { |
WiredHome | 13:8975d7928678 | 486 | (*handlers[i].callback)(this, SEND_PAGE, queryString, queryParams, queryParamCount); |
WiredHome | 3:17928786bdb5 | 487 | regHandled = true; |
WiredHome | 3:17928786bdb5 | 488 | break; // we only execute the first one |
WiredHome | 3:17928786bdb5 | 489 | } |
WiredHome | 3:17928786bdb5 | 490 | } |
WiredHome | 3:17928786bdb5 | 491 | return regHandled; |
WiredHome | 3:17928786bdb5 | 492 | } |
WiredHome | 3:17928786bdb5 | 493 | |
WiredHome | 14:19c5f6151319 | 494 | |
WiredHome | 3:17928786bdb5 | 495 | void HTTPServer::SendResponse() |
WiredHome | 3:17928786bdb5 | 496 | { |
WiredHome | 27:90a1f5a5392f | 497 | INFO("SendResponse(%s) at %u", queryType, (unsigned int)PerformanceTimer.read_us()); |
WiredHome | 3:17928786bdb5 | 498 | if (strcmp(queryType, "GET") == 0 || strcmp(queryType, "POST") == 0) { |
WiredHome | 3:17928786bdb5 | 499 | if (!(queryString[0] == '.' && queryString[1] == '.')) { |
WiredHome | 3:17928786bdb5 | 500 | const char * fType; |
WiredHome | 3:17928786bdb5 | 501 | |
WiredHome | 3:17928786bdb5 | 502 | if (!CheckDynamicHandlers()) { |
WiredHome | 3:17928786bdb5 | 503 | // Otherwise, this queryString must be trying to reference a static file |
WiredHome | 3:17928786bdb5 | 504 | if (queryString[strlen(queryString)-1] == '/') { |
WiredHome | 3:17928786bdb5 | 505 | queryString = rewriteWithDefaultFile(queryString); |
WiredHome | 3:17928786bdb5 | 506 | } |
WiredHome | 3:17928786bdb5 | 507 | // see if we support this file type |
WiredHome | 3:17928786bdb5 | 508 | fType = GetSupportedType(queryString); |
WiredHome | 3:17928786bdb5 | 509 | if (fType) { |
WiredHome | 3:17928786bdb5 | 510 | queryString = rewritePrependWebroot(queryString); |
WiredHome | 3:17928786bdb5 | 511 | SendFile(queryString, fType); |
WiredHome | 3:17928786bdb5 | 512 | } else { |
WiredHome | 3:17928786bdb5 | 513 | header(404, "Not Found", "Pragma: err - Unsupported type\r\n"); |
WiredHome | 3:17928786bdb5 | 514 | } |
WiredHome | 3:17928786bdb5 | 515 | } |
WiredHome | 3:17928786bdb5 | 516 | } else { |
WiredHome | 3:17928786bdb5 | 517 | header(400, "Bad Request", "Pragma: err - Unsupported path\r\n"); |
WiredHome | 3:17928786bdb5 | 518 | } |
WiredHome | 3:17928786bdb5 | 519 | } else { |
WiredHome | 3:17928786bdb5 | 520 | header(400, "Bad Request", "Pragma: err - Unsupported query type\r\n"); |
WiredHome | 3:17928786bdb5 | 521 | } |
WiredHome | 27:90a1f5a5392f | 522 | INFO(" SendResponse complete at %u", (unsigned int)PerformanceTimer.read_us()); |
WiredHome | 17:69ff00ce39f4 | 523 | |
WiredHome | 3:17928786bdb5 | 524 | if (queryType) { |
WiredHome | 8:262583f054f6 | 525 | myfree(queryType); |
WiredHome | 3:17928786bdb5 | 526 | queryType = NULL; |
WiredHome | 3:17928786bdb5 | 527 | } |
WiredHome | 3:17928786bdb5 | 528 | if (queryString) { |
WiredHome | 8:262583f054f6 | 529 | myfree(queryString); |
WiredHome | 3:17928786bdb5 | 530 | queryString = NULL; |
WiredHome | 3:17928786bdb5 | 531 | } |
WiredHome | 3:17928786bdb5 | 532 | if (postQueryString) { |
WiredHome | 8:262583f054f6 | 533 | myfree(postQueryString); |
WiredHome | 3:17928786bdb5 | 534 | postQueryString = NULL; |
WiredHome | 3:17928786bdb5 | 535 | } |
WiredHome | 27:90a1f5a5392f | 536 | INFO(" SendResponse free at %u", (unsigned int)PerformanceTimer.read_us()); |
WiredHome | 3:17928786bdb5 | 537 | } |
WiredHome | 3:17928786bdb5 | 538 | |
WiredHome | 14:19c5f6151319 | 539 | |
WiredHome | 3:17928786bdb5 | 540 | bool HTTPServer::ParseHeader(char * buffer) |
WiredHome | 3:17928786bdb5 | 541 | { |
WiredHome | 3:17928786bdb5 | 542 | char * dblCR; |
WiredHome | 3:17928786bdb5 | 543 | bool advanceState = false; |
WiredHome | 3:17928786bdb5 | 544 | int bytecount; |
WiredHome | 7:99ad7a67f05e | 545 | |
WiredHome | 3:17928786bdb5 | 546 | // Buffer could have partial, but the double \r\n is the key |
WiredHome | 13:8975d7928678 | 547 | // GET /QueryString?this=that&sky=blue HTTP/1.1\r\n |
WiredHome | 8:262583f054f6 | 548 | // GET /QueryString HTTP/1.1\r\nHost: 192.168.1.140\r\nCache-Con |
WiredHome | 8:262583f054f6 | 549 | // GET /QueryString HTTP/1.1\r\nHost: 192.168.1.140\r\nCache-Control: max-age=0\r\n\r\n |
WiredHome | 3:17928786bdb5 | 550 | dblCR = strstr(buffer,"\r\n\r\n"); |
WiredHome | 3:17928786bdb5 | 551 | if (dblCR) { // Have to scan from the beginning in case split on \r |
WiredHome | 27:90a1f5a5392f | 552 | INFO("==\r\n%s==\r\n", buffer); |
WiredHome | 3:17928786bdb5 | 553 | char * soRec = buffer; // start of the next record of text |
WiredHome | 13:8975d7928678 | 554 | char * eoRec = strchr(soRec, '\n'); // search for end of the current record |
WiredHome | 7:99ad7a67f05e | 555 | |
WiredHome | 13:8975d7928678 | 556 | headerParamCount = 0; |
WiredHome | 3:17928786bdb5 | 557 | bytecount = strlen(buffer); |
WiredHome | 3:17928786bdb5 | 558 | if (bytecount > maxheaderbytes) |
WiredHome | 3:17928786bdb5 | 559 | maxheaderbytes = bytecount; |
WiredHome | 3:17928786bdb5 | 560 | while (eoRec) { |
WiredHome | 3:17928786bdb5 | 561 | *eoRec = '\0'; |
WiredHome | 3:17928786bdb5 | 562 | if (*(eoRec-1) == '\r') |
WiredHome | 3:17928786bdb5 | 563 | *(eoRec-1) = '\0'; |
WiredHome | 8:262583f054f6 | 564 | // Inspect the supported query types (GET, POST) and ignore (HEAD, PUT, OPTION, DELETE, TRACE, CONNECT] |
WiredHome | 8:262583f054f6 | 565 | // This is very clumsy |
WiredHome | 8:262583f054f6 | 566 | if (strstr(soRec, "GET ") == soRec) { |
WiredHome | 8:262583f054f6 | 567 | Extract(soRec, "GET", &queryString); |
WiredHome | 8:262583f054f6 | 568 | if (queryString) { |
WiredHome | 8:262583f054f6 | 569 | queryType = (char *)mymalloc(strlen("GET")+1); |
WiredHome | 8:262583f054f6 | 570 | strcpy(queryType, "GET"); |
WiredHome | 8:262583f054f6 | 571 | } |
WiredHome | 8:262583f054f6 | 572 | } else if (strstr(soRec, "POST ") == soRec) { |
WiredHome | 8:262583f054f6 | 573 | Extract(soRec, "POST", &queryString); |
WiredHome | 8:262583f054f6 | 574 | if (queryString) { |
WiredHome | 8:262583f054f6 | 575 | queryType = (char *)mymalloc(strlen("POST")+1); |
WiredHome | 8:262583f054f6 | 576 | strcpy(queryType, "POST"); |
WiredHome | 8:262583f054f6 | 577 | } |
WiredHome | 10:9c8d2c6a3469 | 578 | } |
WiredHome | 13:8975d7928678 | 579 | |
WiredHome | 13:8975d7928678 | 580 | // if there is a ": " delimiter, we have a header item to parse into name,value pair |
WiredHome | 13:8975d7928678 | 581 | // "Connection: keep-alive" becomes "Connection" "keep-alive" |
WiredHome | 13:8975d7928678 | 582 | char *delim = strstr(soRec, ": "); |
WiredHome | 13:8975d7928678 | 583 | char *chkSpace = strchr(soRec, ' '); // a field-name has no space ahead of the ":" |
WiredHome | 13:8975d7928678 | 584 | if (delim |
WiredHome | 13:8975d7928678 | 585 | && (!chkSpace || (chkSpace && delim < chkSpace)) |
WiredHome | 13:8975d7928678 | 586 | && headerParamCount < maxheaderParams) { |
WiredHome | 14:19c5f6151319 | 587 | *delim++ = '\0'; // replace ": " with null |
WiredHome | 13:8975d7928678 | 588 | *delim++ = '\0'; |
WiredHome | 13:8975d7928678 | 589 | headerParams[headerParamCount].name = soRec; |
WiredHome | 13:8975d7928678 | 590 | headerParams[headerParamCount].value = delim; |
WiredHome | 27:90a1f5a5392f | 591 | INFO("%d: headerParams[%s] = {%s}", headerParamCount, |
WiredHome | 13:8975d7928678 | 592 | headerParams[headerParamCount].name, headerParams[headerParamCount].value); |
WiredHome | 13:8975d7928678 | 593 | headerParamCount++; |
WiredHome | 13:8975d7928678 | 594 | } |
WiredHome | 3:17928786bdb5 | 595 | soRec = eoRec + 1; |
WiredHome | 3:17928786bdb5 | 596 | eoRec = strchr(soRec, '\n'); |
WiredHome | 3:17928786bdb5 | 597 | } |
WiredHome | 3:17928786bdb5 | 598 | if (queryString) { |
WiredHome | 3:17928786bdb5 | 599 | // We have enough to try to reply |
WiredHome | 27:90a1f5a5392f | 600 | INFO("create reply queryType{%s}, queryString{%s}", "GET", queryString); |
WiredHome | 13:8975d7928678 | 601 | // parse queryParams - if any |
WiredHome | 3:17928786bdb5 | 602 | // /file.htm?name1=value1&name2=value2... |
WiredHome | 3:17928786bdb5 | 603 | // /file.htm?name1&name2=value2... |
WiredHome | 13:8975d7928678 | 604 | queryParamCount = 0; |
WiredHome | 3:17928786bdb5 | 605 | char * paramDelim = strchr(queryString, '?'); |
WiredHome | 3:17928786bdb5 | 606 | if (paramDelim) { |
WiredHome | 3:17928786bdb5 | 607 | *paramDelim++ = '\0'; |
WiredHome | 3:17928786bdb5 | 608 | UnescapeString(paramDelim); // everything after the '?' |
WiredHome | 13:8975d7928678 | 609 | ParseParameters(paramDelim); // pointing at the NULL, but there are queryParams beyond |
WiredHome | 3:17928786bdb5 | 610 | } |
WiredHome | 3:17928786bdb5 | 611 | } else { |
WiredHome | 27:90a1f5a5392f | 612 | ERR("queryString not found in (%s)", soRec); |
WiredHome | 3:17928786bdb5 | 613 | } |
WiredHome | 3:17928786bdb5 | 614 | advanceState = true; |
WiredHome | 3:17928786bdb5 | 615 | buffer[0] = 0; |
WiredHome | 3:17928786bdb5 | 616 | |
WiredHome | 3:17928786bdb5 | 617 | // This part parses the extra data on a POST method. |
WiredHome | 3:17928786bdb5 | 618 | // Since there has to be a dynamic handler registered for this |
WiredHome | 3:17928786bdb5 | 619 | // it would make sense to move some of this responsibility to |
WiredHome | 3:17928786bdb5 | 620 | // that handler. It could then choose if it wanted to allocate |
WiredHome | 3:17928786bdb5 | 621 | // the requested 'Content-Length' amount of memory. |
WiredHome | 3:17928786bdb5 | 622 | // Should we check the 'Content-Type' to see if it is |
WiredHome | 3:17928786bdb5 | 623 | // 'application/x-www-form-urlencoded'? |
WiredHome | 13:8975d7928678 | 624 | int postBytes = atoi(GetHeaderValue("Content-Length")); |
WiredHome | 28:f93ef41b78e1 | 625 | CallBackResults acceptIt = ACCEPT_ERROR; |
WiredHome | 3:17928786bdb5 | 626 | if (strcmp(queryType, "POST") == 0 && postBytes > 0 ) { |
WiredHome | 3:17928786bdb5 | 627 | if (postBytes) { |
WiredHome | 27:90a1f5a5392f | 628 | int ndxHandler = 0; |
WiredHome | 3:17928786bdb5 | 629 | bool regHandled = false; |
WiredHome | 3:17928786bdb5 | 630 | // Registered Dynamic Handler |
WiredHome | 3:17928786bdb5 | 631 | // Callback and ask if they want to accept this data |
WiredHome | 27:90a1f5a5392f | 632 | for (ndxHandler=0; ndxHandler<handlercount; ndxHandler++) { |
WiredHome | 27:90a1f5a5392f | 633 | if (strcmp(handlers[ndxHandler].path, queryString) == 0) { |
WiredHome | 27:90a1f5a5392f | 634 | acceptIt = (*handlers[ndxHandler].callback)(this, CONTENT_LENGTH_REQUEST, queryString, queryParams, queryParamCount); |
WiredHome | 3:17928786bdb5 | 635 | regHandled = true; |
WiredHome | 3:17928786bdb5 | 636 | break; // we only execute the first one |
WiredHome | 3:17928786bdb5 | 637 | } |
WiredHome | 3:17928786bdb5 | 638 | } |
WiredHome | 3:17928786bdb5 | 639 | |
WiredHome | 28:f93ef41b78e1 | 640 | if (regHandled && acceptIt != ACCEPT_ERROR) { |
WiredHome | 27:90a1f5a5392f | 641 | // @todo need to refactor - if the thing is bigger than the buffer, |
WiredHome | 27:90a1f5a5392f | 642 | // then we can receive it a chunk at a time, and hand off |
WiredHome | 27:90a1f5a5392f | 643 | // the chunks to the callback. May need callbacks that |
WiredHome | 27:90a1f5a5392f | 644 | // are: START: extract the filename/object name, |
WiredHome | 27:90a1f5a5392f | 645 | // NEXT: a chunk of data, |
WiredHome | 27:90a1f5a5392f | 646 | // END: signals that all chunks were delivered. |
WiredHome | 27:90a1f5a5392f | 647 | // |
WiredHome | 3:17928786bdb5 | 648 | // If so, we'll make space for it |
WiredHome | 8:262583f054f6 | 649 | postQueryString = (char *)mymalloc(postBytes + 1); |
WiredHome | 28:f93ef41b78e1 | 650 | INFO("Free space %d", Free()); |
WiredHome | 3:17928786bdb5 | 651 | if (postQueryString) { |
WiredHome | 3:17928786bdb5 | 652 | char * offset; |
WiredHome | 3:17928786bdb5 | 653 | int len; |
WiredHome | 3:17928786bdb5 | 654 | |
WiredHome | 28:f93ef41b78e1 | 655 | INFO("Processing"); |
WiredHome | 3:17928786bdb5 | 656 | dblCR += 4; // If we slurped up any of the POST, |
WiredHome | 3:17928786bdb5 | 657 | while (*dblCR && *dblCR <= ' ') |
WiredHome | 3:17928786bdb5 | 658 | dblCR++; |
WiredHome | 3:17928786bdb5 | 659 | strcpy(postQueryString, dblCR); // copy that in and then get the rest |
WiredHome | 3:17928786bdb5 | 660 | while ((len = strlen(postQueryString)) < postBytes) { |
WiredHome | 3:17928786bdb5 | 661 | int n; |
WiredHome | 3:17928786bdb5 | 662 | offset = postQueryString + len; |
WiredHome | 3:17928786bdb5 | 663 | n = client.receive(offset, postBytes - len); |
WiredHome | 3:17928786bdb5 | 664 | if (n >=0) { |
WiredHome | 3:17928786bdb5 | 665 | offset[n] = '\0'; |
WiredHome | 28:f93ef41b78e1 | 666 | INFO("HTTPd: %d of %d: [%s]", len, postBytes, offset); |
WiredHome | 27:90a1f5a5392f | 667 | } else if (n < 0) { |
WiredHome | 28:f93ef41b78e1 | 668 | INFO("HTTPd; n=%d", n); |
WiredHome | 27:90a1f5a5392f | 669 | break; // no more data, before the plan |
WiredHome | 3:17928786bdb5 | 670 | } |
WiredHome | 3:17928786bdb5 | 671 | } |
WiredHome | 3:17928786bdb5 | 672 | if (len >= 0) { |
WiredHome | 27:90a1f5a5392f | 673 | // UnescapeString(postQueryString); |
WiredHome | 27:90a1f5a5392f | 674 | // ParseParameters(postQueryString); |
WiredHome | 27:90a1f5a5392f | 675 | // use the same handler as for the length check |
WiredHome | 28:f93ef41b78e1 | 676 | INFO("calling user code"); |
WiredHome | 27:90a1f5a5392f | 677 | acceptIt = (*handlers[ndxHandler].callback)(this, DATA_TRANSFER, postQueryString, NULL, 0); |
WiredHome | 27:90a1f5a5392f | 678 | } else { |
WiredHome | 27:90a1f5a5392f | 679 | ERR("HTTPd: len error."); |
WiredHome | 3:17928786bdb5 | 680 | } |
WiredHome | 27:90a1f5a5392f | 681 | } else { |
WiredHome | 27:90a1f5a5392f | 682 | ERR("HTTPd: attempt to allocate %d failed.", postBytes+1); |
WiredHome | 3:17928786bdb5 | 683 | } |
WiredHome | 3:17928786bdb5 | 684 | } else { |
WiredHome | 3:17928786bdb5 | 685 | // Simply copy it to the bitbucket |
WiredHome | 3:17928786bdb5 | 686 | int bytesToDump = postBytes; |
WiredHome | 8:262583f054f6 | 687 | char * bitbucket = (char *)mymalloc(201); |
WiredHome | 3:17928786bdb5 | 688 | dblCR += 4; |
WiredHome | 3:17928786bdb5 | 689 | while (*dblCR && *dblCR <= ' ') |
WiredHome | 3:17928786bdb5 | 690 | dblCR++; |
WiredHome | 3:17928786bdb5 | 691 | bytesToDump -= strlen(dblCR); |
WiredHome | 3:17928786bdb5 | 692 | while (bytesToDump > 0) { |
WiredHome | 3:17928786bdb5 | 693 | int n = (bytesToDump > 200) ? 200 : bytesToDump; |
WiredHome | 3:17928786bdb5 | 694 | n = client.receive(bitbucket, n); |
WiredHome | 3:17928786bdb5 | 695 | bytesToDump -= n; |
WiredHome | 3:17928786bdb5 | 696 | } |
WiredHome | 8:262583f054f6 | 697 | myfree(bitbucket); |
WiredHome | 3:17928786bdb5 | 698 | } |
WiredHome | 3:17928786bdb5 | 699 | } |
WiredHome | 3:17928786bdb5 | 700 | } |
WiredHome | 3:17928786bdb5 | 701 | } |
WiredHome | 3:17928786bdb5 | 702 | return advanceState; |
WiredHome | 3:17928786bdb5 | 703 | } |
WiredHome | 3:17928786bdb5 | 704 | |
WiredHome | 14:19c5f6151319 | 705 | |
WiredHome | 27:90a1f5a5392f | 706 | |
WiredHome | 13:8975d7928678 | 707 | const char * HTTPServer::GetHeaderValue(const char * hdr) |
WiredHome | 13:8975d7928678 | 708 | { |
WiredHome | 13:8975d7928678 | 709 | int i; |
WiredHome | 13:8975d7928678 | 710 | |
WiredHome | 13:8975d7928678 | 711 | for (i=0; i<headerParamCount; i++) |
WiredHome | 13:8975d7928678 | 712 | { |
WiredHome | 13:8975d7928678 | 713 | if (strcmp(hdr, headerParams[i].name) == 0) |
WiredHome | 13:8975d7928678 | 714 | return headerParams[i].value; |
WiredHome | 13:8975d7928678 | 715 | } |
WiredHome | 13:8975d7928678 | 716 | return NULL; |
WiredHome | 13:8975d7928678 | 717 | } |
WiredHome | 13:8975d7928678 | 718 | |
WiredHome | 12:109bf1558300 | 719 | |
WiredHome | 7:99ad7a67f05e | 720 | void HTTPServer::GetPerformanceData(SW_PerformanceData * p) |
WiredHome | 7:99ad7a67f05e | 721 | { |
WiredHome | 3:17928786bdb5 | 722 | memcpy(p, &perfData, sizeof(perfData)); |
WiredHome | 3:17928786bdb5 | 723 | } |
WiredHome | 3:17928786bdb5 | 724 | |
WiredHome | 17:69ff00ce39f4 | 725 | unsigned int HTTPServer::GetPerformanceClock() |
WiredHome | 17:69ff00ce39f4 | 726 | { |
WiredHome | 17:69ff00ce39f4 | 727 | return (unsigned int)PerformanceTimer.read_us(); |
WiredHome | 17:69ff00ce39f4 | 728 | } |
WiredHome | 14:19c5f6151319 | 729 | |
WiredHome | 16:6ebacf2946d8 | 730 | unsigned int HTTPServer::RecordPerformanceData(SW_PerformanceParam * param, unsigned int refTime) |
WiredHome | 7:99ad7a67f05e | 731 | { |
WiredHome | 16:6ebacf2946d8 | 732 | unsigned int t_now = (unsigned int)PerformanceTimer.read_us(); |
WiredHome | 3:17928786bdb5 | 733 | param->TotalTime_us += (t_now - refTime); |
WiredHome | 3:17928786bdb5 | 734 | param->Samples++; |
WiredHome | 3:17928786bdb5 | 735 | if ((t_now - refTime) > param->MaxTime_us) |
WiredHome | 3:17928786bdb5 | 736 | param->MaxTime_us = (t_now - refTime); |
WiredHome | 3:17928786bdb5 | 737 | return t_now; |
WiredHome | 3:17928786bdb5 | 738 | } |
WiredHome | 3:17928786bdb5 | 739 | |
WiredHome | 14:19c5f6151319 | 740 | |
WiredHome | 7:99ad7a67f05e | 741 | void HTTPServer::ResetPerformanceData() |
WiredHome | 7:99ad7a67f05e | 742 | { |
WiredHome | 3:17928786bdb5 | 743 | memset(&perfData, 0, sizeof(perfData)); |
WiredHome | 3:17928786bdb5 | 744 | } |
WiredHome | 3:17928786bdb5 | 745 | |
WiredHome | 4:f34642902056 | 746 | |
WiredHome | 21:660143f20b04 | 747 | #ifdef INCLUDE_GETREMOTE |
WiredHome | 21:660143f20b04 | 748 | bool HTTPServer::GetRemoteAddr(char * str, int strSize) |
WiredHome | 21:660143f20b04 | 749 | { |
WiredHome | 21:660143f20b04 | 750 | bool res = false; |
WiredHome | 21:660143f20b04 | 751 | char *p; |
WiredHome | 21:660143f20b04 | 752 | |
WiredHome | 21:660143f20b04 | 753 | if (strSize < 16) { // Can only guard it here w/o modifying Wifly class |
WiredHome | 21:660143f20b04 | 754 | *str = '\0'; |
WiredHome | 21:660143f20b04 | 755 | return res; |
WiredHome | 21:660143f20b04 | 756 | } |
WiredHome | 21:660143f20b04 | 757 | res = wifly->sendCommand("show z\r", NULL, str, strSize); |
WiredHome | 21:660143f20b04 | 758 | if (res) { |
WiredHome | 21:660143f20b04 | 759 | p = strchr(str, '\n'); // truncate after the octets. |
WiredHome | 21:660143f20b04 | 760 | if (p) *p = '\0'; |
WiredHome | 21:660143f20b04 | 761 | p = strchr(str, ' '); // or a space |
WiredHome | 21:660143f20b04 | 762 | if (p) *p = '\0'; |
WiredHome | 21:660143f20b04 | 763 | p = strchr(str, '<'); // or a < |
WiredHome | 21:660143f20b04 | 764 | if (p) *p = '\0'; |
WiredHome | 21:660143f20b04 | 765 | res = true; |
WiredHome | 21:660143f20b04 | 766 | } |
WiredHome | 21:660143f20b04 | 767 | wifly->exit(); |
WiredHome | 21:660143f20b04 | 768 | return res; |
WiredHome | 21:660143f20b04 | 769 | } |
WiredHome | 21:660143f20b04 | 770 | #endif |