A simple web server that can be bound to either the EthernetInterface or the WiflyInterface.
Dependents: Smart-WiFly-WebServer WattEye X10Svr SSDP_Server
SW_HTTPServer.cpp@48:078adbe279ac, 2017-04-08 (annotated)
- Committer:
- WiredHome
- Date:
- Sat Apr 08 19:39:51 2017 +0000
- Revision:
- 48:078adbe279ac
- Parent:
- 47:4c29c8f0cff2
- Child:
- 49:cd391662f254
Minor change - an additional optional parameter on the constructor that defines the blocking time (in msec) when Poll() is called. The default was way too long for most needs.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
WiredHome | 0:729320f63c5c | 1 | // |
WiredHome | 44:71f09e4255f4 | 2 | // @note Copyright © 2014-2016 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 | 29:00116fc9da74 | 14 | |
WiredHome | 44:71f09e4255f4 | 15 | //#define DEBUG "HTTP" |
WiredHome | 38:c8fa31e6fe02 | 16 | #include <cstdio> |
WiredHome | 38:c8fa31e6fe02 | 17 | #if (defined(DEBUG) && !defined(TARGET_LPC11U24)) |
WiredHome | 38:c8fa31e6fe02 | 18 | #define DBG(x, ...) std::printf("[DBG %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); |
WiredHome | 38:c8fa31e6fe02 | 19 | #define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); |
WiredHome | 38:c8fa31e6fe02 | 20 | #define ERR(x, ...) std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); |
WiredHome | 38:c8fa31e6fe02 | 21 | #define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); |
WiredHome | 38:c8fa31e6fe02 | 22 | #else |
WiredHome | 38:c8fa31e6fe02 | 23 | #define DBG(x, ...) |
WiredHome | 38:c8fa31e6fe02 | 24 | #define WARN(x, ...) |
WiredHome | 38:c8fa31e6fe02 | 25 | #define ERR(x, ...) |
WiredHome | 38:c8fa31e6fe02 | 26 | #define INFO(x, ...) |
WiredHome | 38:c8fa31e6fe02 | 27 | #endif |
WiredHome | 38:c8fa31e6fe02 | 28 | |
WiredHome | 33:ef165a67ab22 | 29 | |
WiredHome | 31:8f72be717a3c | 30 | #include "SW_HTTPServer.h" // define DEBUG before this |
WiredHome | 27:90a1f5a5392f | 31 | |
WiredHome | 33:ef165a67ab22 | 32 | #define CHUNK_SIZE 1500 // max size of a single chunk (probably limited by Ethernet to 1500) |
WiredHome | 33:ef165a67ab22 | 33 | #define HANG_TIMEOUT_MS 250 // If we're waiting on the host, which may never respond, this is the timeout |
WiredHome | 0:729320f63c5c | 34 | |
WiredHome | 0:729320f63c5c | 35 | const char * DEFAULT_FILENAME = "index.htm"; |
WiredHome | 0:729320f63c5c | 36 | |
WiredHome | 8:262583f054f6 | 37 | // Header information to always send (must be \r\n terminated) |
WiredHome | 44:71f09e4255f4 | 38 | static const char hdr_httpver[] = "HTTP/1.1"; // supported HTTP/1.1 protocol (sort of) |
WiredHome | 44:71f09e4255f4 | 39 | static const char nl[] = "\r\n"; // final \r\n for the termination of the header |
WiredHome | 0:729320f63c5c | 40 | |
WiredHome | 44:71f09e4255f4 | 41 | // Header items that are sent if the user does not provide their own options. |
WiredHome | 44:71f09e4255f4 | 42 | static const char hdr_age[] = "Max-age: 0\r\n"; // expires right away |
WiredHome | 44:71f09e4255f4 | 43 | static const char hdr_server[] = "Server: Smart_Server v0.2\r\n"; // Server |
WiredHome | 44:71f09e4255f4 | 44 | static const char hdr_close[] = "Connection: close\r\n"; // tell the client the server closes the connection immediately |
WiredHome | 14:19c5f6151319 | 45 | |
WiredHome | 0:729320f63c5c | 46 | static const struct { |
WiredHome | 0:729320f63c5c | 47 | char *ext; |
WiredHome | 0:729320f63c5c | 48 | char *filetype; |
WiredHome | 0:729320f63c5c | 49 | } extensions [] = { |
WiredHome | 3:17928786bdb5 | 50 | {".gif", "Content-Type: image/gif\r\n" }, |
WiredHome | 3:17928786bdb5 | 51 | {".jpg", "Content-Type: image/jpeg\r\n" }, |
WiredHome | 3:17928786bdb5 | 52 | {".jpeg","Content-Type: image/jpeg\r\n" }, |
WiredHome | 3:17928786bdb5 | 53 | {".ico", "Content-Type: image/x-icon\r\n" }, |
WiredHome | 33:ef165a67ab22 | 54 | {".bmp", "Content-Type: image/bmp\r\n" }, |
WiredHome | 3:17928786bdb5 | 55 | {".png", "Content-Type: image/png\r\n" }, |
WiredHome | 3:17928786bdb5 | 56 | {".zip", "Content-Type: image/zip\r\n" }, |
WiredHome | 3:17928786bdb5 | 57 | {".gz", "Content-Type: image/gz\r\n" }, |
WiredHome | 3:17928786bdb5 | 58 | {".tar", "Content-Type: image/tar\r\n" }, |
WiredHome | 3:17928786bdb5 | 59 | {".txt", "Content-Type: plain/text\r\n" }, |
WiredHome | 3:17928786bdb5 | 60 | {".pdf", "Content-Type: application/pdf\r\n" }, |
WiredHome | 3:17928786bdb5 | 61 | {".htm", "Content-Type: text/html\r\n" }, |
WiredHome | 3:17928786bdb5 | 62 | {".html","Content-Type: text/html\r\n" }, |
WiredHome | 44:71f09e4255f4 | 63 | {".xml", "Content-Type: text/xml\r\n" }, |
WiredHome | 47:4c29c8f0cff2 | 64 | {".js", "Content-Type: text/javascript\r\n" }, |
WiredHome | 0:729320f63c5c | 65 | {0,0} |
WiredHome | 0:729320f63c5c | 66 | }; |
WiredHome | 0:729320f63c5c | 67 | |
WiredHome | 44:71f09e4255f4 | 68 | typedef struct { |
WiredHome | 44:71f09e4255f4 | 69 | char * queryType; |
WiredHome | 44:71f09e4255f4 | 70 | int notused; |
WiredHome | 44:71f09e4255f4 | 71 | } QueryMethod; |
WiredHome | 44:71f09e4255f4 | 72 | |
WiredHome | 44:71f09e4255f4 | 73 | // Be sure to include a trailing space. |
WiredHome | 44:71f09e4255f4 | 74 | static const QueryMethod QueryMethodList[] = { |
WiredHome | 44:71f09e4255f4 | 75 | {"GET ", 0}, |
WiredHome | 44:71f09e4255f4 | 76 | {"POST ", 0}, |
WiredHome | 44:71f09e4255f4 | 77 | {"HEAD ", 0}, |
WiredHome | 44:71f09e4255f4 | 78 | {"PUT ", 0}, |
WiredHome | 44:71f09e4255f4 | 79 | {"OPTION ", 0}, |
WiredHome | 44:71f09e4255f4 | 80 | {"DELETE ", 0}, |
WiredHome | 44:71f09e4255f4 | 81 | {"TRACE ", 0}, |
WiredHome | 44:71f09e4255f4 | 82 | {"CONNECT ", 0}, |
WiredHome | 44:71f09e4255f4 | 83 | {NULL, 0} |
WiredHome | 44:71f09e4255f4 | 84 | }; |
WiredHome | 44:71f09e4255f4 | 85 | |
WiredHome | 30:864843965b40 | 86 | #if 0 && defined(DEBUG) |
WiredHome | 30:864843965b40 | 87 | // Haven't learned anything from this in a long time, so disabled. |
WiredHome | 12:109bf1558300 | 88 | // This uses standard library dynamic memory management, but for an |
WiredHome | 9:2ea342765c9d | 89 | // embedded system there are alternates that may make better sense - |
WiredHome | 9:2ea342765c9d | 90 | // search the web for embedded system malloc alternates. |
WiredHome | 29:00116fc9da74 | 91 | void * HTTPServer::MyMalloc(int x, int y) |
WiredHome | 8:262583f054f6 | 92 | { |
WiredHome | 29:00116fc9da74 | 93 | pc->printf("[INF HTTP%4d] malloc(%d)\r\n", y, x); |
WiredHome | 8:262583f054f6 | 94 | return malloc(x); |
WiredHome | 8:262583f054f6 | 95 | } |
WiredHome | 29:00116fc9da74 | 96 | char HTTPServer::toP(void * x) |
WiredHome | 11:17d84c41a7b3 | 97 | { |
WiredHome | 11:17d84c41a7b3 | 98 | char * c = (char *) x; |
WiredHome | 30:864843965b40 | 99 | if (*c >= ' ' && *c < 0x7F) // isprint() |
WiredHome | 11:17d84c41a7b3 | 100 | return *c; |
WiredHome | 11:17d84c41a7b3 | 101 | else |
WiredHome | 11:17d84c41a7b3 | 102 | return '.'; |
WiredHome | 11:17d84c41a7b3 | 103 | } |
WiredHome | 8:262583f054f6 | 104 | #define mymalloc(x) MyMalloc(x, __LINE__) |
WiredHome | 8:262583f054f6 | 105 | #define myfree(x) \ |
WiredHome | 25:f7d6df7a700a | 106 | pc->printf("[INF HTTP%4d] free(%02x %02x %02x %02x %02x ... %c%c%c%c%c)\r\n", __LINE__, \ |
WiredHome | 11:17d84c41a7b3 | 107 | *x, *(x+1), *(x+2), *(x+3), *(x+4), \ |
WiredHome | 11:17d84c41a7b3 | 108 | toP(x), toP(x+1), toP(x+2), toP(x+3), toP(x+4) ); \ |
WiredHome | 8:262583f054f6 | 109 | free(x); |
WiredHome | 8:262583f054f6 | 110 | #else |
WiredHome | 8:262583f054f6 | 111 | #define mymalloc(x) malloc(x) |
WiredHome | 8:262583f054f6 | 112 | #define myfree(x) free(x) |
WiredHome | 8:262583f054f6 | 113 | #endif |
WiredHome | 8:262583f054f6 | 114 | |
WiredHome | 3:17928786bdb5 | 115 | HTTPServer::HTTPServer( |
WiredHome | 7:99ad7a67f05e | 116 | int port, |
WiredHome | 7:99ad7a67f05e | 117 | const char * _webroot, |
WiredHome | 43:3fc773c2986e | 118 | int _maxheaderParams, |
WiredHome | 13:8975d7928678 | 119 | int _maxqueryParams, |
WiredHome | 7:99ad7a67f05e | 120 | int _maxdynamicpages, |
WiredHome | 7:99ad7a67f05e | 121 | PC * _pc, |
WiredHome | 7:99ad7a67f05e | 122 | int _allocforheader, |
WiredHome | 48:078adbe279ac | 123 | int _allocforfile, |
WiredHome | 48:078adbe279ac | 124 | int blockingtime) |
WiredHome | 0:729320f63c5c | 125 | { |
WiredHome | 0:729320f63c5c | 126 | webroot = (char *)malloc(strlen(_webroot)+1); |
WiredHome | 0:729320f63c5c | 127 | strcpy(webroot, _webroot); |
WiredHome | 27:90a1f5a5392f | 128 | if (strlen(webroot)>1 && webroot[strlen(webroot)-1] == '/') // remove trailing '/' |
WiredHome | 27:90a1f5a5392f | 129 | webroot[strlen(webroot)-1] = '\0'; |
WiredHome | 44:71f09e4255f4 | 130 | filenameAliasList = NULL; |
WiredHome | 43:3fc773c2986e | 131 | maxheaderParams = _maxheaderParams; |
WiredHome | 13:8975d7928678 | 132 | headerParams = (namevalue *)malloc(maxheaderParams * sizeof(namevalue)); |
WiredHome | 39:0427544a5c08 | 133 | |
WiredHome | 39:0427544a5c08 | 134 | maxqueryParams = _maxqueryParams; |
WiredHome | 13:8975d7928678 | 135 | queryParams = (namevalue *)malloc(maxqueryParams * sizeof(namevalue)); |
WiredHome | 39:0427544a5c08 | 136 | queryParamCount = 0; |
WiredHome | 39:0427544a5c08 | 137 | |
WiredHome | 39:0427544a5c08 | 138 | maxPostParams = _maxqueryParams; // Same as Query params, but for post method |
WiredHome | 39:0427544a5c08 | 139 | postParams = (namevalue *)malloc(maxPostParams * sizeof(namevalue)); |
WiredHome | 39:0427544a5c08 | 140 | postParamCount = 0; |
WiredHome | 43:3fc773c2986e | 141 | maxdynamicpages = _maxdynamicpages; |
WiredHome | 0:729320f63c5c | 142 | handlers = (handler *)malloc(maxdynamicpages * sizeof(handler)); |
WiredHome | 3:17928786bdb5 | 143 | headerbuffersize = _allocforheader; |
WiredHome | 3:17928786bdb5 | 144 | headerbuffer = (char *)malloc(headerbuffersize); |
WiredHome | 0:729320f63c5c | 145 | pc = _pc; |
WiredHome | 3:17928786bdb5 | 146 | queryType = NULL; |
WiredHome | 3:17928786bdb5 | 147 | queryString = NULL; |
WiredHome | 3:17928786bdb5 | 148 | postQueryString = NULL; |
WiredHome | 0:729320f63c5c | 149 | handlercount = 0; |
WiredHome | 3:17928786bdb5 | 150 | maxheaderbytes = 0; |
WiredHome | 0:729320f63c5c | 151 | server = new TCPSocketServer(); |
WiredHome | 0:729320f63c5c | 152 | server->bind(port); |
WiredHome | 0:729320f63c5c | 153 | server->listen(); |
WiredHome | 48:078adbe279ac | 154 | server->set_blocking(false, 10); |
WiredHome | 48:078adbe279ac | 155 | client.set_blocking(false, 10); //@TODO client is separate from server. any way to combine? |
WiredHome | 3:17928786bdb5 | 156 | ResetPerformanceData(); |
WiredHome | 10:9c8d2c6a3469 | 157 | PerformanceTimer.start(); |
WiredHome | 0:729320f63c5c | 158 | } |
WiredHome | 0:729320f63c5c | 159 | |
WiredHome | 0:729320f63c5c | 160 | HTTPServer::~HTTPServer() |
WiredHome | 0:729320f63c5c | 161 | { |
WiredHome | 8:262583f054f6 | 162 | int i; |
WiredHome | 8:262583f054f6 | 163 | |
WiredHome | 8:262583f054f6 | 164 | for (i=0; i<handlercount; i++) |
WiredHome | 8:262583f054f6 | 165 | myfree(handlers[i].path); |
WiredHome | 8:262583f054f6 | 166 | myfree(headerbuffer); |
WiredHome | 8:262583f054f6 | 167 | myfree(handlers); |
WiredHome | 13:8975d7928678 | 168 | myfree(queryParams); |
WiredHome | 8:262583f054f6 | 169 | myfree(webroot); |
WiredHome | 0:729320f63c5c | 170 | webroot = NULL; |
WiredHome | 0:729320f63c5c | 171 | } |
WiredHome | 0:729320f63c5c | 172 | |
WiredHome | 44:71f09e4255f4 | 173 | void HTTPServer::RegisterFilenameAliasList(const namevalue * namevaluelist) |
WiredHome | 44:71f09e4255f4 | 174 | { |
WiredHome | 44:71f09e4255f4 | 175 | filenameAliasList = namevaluelist; |
WiredHome | 44:71f09e4255f4 | 176 | } |
WiredHome | 44:71f09e4255f4 | 177 | |
WiredHome | 3:17928786bdb5 | 178 | int HTTPServer::GetMaxHeaderSize() |
WiredHome | 3:17928786bdb5 | 179 | { |
WiredHome | 3:17928786bdb5 | 180 | return maxheaderbytes; |
WiredHome | 3:17928786bdb5 | 181 | } |
WiredHome | 3:17928786bdb5 | 182 | |
WiredHome | 0:729320f63c5c | 183 | bool HTTPServer::RegisterHandler(const char * path, Handler callback) |
WiredHome | 0:729320f63c5c | 184 | { |
WiredHome | 0:729320f63c5c | 185 | if (handlercount < maxdynamicpages && path && callback) { |
WiredHome | 8:262583f054f6 | 186 | handlers[handlercount].path = (char *)mymalloc(strlen(path)+1); |
WiredHome | 0:729320f63c5c | 187 | memcpy(handlers[handlercount].path, path, strlen(path)+1); |
WiredHome | 0:729320f63c5c | 188 | handlers[handlercount].callback = callback; |
WiredHome | 0:729320f63c5c | 189 | handlercount++; |
WiredHome | 0:729320f63c5c | 190 | return true; |
WiredHome | 0:729320f63c5c | 191 | } else { |
WiredHome | 0:729320f63c5c | 192 | return false; |
WiredHome | 0:729320f63c5c | 193 | } |
WiredHome | 0:729320f63c5c | 194 | } |
WiredHome | 0:729320f63c5c | 195 | |
WiredHome | 2:a29c32190037 | 196 | // Poll() |
WiredHome | 0:729320f63c5c | 197 | // |
WiredHome | 0:729320f63c5c | 198 | // *OPEN*GET /x=1 HTTP/1.1 |
WiredHome | 0:729320f63c5c | 199 | // Host: 192.168.1.140 |
WiredHome | 0:729320f63c5c | 200 | // Connection: keep-alive |
WiredHome | 0:729320f63c5c | 201 | // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 |
WiredHome | 0:729320f63c5c | 202 | // 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 | 203 | // Accept-Encoding: gzip,deflate,sdch |
WiredHome | 0:729320f63c5c | 204 | // Accept-Language: en-US,en;q=0.8 |
WiredHome | 0:729320f63c5c | 205 | // |
WiredHome | 2:a29c32190037 | 206 | void HTTPServer::Poll() |
WiredHome | 0:729320f63c5c | 207 | { |
WiredHome | 3:17928786bdb5 | 208 | typedef enum { |
WiredHome | 3:17928786bdb5 | 209 | Idle, // waiting for a connection |
WiredHome | 29:00116fc9da74 | 210 | ReceivingHeader, // receiving header |
WiredHome | 29:00116fc9da74 | 211 | ReceivingPayload, // receiving a section after the Header |
WiredHome | 3:17928786bdb5 | 212 | Sending, // send the response |
WiredHome | 7:99ad7a67f05e | 213 | WaitingToClose, // small timeout to close |
WiredHome | 7:99ad7a67f05e | 214 | Reset |
WiredHome | 3:17928786bdb5 | 215 | } state; |
WiredHome | 0:729320f63c5c | 216 | static state op = Idle; |
WiredHome | 3:17928786bdb5 | 217 | static char * bPtr = headerbuffer; |
WiredHome | 0:729320f63c5c | 218 | int n; |
WiredHome | 16:6ebacf2946d8 | 219 | static unsigned int t_ref; // reference point for the PerformanceTimer |
WiredHome | 0:729320f63c5c | 220 | |
WiredHome | 20:786aa5749007 | 221 | #if defined(DEBUG) |
WiredHome | 8:262583f054f6 | 222 | static state lastOp = Reset; |
WiredHome | 7:99ad7a67f05e | 223 | if (lastOp != op) { |
WiredHome | 29:00116fc9da74 | 224 | const char *states[] = {"Idle", "ReceivingHeader", "ReceivingPayload", "Sending", "WaitingToClose", "Reset"}; |
WiredHome | 27:90a1f5a5392f | 225 | INFO("Poll: %s", states[op]); |
WiredHome | 7:99ad7a67f05e | 226 | lastOp = op; |
WiredHome | 7:99ad7a67f05e | 227 | } |
WiredHome | 8:262583f054f6 | 228 | #endif |
WiredHome | 0:729320f63c5c | 229 | switch(op) { |
WiredHome | 3:17928786bdb5 | 230 | default: // not expected to arrive here |
WiredHome | 3:17928786bdb5 | 231 | op = Idle; |
WiredHome | 3:17928786bdb5 | 232 | break; |
WiredHome | 8:262583f054f6 | 233 | |
WiredHome | 3:17928786bdb5 | 234 | case Idle: |
WiredHome | 10:9c8d2c6a3469 | 235 | PerformanceTimer.reset(); |
WiredHome | 17:69ff00ce39f4 | 236 | t_ref = (unsigned int)PerformanceTimer.read_us(); |
WiredHome | 3:17928786bdb5 | 237 | bPtr = headerbuffer; |
WiredHome | 11:17d84c41a7b3 | 238 | if (0 == server->accept(client)) { |
WiredHome | 29:00116fc9da74 | 239 | op = ReceivingHeader; |
WiredHome | 17:69ff00ce39f4 | 240 | t_ref = RecordPerformanceData(&perfData.ConnectionAccepted, t_ref); |
WiredHome | 27:90a1f5a5392f | 241 | INFO("Accepted at %u", (unsigned int)PerformanceTimer.read_us()); |
WiredHome | 48:078adbe279ac | 242 | } else { |
WiredHome | 48:078adbe279ac | 243 | INFO("Timeout waiting for accept()"); |
WiredHome | 3:17928786bdb5 | 244 | } |
WiredHome | 0:729320f63c5c | 245 | break; |
WiredHome | 8:262583f054f6 | 246 | |
WiredHome | 29:00116fc9da74 | 247 | case ReceivingHeader: |
WiredHome | 3:17928786bdb5 | 248 | n = client.receive(bPtr, headerbuffersize - (bPtr - headerbuffer)); |
WiredHome | 44:71f09e4255f4 | 249 | INFO("%sclient.receive() returned %d, from %s", (n<0) ? "*** " : "", n, client.get_address()); |
WiredHome | 3:17928786bdb5 | 250 | if (n < 0) { |
WiredHome | 29:00116fc9da74 | 251 | op = Sending; |
WiredHome | 3:17928786bdb5 | 252 | } else if (n) { |
WiredHome | 3:17928786bdb5 | 253 | bPtr[n] = '\0'; |
WiredHome | 29:00116fc9da74 | 254 | switch (ParseHeader(headerbuffer)) { |
WiredHome | 29:00116fc9da74 | 255 | case ACCEPT_ERROR: |
WiredHome | 29:00116fc9da74 | 256 | break; |
WiredHome | 29:00116fc9da74 | 257 | case ACCEPT_COMPLETE: |
WiredHome | 29:00116fc9da74 | 258 | op = Sending; |
WiredHome | 29:00116fc9da74 | 259 | t_ref = RecordPerformanceData(&perfData.HeaderParsed, t_ref); |
WiredHome | 29:00116fc9da74 | 260 | INFO("Header Parsed at %u", (unsigned int)PerformanceTimer.read_us()); |
WiredHome | 29:00116fc9da74 | 261 | break; |
WiredHome | 29:00116fc9da74 | 262 | case ACCEPT_CONTINUE: |
WiredHome | 29:00116fc9da74 | 263 | op = ReceivingPayload; |
WiredHome | 29:00116fc9da74 | 264 | break; |
WiredHome | 3:17928786bdb5 | 265 | } |
WiredHome | 3:17928786bdb5 | 266 | bPtr += n; |
WiredHome | 0:729320f63c5c | 267 | } |
WiredHome | 0:729320f63c5c | 268 | break; |
WiredHome | 8:262583f054f6 | 269 | |
WiredHome | 29:00116fc9da74 | 270 | case ReceivingPayload: |
WiredHome | 29:00116fc9da74 | 271 | // After the header, there is a payload that will be handled |
WiredHome | 33:ef165a67ab22 | 272 | #if 1 |
WiredHome | 33:ef165a67ab22 | 273 | n = client.receive(bPtr, headerbuffersize - (bPtr - headerbuffer)); |
WiredHome | 33:ef165a67ab22 | 274 | if (n < 0) { |
WiredHome | 33:ef165a67ab22 | 275 | op = Sending; |
WiredHome | 33:ef165a67ab22 | 276 | INFO("*** client.receive() => %d", n); |
WiredHome | 33:ef165a67ab22 | 277 | } else if (n) { |
WiredHome | 33:ef165a67ab22 | 278 | bPtr[n] = '\0'; |
WiredHome | 33:ef165a67ab22 | 279 | INFO("*** payload size %d", n); |
WiredHome | 33:ef165a67ab22 | 280 | } |
WiredHome | 33:ef165a67ab22 | 281 | #else |
WiredHome | 29:00116fc9da74 | 282 | op = Sending; |
WiredHome | 33:ef165a67ab22 | 283 | #endif |
WiredHome | 29:00116fc9da74 | 284 | break; |
WiredHome | 29:00116fc9da74 | 285 | |
WiredHome | 0:729320f63c5c | 286 | case Sending: |
WiredHome | 3:17928786bdb5 | 287 | SendResponse(); |
WiredHome | 0:729320f63c5c | 288 | op = WaitingToClose; |
WiredHome | 17:69ff00ce39f4 | 289 | t_ref = RecordPerformanceData(&perfData.ResponseSent, t_ref); |
WiredHome | 27:90a1f5a5392f | 290 | INFO("Response Sent at %u", (unsigned int)PerformanceTimer.read_us()); |
WiredHome | 0:729320f63c5c | 291 | break; |
WiredHome | 9:2ea342765c9d | 292 | |
WiredHome | 0:729320f63c5c | 293 | case WaitingToClose: |
WiredHome | 3:17928786bdb5 | 294 | close_connection(); |
WiredHome | 0:729320f63c5c | 295 | op = Idle; |
WiredHome | 17:69ff00ce39f4 | 296 | RecordPerformanceData(&perfData.ConnectionClosed, t_ref); |
WiredHome | 44:71f09e4255f4 | 297 | INFO("Connection closed exit: %u\r\n\r\n", (unsigned int)PerformanceTimer.read_us()); |
WiredHome | 0:729320f63c5c | 298 | break; |
WiredHome | 0:729320f63c5c | 299 | } |
WiredHome | 0:729320f63c5c | 300 | } |
WiredHome | 0:729320f63c5c | 301 | |
WiredHome | 0:729320f63c5c | 302 | |
WiredHome | 0:729320f63c5c | 303 | const char * HTTPServer::GetSupportedType(const char * filename) |
WiredHome | 0:729320f63c5c | 304 | { |
WiredHome | 0:729320f63c5c | 305 | int i; |
WiredHome | 0:729320f63c5c | 306 | int buflen = strlen(filename); |
WiredHome | 0:729320f63c5c | 307 | int extlen; |
WiredHome | 0:729320f63c5c | 308 | |
WiredHome | 0:729320f63c5c | 309 | for (i=0; extensions[i].ext != 0; i++) { |
WiredHome | 0:729320f63c5c | 310 | extlen = strlen(extensions[i].ext); |
WiredHome | 0:729320f63c5c | 311 | if ( !strncmp(&filename[buflen-extlen], extensions[i].ext, extlen)) { |
WiredHome | 0:729320f63c5c | 312 | return extensions[i].filetype; |
WiredHome | 0:729320f63c5c | 313 | } |
WiredHome | 0:729320f63c5c | 314 | } |
WiredHome | 0:729320f63c5c | 315 | return NULL; |
WiredHome | 0:729320f63c5c | 316 | } |
WiredHome | 0:729320f63c5c | 317 | |
WiredHome | 3:17928786bdb5 | 318 | |
WiredHome | 0:729320f63c5c | 319 | void HTTPServer::send(const char * msg, int bytes) |
WiredHome | 0:729320f63c5c | 320 | { |
WiredHome | 0:729320f63c5c | 321 | if (bytes == -1) |
WiredHome | 0:729320f63c5c | 322 | bytes = strlen(msg); |
WiredHome | 44:71f09e4255f4 | 323 | INFO("Sending %d bytes", bytes); |
WiredHome | 44:71f09e4255f4 | 324 | //INFO("send:\r\n%s", msg); |
WiredHome | 48:078adbe279ac | 325 | #ifdef DEBUG |
WiredHome | 48:078adbe279ac | 326 | int r = |
WiredHome | 48:078adbe279ac | 327 | #endif |
WiredHome | 20:786aa5749007 | 328 | client.send((char *)msg, bytes); |
WiredHome | 44:71f09e4255f4 | 329 | INFO("client.send returned: %d", r); |
WiredHome | 0:729320f63c5c | 330 | } |
WiredHome | 0:729320f63c5c | 331 | |
WiredHome | 44:71f09e4255f4 | 332 | const char * HTTPServer::FindAlias(const HTTPServer::namevalue * haystack, const char * needle) |
WiredHome | 44:71f09e4255f4 | 333 | { |
WiredHome | 44:71f09e4255f4 | 334 | while (haystack && haystack->name) { |
WiredHome | 44:71f09e4255f4 | 335 | if (strcmp(haystack->name,needle) == 0) |
WiredHome | 44:71f09e4255f4 | 336 | return haystack->value; |
WiredHome | 44:71f09e4255f4 | 337 | haystack++; |
WiredHome | 44:71f09e4255f4 | 338 | } |
WiredHome | 44:71f09e4255f4 | 339 | return needle; |
WiredHome | 44:71f09e4255f4 | 340 | } |
WiredHome | 44:71f09e4255f4 | 341 | |
WiredHome | 44:71f09e4255f4 | 342 | uint32_t HTTPServer::FileSize(const char * filename) |
WiredHome | 44:71f09e4255f4 | 343 | { |
WiredHome | 44:71f09e4255f4 | 344 | uint32_t size = 0; |
WiredHome | 44:71f09e4255f4 | 345 | FILE * fh; |
WiredHome | 44:71f09e4255f4 | 346 | |
WiredHome | 44:71f09e4255f4 | 347 | filename = FindAlias(filenameAliasList, filename); |
WiredHome | 44:71f09e4255f4 | 348 | fh = fopen(filename, "r"); |
WiredHome | 44:71f09e4255f4 | 349 | if (fh) { |
WiredHome | 44:71f09e4255f4 | 350 | fseek(fh, 0, SEEK_END); // seek to end of file |
WiredHome | 44:71f09e4255f4 | 351 | size = ftell(fh); // get current file pointer |
WiredHome | 44:71f09e4255f4 | 352 | fclose(fh); |
WiredHome | 44:71f09e4255f4 | 353 | } |
WiredHome | 44:71f09e4255f4 | 354 | return size; |
WiredHome | 44:71f09e4255f4 | 355 | } |
WiredHome | 3:17928786bdb5 | 356 | |
WiredHome | 0:729320f63c5c | 357 | bool HTTPServer::SendFile(const char * filename, const char * filetype) |
WiredHome | 0:729320f63c5c | 358 | { |
WiredHome | 0:729320f63c5c | 359 | FILE * fp; |
WiredHome | 3:17928786bdb5 | 360 | |
WiredHome | 44:71f09e4255f4 | 361 | INFO("SendFile(%s,...)", filename); |
WiredHome | 44:71f09e4255f4 | 362 | filename = FindAlias(filenameAliasList, filename); |
WiredHome | 44:71f09e4255f4 | 363 | INFO(" Alias(%s,...)", filename); |
WiredHome | 0:729320f63c5c | 364 | fp = fopen(filename,"rb"); |
WiredHome | 0:729320f63c5c | 365 | if (fp) { // can open it |
WiredHome | 8:262583f054f6 | 366 | char *fbuffer = (char *)mymalloc(FILESEND_BUF_SIZE); |
WiredHome | 0:729320f63c5c | 367 | int bytes; |
WiredHome | 0:729320f63c5c | 368 | |
WiredHome | 3:17928786bdb5 | 369 | if (fbuffer) { |
WiredHome | 44:71f09e4255f4 | 370 | char ContentLen[30]; |
WiredHome | 44:71f09e4255f4 | 371 | snprintf(ContentLen, sizeof(ContentLen), "Content-Length: %u\r\n", FileSize(filename)); |
WiredHome | 44:71f09e4255f4 | 372 | header(OK, "OK", filetype, ContentLen); |
WiredHome | 44:71f09e4255f4 | 373 | header(""); |
WiredHome | 0:729320f63c5c | 374 | bytes = fread(fbuffer,sizeof(char),FILESEND_BUF_SIZE,fp); |
WiredHome | 3:17928786bdb5 | 375 | while (bytes > 0) { |
WiredHome | 3:17928786bdb5 | 376 | send(fbuffer, bytes); |
WiredHome | 3:17928786bdb5 | 377 | bytes = fread(fbuffer,sizeof(char),FILESEND_BUF_SIZE,fp); |
WiredHome | 3:17928786bdb5 | 378 | } |
WiredHome | 8:262583f054f6 | 379 | myfree(fbuffer); |
WiredHome | 3:17928786bdb5 | 380 | } else { |
WiredHome | 44:71f09e4255f4 | 381 | header(Server_Error, "Server Error", NULL, "Pragma: err - insufficient memory\r\n"); |
WiredHome | 44:71f09e4255f4 | 382 | header(""); |
WiredHome | 0:729320f63c5c | 383 | } |
WiredHome | 0:729320f63c5c | 384 | fclose(fp); |
WiredHome | 0:729320f63c5c | 385 | return true; |
WiredHome | 0:729320f63c5c | 386 | } else { |
WiredHome | 44:71f09e4255f4 | 387 | header(Not_Found, "Not Found", NULL, "Pragma: err - Can't open file\r\n"); |
WiredHome | 44:71f09e4255f4 | 388 | header(""); |
WiredHome | 0:729320f63c5c | 389 | return false; |
WiredHome | 0:729320f63c5c | 390 | } |
WiredHome | 0:729320f63c5c | 391 | } |
WiredHome | 0:729320f63c5c | 392 | |
WiredHome | 0:729320f63c5c | 393 | int HTTPServer::HexCharToInt(char c) |
WiredHome | 0:729320f63c5c | 394 | { |
WiredHome | 0:729320f63c5c | 395 | if (c >= 'a' && c <= 'f') |
WiredHome | 0:729320f63c5c | 396 | return (c - 'a' + 10); |
WiredHome | 0:729320f63c5c | 397 | else if (c >= 'A' && c <= 'F') |
WiredHome | 0:729320f63c5c | 398 | return (c - 'A' + 10); |
WiredHome | 0:729320f63c5c | 399 | else if (c >= '0' && c <= '9') |
WiredHome | 0:729320f63c5c | 400 | return c - '0'; |
WiredHome | 0:729320f63c5c | 401 | else |
WiredHome | 0:729320f63c5c | 402 | return 0; |
WiredHome | 0:729320f63c5c | 403 | } |
WiredHome | 0:729320f63c5c | 404 | |
WiredHome | 0:729320f63c5c | 405 | char HTTPServer::HexPairToChar(char * p) |
WiredHome | 0:729320f63c5c | 406 | { |
WiredHome | 0:729320f63c5c | 407 | return 16 * HexCharToInt(*p) + HexCharToInt(*(p+1)); |
WiredHome | 0:729320f63c5c | 408 | } |
WiredHome | 0:729320f63c5c | 409 | |
WiredHome | 39:0427544a5c08 | 410 | // modifies in-place |
WiredHome | 0:729320f63c5c | 411 | void HTTPServer::UnescapeString(char * encoded) |
WiredHome | 0:729320f63c5c | 412 | { |
WiredHome | 0:729320f63c5c | 413 | char *p; |
WiredHome | 0:729320f63c5c | 414 | |
WiredHome | 0:729320f63c5c | 415 | // first convert '+' to ' ' |
WiredHome | 0:729320f63c5c | 416 | p = strchr(encoded, '+'); |
WiredHome | 0:729320f63c5c | 417 | while (p) { |
WiredHome | 0:729320f63c5c | 418 | *p = ' '; |
WiredHome | 0:729320f63c5c | 419 | p = strchr(encoded, '+'); |
WiredHome | 0:729320f63c5c | 420 | } |
WiredHome | 0:729320f63c5c | 421 | // then convert hex '%xx' to char 'x' |
WiredHome | 0:729320f63c5c | 422 | p = strchr(encoded, '%'); |
WiredHome | 0:729320f63c5c | 423 | while (p) { |
WiredHome | 0:729320f63c5c | 424 | if (strchr("0123456789ABCDEFabcdef", *(p+1)) |
WiredHome | 0:729320f63c5c | 425 | && strchr("0123456789ABCDEFabcdef", *(p+2)) ) { |
WiredHome | 0:729320f63c5c | 426 | *p = HexPairToChar(p+1); |
WiredHome | 0:729320f63c5c | 427 | p++; // advance past the % |
WiredHome | 0:729320f63c5c | 428 | char * a = p; |
WiredHome | 0:729320f63c5c | 429 | char * b = p + 2; |
WiredHome | 0:729320f63c5c | 430 | do { |
WiredHome | 0:729320f63c5c | 431 | *a++ = *b++; |
WiredHome | 0:729320f63c5c | 432 | } while (*b); |
WiredHome | 0:729320f63c5c | 433 | *a = '\0'; |
WiredHome | 0:729320f63c5c | 434 | } |
WiredHome | 0:729320f63c5c | 435 | p = strchr(p, '%'); |
WiredHome | 0:729320f63c5c | 436 | } |
WiredHome | 0:729320f63c5c | 437 | } |
WiredHome | 0:729320f63c5c | 438 | |
WiredHome | 0:729320f63c5c | 439 | const char * HTTPServer::GetParameter(const char * name) |
WiredHome | 0:729320f63c5c | 440 | { |
WiredHome | 37:0cb2774e2410 | 441 | INFO("GetParameter(%s)", name); |
WiredHome | 13:8975d7928678 | 442 | for (int i=0; i<queryParamCount; i++) { |
WiredHome | 37:0cb2774e2410 | 443 | INFO(" %d: %s = %s", i, queryParams[i].name, queryParams[i].value); |
WiredHome | 13:8975d7928678 | 444 | if (strcmp(queryParams[i].name, name) == 0) { |
WiredHome | 37:0cb2774e2410 | 445 | INFO(" value {%s}", queryParams[i].value); |
WiredHome | 13:8975d7928678 | 446 | return queryParams[i].value; |
WiredHome | 0:729320f63c5c | 447 | } |
WiredHome | 0:729320f63c5c | 448 | } |
WiredHome | 0:729320f63c5c | 449 | return NULL; |
WiredHome | 0:729320f63c5c | 450 | } |
WiredHome | 0:729320f63c5c | 451 | |
WiredHome | 44:71f09e4255f4 | 452 | const HTTPServer::namevalue * HTTPServer::GetParameter(int index) |
WiredHome | 39:0427544a5c08 | 453 | { |
WiredHome | 39:0427544a5c08 | 454 | if (index < queryParamCount) |
WiredHome | 39:0427544a5c08 | 455 | return &queryParams[index]; |
WiredHome | 39:0427544a5c08 | 456 | else |
WiredHome | 39:0427544a5c08 | 457 | return NULL; |
WiredHome | 39:0427544a5c08 | 458 | } |
WiredHome | 39:0427544a5c08 | 459 | |
WiredHome | 39:0427544a5c08 | 460 | const char * HTTPServer::GetPostParameter(const char * name) |
WiredHome | 39:0427544a5c08 | 461 | { |
WiredHome | 39:0427544a5c08 | 462 | INFO("GetPostParameter(%s)", name); |
WiredHome | 39:0427544a5c08 | 463 | for (int i=0; i<postParamCount; i++) { |
WiredHome | 39:0427544a5c08 | 464 | INFO(" %d: %s = %s", i, postParams[i].name, postParams[i].value); |
WiredHome | 39:0427544a5c08 | 465 | if (strcmp(postParams[i].name, name) == 0) { |
WiredHome | 39:0427544a5c08 | 466 | INFO(" value {%s}", postParams[i].value); |
WiredHome | 39:0427544a5c08 | 467 | return postParams[i].value; |
WiredHome | 39:0427544a5c08 | 468 | } |
WiredHome | 39:0427544a5c08 | 469 | } |
WiredHome | 39:0427544a5c08 | 470 | return NULL; |
WiredHome | 39:0427544a5c08 | 471 | } |
WiredHome | 39:0427544a5c08 | 472 | |
WiredHome | 39:0427544a5c08 | 473 | HTTPServer::namevalue * HTTPServer::GetPostParameter(int index) |
WiredHome | 39:0427544a5c08 | 474 | { |
WiredHome | 39:0427544a5c08 | 475 | if (index < postParamCount) |
WiredHome | 39:0427544a5c08 | 476 | return &postParams[index]; |
WiredHome | 39:0427544a5c08 | 477 | else |
WiredHome | 39:0427544a5c08 | 478 | return NULL; |
WiredHome | 39:0427544a5c08 | 479 | } |
WiredHome | 37:0cb2774e2410 | 480 | |
WiredHome | 0:729320f63c5c | 481 | // this=that&who=what&more=stuff... |
WiredHome | 0:729320f63c5c | 482 | // ^ ^ ^ |
WiredHome | 39:0427544a5c08 | 483 | int HTTPServer::ParseParameters(namevalue * qP, int * qpCount, int maxP, char * pName) |
WiredHome | 0:729320f63c5c | 484 | { |
WiredHome | 0:729320f63c5c | 485 | char * pVal; |
WiredHome | 0:729320f63c5c | 486 | char * pNextName; |
WiredHome | 0:729320f63c5c | 487 | |
WiredHome | 13:8975d7928678 | 488 | // Parse queryParams |
WiredHome | 0:729320f63c5c | 489 | pVal = strchr(pName, '#'); // If there is a '#fragment_id', we can ignore it |
WiredHome | 0:729320f63c5c | 490 | if (pVal) |
WiredHome | 3:17928786bdb5 | 491 | *pVal = '\0'; |
WiredHome | 0:729320f63c5c | 492 | do { |
Sissors | 42:0d5b682bb17a | 493 | INFO("ParseParameters(%s), qpCount: %d", pName, *qpCount); |
WiredHome | 39:0427544a5c08 | 494 | qP->name = pName; |
WiredHome | 0:729320f63c5c | 495 | pVal = strchr(pName, '='); |
WiredHome | 0:729320f63c5c | 496 | pNextName = strchr(pName,'&'); |
WiredHome | 0:729320f63c5c | 497 | if (pVal) { |
WiredHome | 0:729320f63c5c | 498 | if (pNextName == NULL || (pNextName && pNextName > pVal)) { |
WiredHome | 0:729320f63c5c | 499 | *pVal++ = '\0'; |
WiredHome | 39:0427544a5c08 | 500 | qP->value = pVal; |
WiredHome | 0:729320f63c5c | 501 | pName = pVal; |
WiredHome | 0:729320f63c5c | 502 | } |
WiredHome | 0:729320f63c5c | 503 | } |
WiredHome | 0:729320f63c5c | 504 | if (pNextName) { |
WiredHome | 0:729320f63c5c | 505 | pName = pNextName; |
WiredHome | 0:729320f63c5c | 506 | *pName++ = '\0'; |
WiredHome | 0:729320f63c5c | 507 | } else { |
WiredHome | 0:729320f63c5c | 508 | pName = NULL; |
WiredHome | 0:729320f63c5c | 509 | } |
WiredHome | 39:0427544a5c08 | 510 | INFO(" param{%s}={%s}", qP->name, qP->value); |
WiredHome | 39:0427544a5c08 | 511 | *qpCount += 1; |
WiredHome | 39:0427544a5c08 | 512 | qP++; |
WiredHome | 39:0427544a5c08 | 513 | } while (pName && *qpCount < maxP); |
WiredHome | 39:0427544a5c08 | 514 | INFO(" count %d", *qpCount); |
WiredHome | 39:0427544a5c08 | 515 | return *qpCount; |
WiredHome | 0:729320f63c5c | 516 | } |
WiredHome | 0:729320f63c5c | 517 | |
WiredHome | 0:729320f63c5c | 518 | |
WiredHome | 44:71f09e4255f4 | 519 | void HTTPServer::header(HTTPServer::HeaderCodes code, const char * code_text, const char * content_type, const char * optional_text) |
WiredHome | 0:729320f63c5c | 520 | { |
WiredHome | 0:729320f63c5c | 521 | char http[100]; |
WiredHome | 0:729320f63c5c | 522 | |
WiredHome | 44:71f09e4255f4 | 523 | INFO("header(%d, %s, %s, ...)", code, code_text, content_type); |
WiredHome | 44:71f09e4255f4 | 524 | snprintf(http, sizeof(http), "%s %i %s\r\n", hdr_httpver, code, code_text); |
WiredHome | 0:729320f63c5c | 525 | send(http); |
WiredHome | 0:729320f63c5c | 526 | if (content_type) { |
WiredHome | 0:729320f63c5c | 527 | send(content_type); |
WiredHome | 0:729320f63c5c | 528 | } |
WiredHome | 0:729320f63c5c | 529 | if (optional_text) { |
WiredHome | 44:71f09e4255f4 | 530 | if (*optional_text != '\0') |
WiredHome | 44:71f09e4255f4 | 531 | send(optional_text); |
WiredHome | 44:71f09e4255f4 | 532 | } else { |
WiredHome | 44:71f09e4255f4 | 533 | send(hdr_age); |
WiredHome | 44:71f09e4255f4 | 534 | send(hdr_server); |
WiredHome | 44:71f09e4255f4 | 535 | send(hdr_close); |
WiredHome | 44:71f09e4255f4 | 536 | header(""); |
WiredHome | 0:729320f63c5c | 537 | } |
WiredHome | 0:729320f63c5c | 538 | } |
WiredHome | 0:729320f63c5c | 539 | |
WiredHome | 44:71f09e4255f4 | 540 | void HTTPServer::header(const char * partialheader) |
WiredHome | 44:71f09e4255f4 | 541 | { |
WiredHome | 44:71f09e4255f4 | 542 | if (!partialheader || *partialheader == '\0') |
WiredHome | 44:71f09e4255f4 | 543 | send(nl); |
WiredHome | 44:71f09e4255f4 | 544 | else |
WiredHome | 44:71f09e4255f4 | 545 | send(partialheader); |
WiredHome | 44:71f09e4255f4 | 546 | } |
WiredHome | 14:19c5f6151319 | 547 | |
WiredHome | 7:99ad7a67f05e | 548 | bool HTTPServer::close_connection() |
WiredHome | 0:729320f63c5c | 549 | { |
WiredHome | 7:99ad7a67f05e | 550 | bool res; |
WiredHome | 7:99ad7a67f05e | 551 | |
Sissors | 41:6f2f1fb96742 | 552 | res = client.close(); |
WiredHome | 27:90a1f5a5392f | 553 | INFO("close connection returned %d", res); |
WiredHome | 7:99ad7a67f05e | 554 | return res; |
WiredHome | 0:729320f63c5c | 555 | } |
WiredHome | 0:729320f63c5c | 556 | |
WiredHome | 14:19c5f6151319 | 557 | |
WiredHome | 0:729320f63c5c | 558 | bool HTTPServer::Extract(char * haystack, char * needle, char ** string) |
WiredHome | 0:729320f63c5c | 559 | { |
WiredHome | 0:729320f63c5c | 560 | bool ret = false; // assume failure until proven otherwise |
WiredHome | 0:729320f63c5c | 561 | char * qs = NULL; |
WiredHome | 0:729320f63c5c | 562 | char * eqs = NULL; |
WiredHome | 0:729320f63c5c | 563 | char * container = NULL; |
WiredHome | 0:729320f63c5c | 564 | char * get = strstr(haystack, needle); // what if not at the front? |
WiredHome | 44:71f09e4255f4 | 565 | |
WiredHome | 0:729320f63c5c | 566 | if (get) { |
WiredHome | 44:71f09e4255f4 | 567 | // Seems to be a valid "GET /QueryString HTTP/1.1" |
WiredHome | 44:71f09e4255f4 | 568 | // or "POST /upnp/control/metainfo1 HTTP/1.0" |
WiredHome | 8:262583f054f6 | 569 | // or "...<needle>param..." |
WiredHome | 0:729320f63c5c | 570 | qs = get + strlen(needle); // in case the needle didn't have space delimiters |
WiredHome | 0:729320f63c5c | 571 | while (*qs == ' ') |
WiredHome | 0:729320f63c5c | 572 | qs++; |
WiredHome | 0:729320f63c5c | 573 | // /QueryString\0HTTP/1.1\0\0 |
WiredHome | 0:729320f63c5c | 574 | if (*string) // recycle old string when working a new one |
WiredHome | 8:262583f054f6 | 575 | myfree(*string); |
WiredHome | 8:262583f054f6 | 576 | container = (char *)mymalloc(strlen(qs)); |
WiredHome | 0:729320f63c5c | 577 | if (container) { |
WiredHome | 0:729320f63c5c | 578 | strcpy(container, qs); |
WiredHome | 0:729320f63c5c | 579 | eqs = strchr(container, ' '); |
WiredHome | 0:729320f63c5c | 580 | if (eqs) |
WiredHome | 0:729320f63c5c | 581 | *eqs = '\0'; |
WiredHome | 0:729320f63c5c | 582 | *string = container; |
WiredHome | 27:90a1f5a5392f | 583 | INFO("Extract(%s) = %s", needle, container); |
WiredHome | 0:729320f63c5c | 584 | ret = true; |
WiredHome | 0:729320f63c5c | 585 | } else { |
WiredHome | 0:729320f63c5c | 586 | *string = NULL; // something bad happened... no memory |
WiredHome | 0:729320f63c5c | 587 | } |
WiredHome | 0:729320f63c5c | 588 | } |
WiredHome | 0:729320f63c5c | 589 | return ret; |
WiredHome | 0:729320f63c5c | 590 | } |
WiredHome | 0:729320f63c5c | 591 | |
WiredHome | 14:19c5f6151319 | 592 | |
WiredHome | 0:729320f63c5c | 593 | char * HTTPServer::rewriteWithDefaultFile(char * queryString) |
WiredHome | 0:729320f63c5c | 594 | { |
WiredHome | 8:262583f054f6 | 595 | char * temp = (char *)mymalloc(strlen(queryString) + strlen(DEFAULT_FILENAME) + 1); |
WiredHome | 0:729320f63c5c | 596 | |
WiredHome | 0:729320f63c5c | 597 | if (temp) { |
WiredHome | 0:729320f63c5c | 598 | *temp = '\0'; |
WiredHome | 0:729320f63c5c | 599 | strcpy(temp, queryString); |
WiredHome | 0:729320f63c5c | 600 | strcat(temp, DEFAULT_FILENAME); |
WiredHome | 8:262583f054f6 | 601 | myfree(queryString); |
WiredHome | 0:729320f63c5c | 602 | return temp; |
WiredHome | 0:729320f63c5c | 603 | } else { |
WiredHome | 0:729320f63c5c | 604 | return queryString; |
WiredHome | 0:729320f63c5c | 605 | } |
WiredHome | 0:729320f63c5c | 606 | } |
WiredHome | 0:729320f63c5c | 607 | |
WiredHome | 14:19c5f6151319 | 608 | |
WiredHome | 0:729320f63c5c | 609 | char * HTTPServer::rewritePrependWebroot(char * queryString) |
WiredHome | 0:729320f63c5c | 610 | { |
WiredHome | 24:062431453abb | 611 | char * temp = (char *)mymalloc(strlen(webroot) + strlen(queryString) + 2); // save room for '/' |
WiredHome | 0:729320f63c5c | 612 | |
WiredHome | 0:729320f63c5c | 613 | if (temp) { |
WiredHome | 24:062431453abb | 614 | char *lastC; |
WiredHome | 0:729320f63c5c | 615 | *temp = '\0'; |
WiredHome | 0:729320f63c5c | 616 | strcpy(temp, webroot); |
WiredHome | 24:062431453abb | 617 | lastC = &temp[strlen(temp)-1]; |
WiredHome | 24:062431453abb | 618 | if (*lastC == '/' && *queryString == '/') |
WiredHome | 24:062431453abb | 619 | queryString++; // don't create two '/' |
WiredHome | 24:062431453abb | 620 | else if (*lastC != '/' && *queryString != '/') |
WiredHome | 24:062431453abb | 621 | strcat(temp, "/"); |
WiredHome | 0:729320f63c5c | 622 | strcat(temp, queryString); |
WiredHome | 8:262583f054f6 | 623 | myfree(queryString); |
WiredHome | 0:729320f63c5c | 624 | return temp; |
WiredHome | 0:729320f63c5c | 625 | } else { |
WiredHome | 0:729320f63c5c | 626 | return queryString; |
WiredHome | 0:729320f63c5c | 627 | } |
WiredHome | 0:729320f63c5c | 628 | } |
WiredHome | 0:729320f63c5c | 629 | |
WiredHome | 14:19c5f6151319 | 630 | |
WiredHome | 3:17928786bdb5 | 631 | bool HTTPServer::CheckDynamicHandlers() |
WiredHome | 3:17928786bdb5 | 632 | { |
WiredHome | 3:17928786bdb5 | 633 | bool regHandled = false; |
WiredHome | 0:729320f63c5c | 634 | |
WiredHome | 3:17928786bdb5 | 635 | // If this queryString is in the list of registered handlers, call that |
WiredHome | 3:17928786bdb5 | 636 | for (int i=0; i<handlercount; i++) { |
WiredHome | 3:17928786bdb5 | 637 | if (strcmp(handlers[i].path, queryString) == 0) { |
WiredHome | 39:0427544a5c08 | 638 | INFO("CheckDynamicHandlers - SEND_PAGE"); |
WiredHome | 13:8975d7928678 | 639 | (*handlers[i].callback)(this, SEND_PAGE, queryString, queryParams, queryParamCount); |
WiredHome | 3:17928786bdb5 | 640 | regHandled = true; |
WiredHome | 3:17928786bdb5 | 641 | break; // we only execute the first one |
WiredHome | 3:17928786bdb5 | 642 | } |
WiredHome | 3:17928786bdb5 | 643 | } |
WiredHome | 3:17928786bdb5 | 644 | return regHandled; |
WiredHome | 3:17928786bdb5 | 645 | } |
WiredHome | 3:17928786bdb5 | 646 | |
WiredHome | 14:19c5f6151319 | 647 | |
WiredHome | 3:17928786bdb5 | 648 | void HTTPServer::SendResponse() |
WiredHome | 3:17928786bdb5 | 649 | { |
WiredHome | 27:90a1f5a5392f | 650 | INFO("SendResponse(%s) at %u", queryType, (unsigned int)PerformanceTimer.read_us()); |
WiredHome | 44:71f09e4255f4 | 651 | if (strcmp(queryType, "GET ") == 0 || strcmp(queryType, "POST ") == 0) { |
WiredHome | 3:17928786bdb5 | 652 | if (!(queryString[0] == '.' && queryString[1] == '.')) { |
WiredHome | 3:17928786bdb5 | 653 | const char * fType; |
WiredHome | 3:17928786bdb5 | 654 | |
WiredHome | 3:17928786bdb5 | 655 | if (!CheckDynamicHandlers()) { |
WiredHome | 3:17928786bdb5 | 656 | // Otherwise, this queryString must be trying to reference a static file |
WiredHome | 3:17928786bdb5 | 657 | if (queryString[strlen(queryString)-1] == '/') { |
WiredHome | 3:17928786bdb5 | 658 | queryString = rewriteWithDefaultFile(queryString); |
WiredHome | 3:17928786bdb5 | 659 | } |
WiredHome | 44:71f09e4255f4 | 660 | INFO(" queryString: %s", queryString); |
WiredHome | 3:17928786bdb5 | 661 | // see if we support this file type |
WiredHome | 3:17928786bdb5 | 662 | fType = GetSupportedType(queryString); |
WiredHome | 3:17928786bdb5 | 663 | if (fType) { |
WiredHome | 3:17928786bdb5 | 664 | queryString = rewritePrependWebroot(queryString); |
WiredHome | 44:71f09e4255f4 | 665 | INFO(" SendFile(%s,%s)", queryString, fType); |
WiredHome | 3:17928786bdb5 | 666 | SendFile(queryString, fType); |
WiredHome | 3:17928786bdb5 | 667 | } else { |
WiredHome | 44:71f09e4255f4 | 668 | header(Not_Found, "Not Found", NULL, "Pragma: err - Unsupported type\r\n"); |
WiredHome | 44:71f09e4255f4 | 669 | header(""); |
WiredHome | 3:17928786bdb5 | 670 | } |
WiredHome | 3:17928786bdb5 | 671 | } |
WiredHome | 3:17928786bdb5 | 672 | } else { |
WiredHome | 44:71f09e4255f4 | 673 | header(Bad_Request, "Bad Request", NULL, "Pragma: err - Unsupported path\r\n"); |
WiredHome | 44:71f09e4255f4 | 674 | header(""); |
WiredHome | 3:17928786bdb5 | 675 | } |
WiredHome | 3:17928786bdb5 | 676 | } else { |
WiredHome | 44:71f09e4255f4 | 677 | header(Bad_Request, "Bad Request", NULL, "Pragma: err - Unsupported query type\r\n"); |
WiredHome | 44:71f09e4255f4 | 678 | header(""); |
WiredHome | 3:17928786bdb5 | 679 | } |
WiredHome | 27:90a1f5a5392f | 680 | INFO(" SendResponse complete at %u", (unsigned int)PerformanceTimer.read_us()); |
WiredHome | 17:69ff00ce39f4 | 681 | |
WiredHome | 3:17928786bdb5 | 682 | if (queryType) { |
WiredHome | 8:262583f054f6 | 683 | myfree(queryType); |
WiredHome | 3:17928786bdb5 | 684 | queryType = NULL; |
WiredHome | 3:17928786bdb5 | 685 | } |
WiredHome | 3:17928786bdb5 | 686 | if (queryString) { |
WiredHome | 8:262583f054f6 | 687 | myfree(queryString); |
WiredHome | 3:17928786bdb5 | 688 | queryString = NULL; |
WiredHome | 3:17928786bdb5 | 689 | } |
WiredHome | 3:17928786bdb5 | 690 | if (postQueryString) { |
WiredHome | 8:262583f054f6 | 691 | myfree(postQueryString); |
WiredHome | 3:17928786bdb5 | 692 | postQueryString = NULL; |
WiredHome | 3:17928786bdb5 | 693 | } |
WiredHome | 27:90a1f5a5392f | 694 | INFO(" SendResponse free at %u", (unsigned int)PerformanceTimer.read_us()); |
WiredHome | 3:17928786bdb5 | 695 | } |
WiredHome | 3:17928786bdb5 | 696 | |
WiredHome | 14:19c5f6151319 | 697 | |
WiredHome | 29:00116fc9da74 | 698 | HTTPServer::CallBackResults HTTPServer::ParseHeader(char * buffer) |
WiredHome | 3:17928786bdb5 | 699 | { |
WiredHome | 3:17928786bdb5 | 700 | char * dblCR; |
WiredHome | 29:00116fc9da74 | 701 | CallBackResults advanceState = ACCEPT_ERROR; |
WiredHome | 3:17928786bdb5 | 702 | int bytecount; |
WiredHome | 7:99ad7a67f05e | 703 | |
WiredHome | 3:17928786bdb5 | 704 | // Buffer could have partial, but the double \r\n is the key |
WiredHome | 13:8975d7928678 | 705 | // GET /QueryString?this=that&sky=blue HTTP/1.1\r\n |
WiredHome | 8:262583f054f6 | 706 | // GET /QueryString HTTP/1.1\r\nHost: 192.168.1.140\r\nCache-Con |
WiredHome | 8:262583f054f6 | 707 | // GET /QueryString HTTP/1.1\r\nHost: 192.168.1.140\r\nCache-Control: max-age=0\r\n\r\n |
WiredHome | 39:0427544a5c08 | 708 | // POST /dyn2 HTTP/1.2\r\nAccept: text/html, application/xhtml+xml, */*\r\n\r\n |
WiredHome | 3:17928786bdb5 | 709 | dblCR = strstr(buffer,"\r\n\r\n"); |
WiredHome | 3:17928786bdb5 | 710 | if (dblCR) { // Have to scan from the beginning in case split on \r |
WiredHome | 44:71f09e4255f4 | 711 | INFO("\r\n==\r\n%s\r\n==", buffer); |
WiredHome | 3:17928786bdb5 | 712 | char * soRec = buffer; // start of the next record of text |
WiredHome | 13:8975d7928678 | 713 | char * eoRec = strchr(soRec, '\n'); // search for end of the current record |
WiredHome | 7:99ad7a67f05e | 714 | |
WiredHome | 13:8975d7928678 | 715 | headerParamCount = 0; |
WiredHome | 3:17928786bdb5 | 716 | bytecount = strlen(buffer); |
WiredHome | 3:17928786bdb5 | 717 | if (bytecount > maxheaderbytes) |
WiredHome | 3:17928786bdb5 | 718 | maxheaderbytes = bytecount; |
WiredHome | 3:17928786bdb5 | 719 | while (eoRec) { |
WiredHome | 3:17928786bdb5 | 720 | *eoRec = '\0'; |
WiredHome | 3:17928786bdb5 | 721 | if (*(eoRec-1) == '\r') |
WiredHome | 3:17928786bdb5 | 722 | *(eoRec-1) = '\0'; |
WiredHome | 44:71f09e4255f4 | 723 | INFO("method: %s", soRec); |
WiredHome | 44:71f09e4255f4 | 724 | #if 1 |
WiredHome | 44:71f09e4255f4 | 725 | const QueryMethod * qm = QueryMethodList; |
WiredHome | 44:71f09e4255f4 | 726 | while (*qm->queryType) { |
WiredHome | 44:71f09e4255f4 | 727 | if (strstr(soRec, qm->queryType) == soRec) { |
WiredHome | 44:71f09e4255f4 | 728 | Extract(soRec, qm->queryType, &queryString); |
WiredHome | 44:71f09e4255f4 | 729 | if (queryString) { |
WiredHome | 44:71f09e4255f4 | 730 | queryType = (char *)mymalloc(strlen(qm->queryType)+1); |
WiredHome | 44:71f09e4255f4 | 731 | strcpy(queryType, qm->queryType); |
WiredHome | 44:71f09e4255f4 | 732 | } |
WiredHome | 44:71f09e4255f4 | 733 | } |
WiredHome | 44:71f09e4255f4 | 734 | qm++; |
WiredHome | 44:71f09e4255f4 | 735 | } |
WiredHome | 44:71f09e4255f4 | 736 | #else |
WiredHome | 8:262583f054f6 | 737 | // Inspect the supported query types (GET, POST) and ignore (HEAD, PUT, OPTION, DELETE, TRACE, CONNECT] |
WiredHome | 44:71f09e4255f4 | 738 | // This is presently very clumsy |
WiredHome | 44:71f09e4255f4 | 739 | if (strstr(soRec, "GET ") == soRec) { |
WiredHome | 8:262583f054f6 | 740 | Extract(soRec, "GET", &queryString); |
WiredHome | 8:262583f054f6 | 741 | if (queryString) { |
WiredHome | 8:262583f054f6 | 742 | queryType = (char *)mymalloc(strlen("GET")+1); |
WiredHome | 8:262583f054f6 | 743 | strcpy(queryType, "GET"); |
WiredHome | 8:262583f054f6 | 744 | } |
WiredHome | 8:262583f054f6 | 745 | } else if (strstr(soRec, "POST ") == soRec) { |
WiredHome | 39:0427544a5c08 | 746 | Extract(soRec, "POST", &queryString); |
WiredHome | 8:262583f054f6 | 747 | if (queryString) { |
WiredHome | 8:262583f054f6 | 748 | queryType = (char *)mymalloc(strlen("POST")+1); |
WiredHome | 8:262583f054f6 | 749 | strcpy(queryType, "POST"); |
WiredHome | 8:262583f054f6 | 750 | } |
WiredHome | 10:9c8d2c6a3469 | 751 | } |
WiredHome | 44:71f09e4255f4 | 752 | #endif |
WiredHome | 44:71f09e4255f4 | 753 | |
WiredHome | 13:8975d7928678 | 754 | // if there is a ": " delimiter, we have a header item to parse into name,value pair |
WiredHome | 13:8975d7928678 | 755 | // "Connection: keep-alive" becomes "Connection" "keep-alive" |
WiredHome | 13:8975d7928678 | 756 | char *delim = strstr(soRec, ": "); |
WiredHome | 13:8975d7928678 | 757 | char *chkSpace = strchr(soRec, ' '); // a field-name has no space ahead of the ":" |
WiredHome | 44:71f09e4255f4 | 758 | //INFO("hpc:%d,mhp:%d, {%s}", headerParamCount, maxheaderParams, soRec); |
WiredHome | 29:00116fc9da74 | 759 | if (delim |
WiredHome | 29:00116fc9da74 | 760 | && (!chkSpace || (chkSpace && delim < chkSpace)) |
WiredHome | 29:00116fc9da74 | 761 | && headerParamCount < maxheaderParams) { |
WiredHome | 14:19c5f6151319 | 762 | *delim++ = '\0'; // replace ": " with null |
WiredHome | 13:8975d7928678 | 763 | *delim++ = '\0'; |
WiredHome | 13:8975d7928678 | 764 | headerParams[headerParamCount].name = soRec; |
WiredHome | 13:8975d7928678 | 765 | headerParams[headerParamCount].value = delim; |
WiredHome | 37:0cb2774e2410 | 766 | INFO("%d: headerParams[%s] = {%s}", headerParamCount, |
WiredHome | 37:0cb2774e2410 | 767 | headerParams[headerParamCount].name, headerParams[headerParamCount].value); |
WiredHome | 13:8975d7928678 | 768 | headerParamCount++; |
WiredHome | 13:8975d7928678 | 769 | } |
WiredHome | 3:17928786bdb5 | 770 | soRec = eoRec + 1; |
WiredHome | 3:17928786bdb5 | 771 | eoRec = strchr(soRec, '\n'); |
WiredHome | 44:71f09e4255f4 | 772 | if (soRec > dblCR) // Just walked past the end of the header |
WiredHome | 44:71f09e4255f4 | 773 | break; |
WiredHome | 3:17928786bdb5 | 774 | } |
WiredHome | 29:00116fc9da74 | 775 | |
WiredHome | 3:17928786bdb5 | 776 | if (queryString) { |
WiredHome | 3:17928786bdb5 | 777 | // We have enough to try to reply |
WiredHome | 37:0cb2774e2410 | 778 | INFO("create reply queryType{%s}, queryString{%s}", queryType, queryString); |
WiredHome | 13:8975d7928678 | 779 | // parse queryParams - if any |
WiredHome | 3:17928786bdb5 | 780 | // /file.htm?name1=value1&name2=value2... |
WiredHome | 3:17928786bdb5 | 781 | // /file.htm?name1&name2=value2... |
WiredHome | 13:8975d7928678 | 782 | queryParamCount = 0; |
WiredHome | 3:17928786bdb5 | 783 | char * paramDelim = strchr(queryString, '?'); |
WiredHome | 3:17928786bdb5 | 784 | if (paramDelim) { |
WiredHome | 3:17928786bdb5 | 785 | *paramDelim++ = '\0'; |
WiredHome | 3:17928786bdb5 | 786 | UnescapeString(paramDelim); // everything after the '?' |
WiredHome | 39:0427544a5c08 | 787 | ParseParameters(queryParams, &queryParamCount, maxqueryParams, paramDelim); // pointing past the NULL, and there are queryParams here |
WiredHome | 3:17928786bdb5 | 788 | } |
WiredHome | 3:17928786bdb5 | 789 | } else { |
WiredHome | 29:00116fc9da74 | 790 | ERR("queryString not found in (%s) [this should never happen]", soRec); |
WiredHome | 3:17928786bdb5 | 791 | } |
WiredHome | 44:71f09e4255f4 | 792 | advanceState = ACCEPT_COMPLETE; // Should be ACCEPT_CONTINUE and the stuff below moves out of here |
WiredHome | 3:17928786bdb5 | 793 | buffer[0] = 0; |
WiredHome | 3:17928786bdb5 | 794 | |
WiredHome | 3:17928786bdb5 | 795 | // This part parses the extra data on a POST method. |
WiredHome | 3:17928786bdb5 | 796 | // Since there has to be a dynamic handler registered for this |
WiredHome | 3:17928786bdb5 | 797 | // it would make sense to move some of this responsibility to |
WiredHome | 3:17928786bdb5 | 798 | // that handler. It could then choose if it wanted to allocate |
WiredHome | 3:17928786bdb5 | 799 | // the requested 'Content-Length' amount of memory. |
WiredHome | 13:8975d7928678 | 800 | int postBytes = atoi(GetHeaderValue("Content-Length")); |
WiredHome | 28:f93ef41b78e1 | 801 | CallBackResults acceptIt = ACCEPT_ERROR; |
WiredHome | 44:71f09e4255f4 | 802 | INFO("Content-Length: %d", postBytes); |
WiredHome | 44:71f09e4255f4 | 803 | if (strcmp(queryType, "POST ") == 0 ) { |
WiredHome | 44:71f09e4255f4 | 804 | INFO("parse POST data %d bytes", postBytes); // We might have no idea how much data is coming... |
WiredHome | 44:71f09e4255f4 | 805 | int ndxHandler = 0; |
WiredHome | 44:71f09e4255f4 | 806 | bool regHandled = false; |
WiredHome | 44:71f09e4255f4 | 807 | // Registered Dynamic Handler |
WiredHome | 44:71f09e4255f4 | 808 | // Callback and ask if they want to accept this data |
WiredHome | 44:71f09e4255f4 | 809 | for (ndxHandler=0; ndxHandler<handlercount; ndxHandler++) { |
WiredHome | 44:71f09e4255f4 | 810 | INFO("is '%s' a handler for '%s' ?", handlers[ndxHandler].path, queryString); |
WiredHome | 44:71f09e4255f4 | 811 | if (strcmp(handlers[ndxHandler].path, queryString) == 0) { |
WiredHome | 44:71f09e4255f4 | 812 | acceptIt = (*handlers[ndxHandler].callback)(this, CONTENT_LENGTH_REQUEST, queryString, queryParams, queryParamCount); |
WiredHome | 44:71f09e4255f4 | 813 | regHandled = true; |
WiredHome | 44:71f09e4255f4 | 814 | break; // only one callback per path allowed |
WiredHome | 3:17928786bdb5 | 815 | } |
WiredHome | 44:71f09e4255f4 | 816 | } |
WiredHome | 44:71f09e4255f4 | 817 | INFO("reghandled: %d, acceptIt: %d", regHandled, acceptIt); |
WiredHome | 44:71f09e4255f4 | 818 | if (regHandled && acceptIt != ACCEPT_ERROR) { |
WiredHome | 44:71f09e4255f4 | 819 | // @todo need to refactor - if the thing is bigger than the buffer, |
WiredHome | 44:71f09e4255f4 | 820 | // then we can receive it a chunk at a time, and hand off |
WiredHome | 44:71f09e4255f4 | 821 | // the chunks to the callback. May need callbacks that |
WiredHome | 44:71f09e4255f4 | 822 | // are: DATA_TRANSFER: self-detect to extract the filename/object name, |
WiredHome | 44:71f09e4255f4 | 823 | // DATA_TRANSFER: subsequent chunk of data, |
WiredHome | 44:71f09e4255f4 | 824 | // DATA_TRANSFER_END: signals that last chunk is enclosed. |
WiredHome | 44:71f09e4255f4 | 825 | // |
WiredHome | 44:71f09e4255f4 | 826 | // If so, we'll make space for it |
WiredHome | 44:71f09e4255f4 | 827 | postQueryString = (char *)mymalloc(CHUNK_SIZE); |
WiredHome | 44:71f09e4255f4 | 828 | //INFO("Free space %d", Free()); |
WiredHome | 44:71f09e4255f4 | 829 | INFO("postQueryString %p", postQueryString); |
WiredHome | 44:71f09e4255f4 | 830 | if (postQueryString) { |
WiredHome | 44:71f09e4255f4 | 831 | int len = 0; |
WiredHome | 44:71f09e4255f4 | 832 | int ttlCount; |
WiredHome | 44:71f09e4255f4 | 833 | Timer escapePlan; |
WiredHome | 44:71f09e4255f4 | 834 | bool escape = false; |
WiredHome | 44:71f09e4255f4 | 835 | |
WiredHome | 44:71f09e4255f4 | 836 | INFO("Processing tail..."); |
WiredHome | 44:71f09e4255f4 | 837 | escapePlan.start(); |
WiredHome | 44:71f09e4255f4 | 838 | dblCR += 4; // There may be some after the double CR that we need |
WiredHome | 44:71f09e4255f4 | 839 | ttlCount = strlen(dblCR); |
WiredHome | 44:71f09e4255f4 | 840 | strcpy(postQueryString, dblCR); |
WiredHome | 44:71f09e4255f4 | 841 | //INFO(" {%s}", postQueryString); |
WiredHome | 44:71f09e4255f4 | 842 | while ((!postBytes || ttlCount < postBytes) && !escape) { |
WiredHome | 44:71f09e4255f4 | 843 | INFO("ttlCount: %d < postBytes: %d, of max chunk alloc %d", ttlCount, postBytes, CHUNK_SIZE); |
WiredHome | 44:71f09e4255f4 | 844 | len = client.receive(postQueryString + ttlCount, CHUNK_SIZE - ttlCount); |
WiredHome | 44:71f09e4255f4 | 845 | if (len > 0) { |
WiredHome | 44:71f09e4255f4 | 846 | ttlCount += len; |
WiredHome | 44:71f09e4255f4 | 847 | postQueryString[ttlCount] = '\0'; // Whether binary or ASCII, this is ok as it's after the data |
WiredHome | 44:71f09e4255f4 | 848 | INFO(" postBytes %d: [%s], [%d]", postBytes, postQueryString, ndxHandler); |
WiredHome | 44:71f09e4255f4 | 849 | escapePlan.reset(); |
WiredHome | 44:71f09e4255f4 | 850 | } else if (len < 0) { |
WiredHome | 44:71f09e4255f4 | 851 | INFO("*** connection closed ***"); |
WiredHome | 44:71f09e4255f4 | 852 | break; // no more data, before the plan |
WiredHome | 44:71f09e4255f4 | 853 | } else { // n == 0 |
WiredHome | 44:71f09e4255f4 | 854 | ; |
WiredHome | 3:17928786bdb5 | 855 | } |
WiredHome | 44:71f09e4255f4 | 856 | if (escapePlan.read_ms() > HANG_TIMEOUT_MS) { // if no Content-Length, we wait... |
WiredHome | 44:71f09e4255f4 | 857 | escape = true; |
WiredHome | 44:71f09e4255f4 | 858 | WARN("Escape plan activated."); |
WiredHome | 44:71f09e4255f4 | 859 | } |
WiredHome | 44:71f09e4255f4 | 860 | if (postBytes > 0 && ttlCount >= postBytes) |
WiredHome | 44:71f09e4255f4 | 861 | break; |
WiredHome | 3:17928786bdb5 | 862 | } |
WiredHome | 44:71f09e4255f4 | 863 | //postParamCount = 0; |
WiredHome | 44:71f09e4255f4 | 864 | //INFO("post: %s", postQueryString); |
WiredHome | 44:71f09e4255f4 | 865 | //We're after the header, so there is "body" stuff which could be anything... |
WiredHome | 44:71f09e4255f4 | 866 | //but probably html or xml stuff... |
WiredHome | 44:71f09e4255f4 | 867 | //ParseParameters(postParams, &postParamCount, maxPostParams, postQueryString); |
WiredHome | 44:71f09e4255f4 | 868 | acceptIt = (*handlers[ndxHandler].callback)(this, DATA_TRANSFER, postQueryString, NULL, ttlCount); |
WiredHome | 44:71f09e4255f4 | 869 | INFO("..processing exit"); |
WiredHome | 44:71f09e4255f4 | 870 | acceptIt = (*handlers[ndxHandler].callback)(this, DATA_TRANSFER_END, NULL, NULL, 0); |
WiredHome | 3:17928786bdb5 | 871 | } else { |
WiredHome | 44:71f09e4255f4 | 872 | ERR("attempt to allocate %d failed.", CHUNK_SIZE); |
WiredHome | 44:71f09e4255f4 | 873 | } |
WiredHome | 44:71f09e4255f4 | 874 | } else { |
WiredHome | 44:71f09e4255f4 | 875 | // Simply copy it to the bitbucket |
WiredHome | 44:71f09e4255f4 | 876 | WARN("No handler, so to the bit bucket it goes ..."); |
WiredHome | 44:71f09e4255f4 | 877 | int bytesToDump = postBytes; |
WiredHome | 44:71f09e4255f4 | 878 | char * bitbucket = (char *)mymalloc(201); |
WiredHome | 44:71f09e4255f4 | 879 | |
WiredHome | 44:71f09e4255f4 | 880 | dblCR += 4; |
WiredHome | 44:71f09e4255f4 | 881 | while (*dblCR && *dblCR <= ' ') |
WiredHome | 44:71f09e4255f4 | 882 | dblCR++; |
WiredHome | 44:71f09e4255f4 | 883 | bytesToDump -= strlen(dblCR); |
WiredHome | 44:71f09e4255f4 | 884 | while (bytesToDump > 0) { |
WiredHome | 44:71f09e4255f4 | 885 | int n = (bytesToDump > 200) ? 200 : bytesToDump; |
WiredHome | 44:71f09e4255f4 | 886 | n = client.receive(bitbucket, n); |
WiredHome | 44:71f09e4255f4 | 887 | if (n < 0) { |
WiredHome | 44:71f09e4255f4 | 888 | ERR("to the bitbucket."); |
WiredHome | 44:71f09e4255f4 | 889 | break; |
WiredHome | 3:17928786bdb5 | 890 | } |
WiredHome | 44:71f09e4255f4 | 891 | bytesToDump -= n; |
WiredHome | 3:17928786bdb5 | 892 | } |
WiredHome | 44:71f09e4255f4 | 893 | myfree(bitbucket); |
WiredHome | 3:17928786bdb5 | 894 | } |
WiredHome | 3:17928786bdb5 | 895 | } |
WiredHome | 3:17928786bdb5 | 896 | } |
WiredHome | 3:17928786bdb5 | 897 | return advanceState; |
WiredHome | 3:17928786bdb5 | 898 | } |
WiredHome | 3:17928786bdb5 | 899 | |
WiredHome | 14:19c5f6151319 | 900 | |
WiredHome | 27:90a1f5a5392f | 901 | |
WiredHome | 13:8975d7928678 | 902 | const char * HTTPServer::GetHeaderValue(const char * hdr) |
WiredHome | 13:8975d7928678 | 903 | { |
WiredHome | 13:8975d7928678 | 904 | int i; |
WiredHome | 29:00116fc9da74 | 905 | |
WiredHome | 29:00116fc9da74 | 906 | for (i=0; i<headerParamCount; i++) { |
WiredHome | 13:8975d7928678 | 907 | if (strcmp(hdr, headerParams[i].name) == 0) |
WiredHome | 13:8975d7928678 | 908 | return headerParams[i].value; |
WiredHome | 29:00116fc9da74 | 909 | } |
WiredHome | 13:8975d7928678 | 910 | return NULL; |
WiredHome | 13:8975d7928678 | 911 | } |
WiredHome | 13:8975d7928678 | 912 | |
WiredHome | 12:109bf1558300 | 913 | |
WiredHome | 7:99ad7a67f05e | 914 | void HTTPServer::GetPerformanceData(SW_PerformanceData * p) |
WiredHome | 7:99ad7a67f05e | 915 | { |
WiredHome | 3:17928786bdb5 | 916 | memcpy(p, &perfData, sizeof(perfData)); |
WiredHome | 3:17928786bdb5 | 917 | } |
WiredHome | 3:17928786bdb5 | 918 | |
WiredHome | 17:69ff00ce39f4 | 919 | unsigned int HTTPServer::GetPerformanceClock() |
WiredHome | 17:69ff00ce39f4 | 920 | { |
WiredHome | 17:69ff00ce39f4 | 921 | return (unsigned int)PerformanceTimer.read_us(); |
WiredHome | 17:69ff00ce39f4 | 922 | } |
WiredHome | 14:19c5f6151319 | 923 | |
WiredHome | 16:6ebacf2946d8 | 924 | unsigned int HTTPServer::RecordPerformanceData(SW_PerformanceParam * param, unsigned int refTime) |
WiredHome | 7:99ad7a67f05e | 925 | { |
WiredHome | 16:6ebacf2946d8 | 926 | unsigned int t_now = (unsigned int)PerformanceTimer.read_us(); |
WiredHome | 3:17928786bdb5 | 927 | param->TotalTime_us += (t_now - refTime); |
WiredHome | 3:17928786bdb5 | 928 | param->Samples++; |
WiredHome | 3:17928786bdb5 | 929 | if ((t_now - refTime) > param->MaxTime_us) |
WiredHome | 3:17928786bdb5 | 930 | param->MaxTime_us = (t_now - refTime); |
WiredHome | 3:17928786bdb5 | 931 | return t_now; |
WiredHome | 3:17928786bdb5 | 932 | } |
WiredHome | 3:17928786bdb5 | 933 | |
WiredHome | 14:19c5f6151319 | 934 | |
WiredHome | 7:99ad7a67f05e | 935 | void HTTPServer::ResetPerformanceData() |
WiredHome | 7:99ad7a67f05e | 936 | { |
WiredHome | 3:17928786bdb5 | 937 | memset(&perfData, 0, sizeof(perfData)); |
WiredHome | 3:17928786bdb5 | 938 | } |
WiredHome | 3:17928786bdb5 | 939 |