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@2:a29c32190037, 2013-06-02 (annotated)
- Committer:
- WiredHome
- Date:
- Sun Jun 02 18:32:05 2013 +0000
- Revision:
- 2:a29c32190037
- Parent:
- 0:729320f63c5c
- Child:
- 3:17928786bdb5
turned off debug
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 | 0:729320f63c5c | 17 | //#define DEBUG |
WiredHome | 0:729320f63c5c | 18 | |
WiredHome | 0:729320f63c5c | 19 | #define FILESEND_BUF_SIZE 1200 // should keep this <= the ethernet frame size |
WiredHome | 0:729320f63c5c | 20 | |
WiredHome | 0:729320f63c5c | 21 | const char * DEFAULT_FILENAME = "index.htm"; |
WiredHome | 0:729320f63c5c | 22 | |
WiredHome | 0:729320f63c5c | 23 | // Header information to always send |
WiredHome | 0:729320f63c5c | 24 | const char hdr_httpver[] = "HTTP/1.1"; // typically HTTP/1.0 or HTTP/1.1 |
WiredHome | 0:729320f63c5c | 25 | const char hdr_age[] = "Max-age: 0\r\n"; // expires right away (must be \r\n terminated) |
WiredHome | 0:729320f63c5c | 26 | const char hdr_server[] = "Server: Smart_Server v0.1\r\n"; // Server (must be \r\n terminated) |
WiredHome | 2:a29c32190037 | 27 | const char hdr_dnt[] = "DNT: 1\r\n"; // Do Not Track |
WiredHome | 0:729320f63c5c | 28 | const char hdr_close[] = "Connection: close\r\n"; // tell the client to close the connection (must be \r\n terminated) |
WiredHome | 0:729320f63c5c | 29 | const char nl[] = "\r\n"; // final \r\n for the termination of the header |
WiredHome | 0:729320f63c5c | 30 | |
WiredHome | 0:729320f63c5c | 31 | static const struct { |
WiredHome | 0:729320f63c5c | 32 | char *ext; |
WiredHome | 0:729320f63c5c | 33 | char *filetype; |
WiredHome | 0:729320f63c5c | 34 | } extensions [] = { |
WiredHome | 0:729320f63c5c | 35 | {".gif", "Content-Type: image/gif\r\n" }, |
WiredHome | 0:729320f63c5c | 36 | {".jpg", "Content-Type: image/jpeg\r\n" }, |
WiredHome | 0:729320f63c5c | 37 | {".jpeg","Content-Type: image/jpeg\r\n" }, |
WiredHome | 0:729320f63c5c | 38 | {".ico", "Content-Type: image/x-icon\r\n"}, |
WiredHome | 0:729320f63c5c | 39 | {".png", "Content-Type: image/png\r\n" }, |
WiredHome | 0:729320f63c5c | 40 | {".zip", "Content-Type: image/zip\r\n" }, |
WiredHome | 0:729320f63c5c | 41 | {".gz", "Content-Type: image/gz\r\n" }, |
WiredHome | 0:729320f63c5c | 42 | {".tar", "Content-Type: image/tar\r\n" }, |
WiredHome | 2:a29c32190037 | 43 | {".txt", "Content-Type: plain/text\r\n" }, |
WiredHome | 2:a29c32190037 | 44 | {".pdf", "Content-Type: application/pdf\r\n" }, |
WiredHome | 0:729320f63c5c | 45 | {".htm", "Content-Type: text/html\r\n" }, |
WiredHome | 0:729320f63c5c | 46 | {".html","Content-Type: text/html\r\n" }, |
WiredHome | 0:729320f63c5c | 47 | {0,0} |
WiredHome | 0:729320f63c5c | 48 | }; |
WiredHome | 0:729320f63c5c | 49 | |
WiredHome | 0:729320f63c5c | 50 | HTTPServer::HTTPServer(Wifly * _wf, int port, const char * _webroot, int _maxparams, int _maxdynamicpages, PC * _pc) |
WiredHome | 0:729320f63c5c | 51 | { |
WiredHome | 0:729320f63c5c | 52 | wifly = _wf; |
WiredHome | 0:729320f63c5c | 53 | webroot = (char *)malloc(strlen(_webroot)+1); |
WiredHome | 0:729320f63c5c | 54 | strcpy(webroot, _webroot); |
WiredHome | 0:729320f63c5c | 55 | maxparams = _maxparams; |
WiredHome | 0:729320f63c5c | 56 | maxdynamicpages = _maxdynamicpages; |
WiredHome | 0:729320f63c5c | 57 | params = (namevalue *)malloc(maxparams * sizeof(namevalue)); |
WiredHome | 0:729320f63c5c | 58 | handlers = (handler *)malloc(maxdynamicpages * sizeof(handler)); |
WiredHome | 0:729320f63c5c | 59 | pc = _pc; |
WiredHome | 0:729320f63c5c | 60 | paramcount = 0; |
WiredHome | 0:729320f63c5c | 61 | handlercount = 0; |
WiredHome | 0:729320f63c5c | 62 | server = new TCPSocketServer(); |
WiredHome | 0:729320f63c5c | 63 | timer = new Timer(); |
WiredHome | 0:729320f63c5c | 64 | timer->start(); |
WiredHome | 0:729320f63c5c | 65 | server->bind(port); |
WiredHome | 0:729320f63c5c | 66 | server->listen(); |
WiredHome | 0:729320f63c5c | 67 | server->set_blocking(false); |
WiredHome | 0:729320f63c5c | 68 | server->accept(client); |
WiredHome | 0:729320f63c5c | 69 | } |
WiredHome | 0:729320f63c5c | 70 | |
WiredHome | 0:729320f63c5c | 71 | HTTPServer::~HTTPServer() |
WiredHome | 0:729320f63c5c | 72 | { |
WiredHome | 0:729320f63c5c | 73 | free(webroot); |
WiredHome | 0:729320f63c5c | 74 | webroot = NULL; |
WiredHome | 0:729320f63c5c | 75 | } |
WiredHome | 0:729320f63c5c | 76 | |
WiredHome | 0:729320f63c5c | 77 | bool HTTPServer::RegisterHandler(const char * path, Handler callback) |
WiredHome | 0:729320f63c5c | 78 | { |
WiredHome | 0:729320f63c5c | 79 | if (handlercount < maxdynamicpages && path && callback) { |
WiredHome | 0:729320f63c5c | 80 | handlers[handlercount].path = (char *)malloc(strlen(path)+1); |
WiredHome | 0:729320f63c5c | 81 | memcpy(handlers[handlercount].path, path, strlen(path)+1); |
WiredHome | 0:729320f63c5c | 82 | handlers[handlercount].callback = callback; |
WiredHome | 0:729320f63c5c | 83 | handlercount++; |
WiredHome | 0:729320f63c5c | 84 | return true; |
WiredHome | 0:729320f63c5c | 85 | } else { |
WiredHome | 0:729320f63c5c | 86 | return false; |
WiredHome | 0:729320f63c5c | 87 | } |
WiredHome | 0:729320f63c5c | 88 | } |
WiredHome | 0:729320f63c5c | 89 | |
WiredHome | 2:a29c32190037 | 90 | // Poll() |
WiredHome | 0:729320f63c5c | 91 | // |
WiredHome | 0:729320f63c5c | 92 | // *OPEN*GET /x=1 HTTP/1.1 |
WiredHome | 0:729320f63c5c | 93 | // Host: 192.168.1.140 |
WiredHome | 0:729320f63c5c | 94 | // Connection: keep-alive |
WiredHome | 0:729320f63c5c | 95 | // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 |
WiredHome | 0:729320f63c5c | 96 | // 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 | 97 | // Accept-Encoding: gzip,deflate,sdch |
WiredHome | 0:729320f63c5c | 98 | // Accept-Language: en-US,en;q=0.8 |
WiredHome | 0:729320f63c5c | 99 | // |
WiredHome | 2:a29c32190037 | 100 | void HTTPServer::Poll() |
WiredHome | 0:729320f63c5c | 101 | { |
WiredHome | 2:a29c32190037 | 102 | #define MAXRECSIZE 4000 |
WiredHome | 0:729320f63c5c | 103 | static char buffer[MAXRECSIZE]; |
WiredHome | 0:729320f63c5c | 104 | static char * bPtr = buffer; |
WiredHome | 0:729320f63c5c | 105 | |
WiredHome | 0:729320f63c5c | 106 | static char * queryType = NULL; |
WiredHome | 0:729320f63c5c | 107 | static char * queryString = NULL; |
WiredHome | 0:729320f63c5c | 108 | static char * hostString = NULL; |
WiredHome | 0:729320f63c5c | 109 | static char * contentLength = NULL; |
WiredHome | 0:729320f63c5c | 110 | static char * contentType = NULL; |
WiredHome | 0:729320f63c5c | 111 | static char * postQueryString = NULL; |
WiredHome | 0:729320f63c5c | 112 | static Timer tmr; |
WiredHome | 0:729320f63c5c | 113 | typedef enum { Idle, Receiving, Reply , Waiting, Sending, WaitingToClose } state; |
WiredHome | 0:729320f63c5c | 114 | static state op = Idle; |
WiredHome | 0:729320f63c5c | 115 | int n; |
WiredHome | 0:729320f63c5c | 116 | |
WiredHome | 0:729320f63c5c | 117 | switch(op) { |
WiredHome | 0:729320f63c5c | 118 | case Reply: |
WiredHome | 0:729320f63c5c | 119 | tmr.reset(); |
WiredHome | 0:729320f63c5c | 120 | tmr.start(); |
WiredHome | 0:729320f63c5c | 121 | op = Waiting; |
WiredHome | 0:729320f63c5c | 122 | break; |
WiredHome | 0:729320f63c5c | 123 | case Waiting: |
WiredHome | 0:729320f63c5c | 124 | if (tmr.read_ms() > 10) { |
WiredHome | 0:729320f63c5c | 125 | //pc->printf("%06d delay expired, now send.\r\n", timer->read_ms()); |
WiredHome | 0:729320f63c5c | 126 | op = Sending; |
WiredHome | 0:729320f63c5c | 127 | } |
WiredHome | 0:729320f63c5c | 128 | break; |
WiredHome | 0:729320f63c5c | 129 | case Sending: |
WiredHome | 0:729320f63c5c | 130 | if (strcmp(queryType, "GET") == 0 |
WiredHome | 0:729320f63c5c | 131 | || strcmp(queryType, "POST") == 0) { |
WiredHome | 0:729320f63c5c | 132 | if (!(queryString[0] == '.' && queryString[1] == '.')) { |
WiredHome | 0:729320f63c5c | 133 | const char * fType; |
WiredHome | 0:729320f63c5c | 134 | bool regHandled = false; |
WiredHome | 0:729320f63c5c | 135 | |
WiredHome | 0:729320f63c5c | 136 | // Registered Dynamic Handler |
WiredHome | 0:729320f63c5c | 137 | // If this queryString is in the list of registered handlers, call that |
WiredHome | 0:729320f63c5c | 138 | for (int i=0; i<handlercount; i++) { |
WiredHome | 0:729320f63c5c | 139 | if (strcmp(handlers[i].path, queryString) == 0) { |
WiredHome | 2:a29c32190037 | 140 | (*handlers[i].callback)(this, SEND_PAGE, queryString, params, paramcount); |
WiredHome | 0:729320f63c5c | 141 | regHandled = true; |
WiredHome | 0:729320f63c5c | 142 | break; // we only execute the first one |
WiredHome | 0:729320f63c5c | 143 | } |
WiredHome | 0:729320f63c5c | 144 | } |
WiredHome | 0:729320f63c5c | 145 | |
WiredHome | 0:729320f63c5c | 146 | if (!regHandled) { |
WiredHome | 0:729320f63c5c | 147 | // Otherwise, this queryString must be trying to reference a static file |
WiredHome | 0:729320f63c5c | 148 | if (queryString[strlen(queryString)-1] == '/') { |
WiredHome | 0:729320f63c5c | 149 | queryString = rewriteWithDefaultFile(queryString); |
WiredHome | 0:729320f63c5c | 150 | } |
WiredHome | 0:729320f63c5c | 151 | // see if we support this file type |
WiredHome | 0:729320f63c5c | 152 | fType = GetSupportedType(queryString); |
WiredHome | 0:729320f63c5c | 153 | if (fType) { |
WiredHome | 0:729320f63c5c | 154 | queryString = rewritePrependWebroot(queryString); |
WiredHome | 0:729320f63c5c | 155 | SendFile(queryString, fType); |
WiredHome | 0:729320f63c5c | 156 | } else { |
WiredHome | 0:729320f63c5c | 157 | //pc->printf("Unsupported file type %s\r\n", queryString); |
WiredHome | 0:729320f63c5c | 158 | header(404, "Not Found", "Pragma: err - Unsupported type\r\n"); |
WiredHome | 0:729320f63c5c | 159 | } |
WiredHome | 0:729320f63c5c | 160 | } |
WiredHome | 0:729320f63c5c | 161 | } else { |
WiredHome | 0:729320f63c5c | 162 | //pc->printf("Unsupported path %s\r\n", queryString); |
WiredHome | 0:729320f63c5c | 163 | header(400, "Bad Request", "Pragma: err - Unsupported path\r\n"); |
WiredHome | 0:729320f63c5c | 164 | } |
WiredHome | 0:729320f63c5c | 165 | } else { |
WiredHome | 0:729320f63c5c | 166 | //pc->printf("Unsupported query type %s\r\n", queryType); |
WiredHome | 0:729320f63c5c | 167 | header(400, "Bad Request", "Pragma: err - Unsupported query type\r\n"); |
WiredHome | 0:729320f63c5c | 168 | } |
WiredHome | 0:729320f63c5c | 169 | tmr.reset(); |
WiredHome | 0:729320f63c5c | 170 | if (queryType) { |
WiredHome | 0:729320f63c5c | 171 | free(queryType); |
WiredHome | 0:729320f63c5c | 172 | queryType = NULL; |
WiredHome | 0:729320f63c5c | 173 | } |
WiredHome | 0:729320f63c5c | 174 | if (queryString) { |
WiredHome | 0:729320f63c5c | 175 | free(queryString); |
WiredHome | 0:729320f63c5c | 176 | queryString = NULL; |
WiredHome | 0:729320f63c5c | 177 | } |
WiredHome | 0:729320f63c5c | 178 | if (hostString) { |
WiredHome | 0:729320f63c5c | 179 | free(hostString); |
WiredHome | 0:729320f63c5c | 180 | hostString = NULL; |
WiredHome | 0:729320f63c5c | 181 | } |
WiredHome | 0:729320f63c5c | 182 | if (contentLength) { |
WiredHome | 0:729320f63c5c | 183 | free(contentLength); |
WiredHome | 0:729320f63c5c | 184 | contentLength = NULL; |
WiredHome | 0:729320f63c5c | 185 | } |
WiredHome | 0:729320f63c5c | 186 | if (contentType) { |
WiredHome | 0:729320f63c5c | 187 | free(contentType); |
WiredHome | 0:729320f63c5c | 188 | contentType = NULL; |
WiredHome | 0:729320f63c5c | 189 | } |
WiredHome | 0:729320f63c5c | 190 | if (postQueryString) { |
WiredHome | 0:729320f63c5c | 191 | free(postQueryString); |
WiredHome | 0:729320f63c5c | 192 | postQueryString = NULL; |
WiredHome | 0:729320f63c5c | 193 | } |
WiredHome | 0:729320f63c5c | 194 | op = WaitingToClose; |
WiredHome | 0:729320f63c5c | 195 | break; |
WiredHome | 0:729320f63c5c | 196 | case WaitingToClose: |
WiredHome | 0:729320f63c5c | 197 | if (tmr.read_ms() > 10) { |
WiredHome | 0:729320f63c5c | 198 | //pc->printf("closing after %d\r\n", tmr.read_ms()); |
WiredHome | 0:729320f63c5c | 199 | close_connection(); |
WiredHome | 0:729320f63c5c | 200 | op = Idle; |
WiredHome | 0:729320f63c5c | 201 | } |
WiredHome | 0:729320f63c5c | 202 | break; |
WiredHome | 0:729320f63c5c | 203 | case Idle: |
WiredHome | 0:729320f63c5c | 204 | //if (server->accept(client) == 0) |
WiredHome | 0:729320f63c5c | 205 | // op = Receiving; |
WiredHome | 0:729320f63c5c | 206 | //break; |
WiredHome | 0:729320f63c5c | 207 | // Idle and Receiving are the same until I figure out the accept method |
WiredHome | 0:729320f63c5c | 208 | // so it doesn't eat a few chars after the *OPEN* |
WiredHome | 0:729320f63c5c | 209 | case Receiving: |
WiredHome | 0:729320f63c5c | 210 | n = client.receive(bPtr, sizeof(buffer) - (bPtr - buffer)); |
WiredHome | 0:729320f63c5c | 211 | if (n < 0) { |
WiredHome | 0:729320f63c5c | 212 | pc->printf("*** client.receive error: %d\r\n", n); |
WiredHome | 0:729320f63c5c | 213 | } else if (n) { |
WiredHome | 0:729320f63c5c | 214 | char * dblCR; |
WiredHome | 0:729320f63c5c | 215 | bPtr[n] = '\0'; |
WiredHome | 0:729320f63c5c | 216 | wifly->setConnectionState(true); // Bad hack to have to do this here.... |
WiredHome | 0:729320f63c5c | 217 | //pc->printf("%s", bPtr); |
WiredHome | 0:729320f63c5c | 218 | // Buffer could have partial, but the double \r\n is the key |
WiredHome | 0:729320f63c5c | 219 | // *OPEN*QueryType QueryString HTTP/1.1.... |
WiredHome | 0:729320f63c5c | 220 | // QueryType:= GET |
WiredHome | 0:729320f63c5c | 221 | // *OPEN*GET /QueryString HTTP/1.1\r\n |
WiredHome | 0:729320f63c5c | 222 | // *OPEN*GET /QueryString HTTP/1.1\r\nHeader stuf |
WiredHome | 0:729320f63c5c | 223 | // *OPEN*GET /QueryString HTTP/1.1\r\nHeader stuff...\r\n\r\n |
WiredHome | 0:729320f63c5c | 224 | dblCR = strstr(buffer,"\r\n\r\n"); |
WiredHome | 0:729320f63c5c | 225 | if (dblCR) { // Have to scan from the beginning in case split on \r |
WiredHome | 2:a29c32190037 | 226 | #ifdef DEBUG |
WiredHome | 2:a29c32190037 | 227 | pc->printf("\r\n\r\nThe Header:\r\n%s\r\n\r\n", buffer); |
WiredHome | 2:a29c32190037 | 228 | #endif |
WiredHome | 0:729320f63c5c | 229 | char * soRec = buffer; // start of the next record of text |
WiredHome | 0:729320f63c5c | 230 | char * eoRec = strchr(soRec, '\n'); // search for end of a record |
WiredHome | 0:729320f63c5c | 231 | while (eoRec) { |
WiredHome | 0:729320f63c5c | 232 | *eoRec = '\0'; |
WiredHome | 0:729320f63c5c | 233 | if (*(eoRec-1) == '\r') |
WiredHome | 0:729320f63c5c | 234 | *(eoRec-1) = '\0'; |
WiredHome | 0:729320f63c5c | 235 | if (!Extract(soRec, "*OPEN*", &queryType)) |
WiredHome | 0:729320f63c5c | 236 | Extract(soRec, "*CLOS*", &queryType); |
WiredHome | 0:729320f63c5c | 237 | if (queryType) |
WiredHome | 0:729320f63c5c | 238 | Extract(soRec, queryType, &queryString); |
WiredHome | 0:729320f63c5c | 239 | Extract(soRec, "Host: ", &hostString); |
WiredHome | 0:729320f63c5c | 240 | Extract(soRec, "Content-Length: ", &contentLength); |
WiredHome | 0:729320f63c5c | 241 | Extract(soRec, "Content-Type: ", &contentType); |
WiredHome | 0:729320f63c5c | 242 | soRec = eoRec + 1; |
WiredHome | 0:729320f63c5c | 243 | eoRec = strchr(soRec, '\n'); |
WiredHome | 0:729320f63c5c | 244 | } |
WiredHome | 0:729320f63c5c | 245 | if (queryString) { |
WiredHome | 0:729320f63c5c | 246 | // We have enough to try to reply |
WiredHome | 0:729320f63c5c | 247 | //pc->printf("create reply queryType{%s}, queryString{%s}\r\n", queryType, queryString); |
WiredHome | 0:729320f63c5c | 248 | // parse params - if any |
WiredHome | 0:729320f63c5c | 249 | // /file.htm?name1=value1&name2=value2... |
WiredHome | 0:729320f63c5c | 250 | // /file.htm?name1&name2=value2... |
WiredHome | 0:729320f63c5c | 251 | paramcount = 0; |
WiredHome | 0:729320f63c5c | 252 | char * paramDelim = strchr(queryString, '?'); |
WiredHome | 0:729320f63c5c | 253 | if (paramDelim) { |
WiredHome | 0:729320f63c5c | 254 | *paramDelim++ = '\0'; |
WiredHome | 0:729320f63c5c | 255 | UnescapeString(paramDelim); // everything after the '?' |
WiredHome | 0:729320f63c5c | 256 | ParseParameters(paramDelim); // pointing at the NULL, but there are params beyond |
WiredHome | 0:729320f63c5c | 257 | } |
WiredHome | 0:729320f63c5c | 258 | //for (int i=0; i<paramcount; i++) |
WiredHome | 0:729320f63c5c | 259 | // pc->printf("param %d '%s'='%s'\r\n", i, params[i].name, params[i].value); |
WiredHome | 0:729320f63c5c | 260 | } else { |
WiredHome | 0:729320f63c5c | 261 | pc->printf("not found\r\n"); |
WiredHome | 0:729320f63c5c | 262 | } |
WiredHome | 0:729320f63c5c | 263 | op = Reply; |
WiredHome | 0:729320f63c5c | 264 | buffer[0] = 0; |
WiredHome | 0:729320f63c5c | 265 | bPtr = buffer; |
WiredHome | 0:729320f63c5c | 266 | |
WiredHome | 0:729320f63c5c | 267 | // This part parses the extra data on a POST method. |
WiredHome | 0:729320f63c5c | 268 | // Since there has to be a dynamic handler registered for this |
WiredHome | 0:729320f63c5c | 269 | // it would make sense to move some of this responsibility to |
WiredHome | 0:729320f63c5c | 270 | // that handler. It could then choose if it wanted to allocate |
WiredHome | 0:729320f63c5c | 271 | // the requested 'Content-Length' amount of memory. |
WiredHome | 0:729320f63c5c | 272 | // Should we check the 'Content-Type' to see if it is |
WiredHome | 0:729320f63c5c | 273 | // 'application/x-www-form-urlencoded'? |
WiredHome | 0:729320f63c5c | 274 | int postBytes = atoi(contentLength); |
WiredHome | 2:a29c32190037 | 275 | bool acceptIt = false; |
WiredHome | 0:729320f63c5c | 276 | //pc->printf("Content-Length = %d\r\n", postBytes); |
WiredHome | 0:729320f63c5c | 277 | if (strcmp(queryType, "POST") == 0 && postBytes > 0 ) { |
WiredHome | 0:729320f63c5c | 278 | if (postBytes) { |
WiredHome | 2:a29c32190037 | 279 | bool regHandled = false; |
WiredHome | 2:a29c32190037 | 280 | // Registered Dynamic Handler |
WiredHome | 2:a29c32190037 | 281 | // Callback and ask if they want to accept this data |
WiredHome | 2:a29c32190037 | 282 | for (int i=0; i<handlercount; i++) { |
WiredHome | 2:a29c32190037 | 283 | if (strcmp(handlers[i].path, queryString) == 0) { |
WiredHome | 2:a29c32190037 | 284 | acceptIt = (*handlers[i].callback)(this, CONTENT_LENGTH_REQUEST, queryString, params, paramcount); |
WiredHome | 2:a29c32190037 | 285 | regHandled = true; |
WiredHome | 2:a29c32190037 | 286 | break; // we only execute the first one |
WiredHome | 2:a29c32190037 | 287 | } |
WiredHome | 2:a29c32190037 | 288 | } |
WiredHome | 2:a29c32190037 | 289 | |
WiredHome | 2:a29c32190037 | 290 | if (regHandled && acceptIt) { |
WiredHome | 2:a29c32190037 | 291 | // If so, we'll make space for it |
WiredHome | 2:a29c32190037 | 292 | postQueryString = (char *)malloc(postBytes + 1); |
WiredHome | 2:a29c32190037 | 293 | if (postQueryString) { |
WiredHome | 2:a29c32190037 | 294 | char * offset; |
WiredHome | 2:a29c32190037 | 295 | int len; |
WiredHome | 2:a29c32190037 | 296 | |
WiredHome | 2:a29c32190037 | 297 | dblCR += 4; // If we slurped up any of the POST, |
WiredHome | 2:a29c32190037 | 298 | while (*dblCR && *dblCR <= ' ') |
WiredHome | 2:a29c32190037 | 299 | dblCR++; |
WiredHome | 2:a29c32190037 | 300 | strcpy(postQueryString, dblCR); // copy that in and then get the rest |
WiredHome | 2:a29c32190037 | 301 | while ((len = strlen(postQueryString)) < postBytes) { |
WiredHome | 2:a29c32190037 | 302 | int n; |
WiredHome | 2:a29c32190037 | 303 | offset = postQueryString + len; |
WiredHome | 2:a29c32190037 | 304 | n = client.receive(offset, postBytes - len); |
WiredHome | 2:a29c32190037 | 305 | if (n >=0) { |
WiredHome | 2:a29c32190037 | 306 | offset[n] = '\0'; |
WiredHome | 2:a29c32190037 | 307 | } |
WiredHome | 2:a29c32190037 | 308 | } |
WiredHome | 2:a29c32190037 | 309 | if (len >= 0) { |
WiredHome | 2:a29c32190037 | 310 | #ifdef DEBUG |
WiredHome | 2:a29c32190037 | 311 | pc->printf("POSTDATA: %s\r\n", postQueryString); |
WiredHome | 2:a29c32190037 | 312 | #endif |
WiredHome | 2:a29c32190037 | 313 | UnescapeString(postQueryString); |
WiredHome | 2:a29c32190037 | 314 | ParseParameters(postQueryString); |
WiredHome | 2:a29c32190037 | 315 | } |
WiredHome | 2:a29c32190037 | 316 | } |
WiredHome | 2:a29c32190037 | 317 | } else { |
WiredHome | 2:a29c32190037 | 318 | // Simply copy it to the bitbucket |
WiredHome | 2:a29c32190037 | 319 | int bytesToDump = postBytes; |
WiredHome | 2:a29c32190037 | 320 | char * bitbucket = (char *)malloc(201); |
WiredHome | 2:a29c32190037 | 321 | dblCR += 4; |
WiredHome | 0:729320f63c5c | 322 | while (*dblCR && *dblCR <= ' ') |
WiredHome | 2:a29c32190037 | 323 | dblCR++; |
WiredHome | 2:a29c32190037 | 324 | bytesToDump -= strlen(dblCR); |
WiredHome | 2:a29c32190037 | 325 | while (bytesToDump > 0) { |
WiredHome | 2:a29c32190037 | 326 | int n = (bytesToDump > 200) ? 200 : bytesToDump; |
WiredHome | 2:a29c32190037 | 327 | n = client.receive(bitbucket, n); |
WiredHome | 2:a29c32190037 | 328 | bytesToDump -= n; |
WiredHome | 0:729320f63c5c | 329 | } |
WiredHome | 2:a29c32190037 | 330 | free(bitbucket); |
WiredHome | 0:729320f63c5c | 331 | } |
WiredHome | 0:729320f63c5c | 332 | } |
WiredHome | 0:729320f63c5c | 333 | } |
WiredHome | 0:729320f63c5c | 334 | } else { |
WiredHome | 0:729320f63c5c | 335 | // received partial, but not the double (\r\n\r\n) |
WiredHome | 0:729320f63c5c | 336 | bPtr += n; |
WiredHome | 0:729320f63c5c | 337 | } |
WiredHome | 0:729320f63c5c | 338 | } |
WiredHome | 0:729320f63c5c | 339 | break; |
WiredHome | 0:729320f63c5c | 340 | default: |
WiredHome | 0:729320f63c5c | 341 | // not expected to arrive here |
WiredHome | 0:729320f63c5c | 342 | op = Idle; |
WiredHome | 0:729320f63c5c | 343 | break; |
WiredHome | 0:729320f63c5c | 344 | } |
WiredHome | 0:729320f63c5c | 345 | } |
WiredHome | 0:729320f63c5c | 346 | |
WiredHome | 0:729320f63c5c | 347 | |
WiredHome | 0:729320f63c5c | 348 | const char * HTTPServer::GetSupportedType(const char * filename) |
WiredHome | 0:729320f63c5c | 349 | { |
WiredHome | 0:729320f63c5c | 350 | int i; |
WiredHome | 0:729320f63c5c | 351 | int buflen = strlen(filename); |
WiredHome | 0:729320f63c5c | 352 | int extlen; |
WiredHome | 0:729320f63c5c | 353 | |
WiredHome | 0:729320f63c5c | 354 | for (i=0; extensions[i].ext != 0; i++) { |
WiredHome | 0:729320f63c5c | 355 | extlen = strlen(extensions[i].ext); |
WiredHome | 0:729320f63c5c | 356 | if ( !strncmp(&filename[buflen-extlen], extensions[i].ext, extlen)) { |
WiredHome | 0:729320f63c5c | 357 | return extensions[i].filetype; |
WiredHome | 0:729320f63c5c | 358 | } |
WiredHome | 0:729320f63c5c | 359 | } |
WiredHome | 0:729320f63c5c | 360 | return NULL; |
WiredHome | 0:729320f63c5c | 361 | } |
WiredHome | 0:729320f63c5c | 362 | |
WiredHome | 0:729320f63c5c | 363 | void HTTPServer::send(const char * msg, int bytes) |
WiredHome | 0:729320f63c5c | 364 | { |
WiredHome | 0:729320f63c5c | 365 | if (bytes == -1) |
WiredHome | 0:729320f63c5c | 366 | bytes = strlen(msg); |
WiredHome | 0:729320f63c5c | 367 | wifly->send(msg, bytes); |
WiredHome | 0:729320f63c5c | 368 | #ifdef DEBUG |
WiredHome | 0:729320f63c5c | 369 | // pc->printf("%s", msg); |
WiredHome | 0:729320f63c5c | 370 | #endif |
WiredHome | 0:729320f63c5c | 371 | } |
WiredHome | 0:729320f63c5c | 372 | |
WiredHome | 0:729320f63c5c | 373 | bool HTTPServer::SendFile(const char * filename, const char * filetype) |
WiredHome | 0:729320f63c5c | 374 | { |
WiredHome | 0:729320f63c5c | 375 | FILE * fp; |
WiredHome | 0:729320f63c5c | 376 | |
WiredHome | 0:729320f63c5c | 377 | fp = fopen(filename,"rb"); |
WiredHome | 0:729320f63c5c | 378 | // is supported, now try to open it |
WiredHome | 0:729320f63c5c | 379 | if (fp) { // can open it |
WiredHome | 0:729320f63c5c | 380 | char *fbuffer = (char *)malloc(FILESEND_BUF_SIZE); |
WiredHome | 0:729320f63c5c | 381 | int bytes; |
WiredHome | 0:729320f63c5c | 382 | |
WiredHome | 0:729320f63c5c | 383 | //pc->printf("sending [%s]\r\n", filename); |
WiredHome | 0:729320f63c5c | 384 | header(200, "OK", filetype); |
WiredHome | 0:729320f63c5c | 385 | // now the file itself |
WiredHome | 0:729320f63c5c | 386 | bytes = fread(fbuffer,sizeof(char),FILESEND_BUF_SIZE,fp); |
WiredHome | 0:729320f63c5c | 387 | while (bytes > 0) { |
WiredHome | 0:729320f63c5c | 388 | send(fbuffer, bytes); |
WiredHome | 0:729320f63c5c | 389 | bytes = fread(fbuffer,sizeof(char),FILESEND_BUF_SIZE,fp); |
WiredHome | 0:729320f63c5c | 390 | } |
WiredHome | 0:729320f63c5c | 391 | free(fbuffer); |
WiredHome | 0:729320f63c5c | 392 | fclose(fp); |
WiredHome | 0:729320f63c5c | 393 | return true; |
WiredHome | 0:729320f63c5c | 394 | } else { |
WiredHome | 0:729320f63c5c | 395 | //pc->printf("Can't open %s\r\n", filename); |
WiredHome | 0:729320f63c5c | 396 | header(404, "Not Found", "Pragma: err - Can't open\r\n"); |
WiredHome | 0:729320f63c5c | 397 | return false; |
WiredHome | 0:729320f63c5c | 398 | } |
WiredHome | 0:729320f63c5c | 399 | } |
WiredHome | 0:729320f63c5c | 400 | |
WiredHome | 0:729320f63c5c | 401 | int HTTPServer::HexCharToInt(char c) |
WiredHome | 0:729320f63c5c | 402 | { |
WiredHome | 0:729320f63c5c | 403 | if (c >= 'a' && c <= 'f') |
WiredHome | 0:729320f63c5c | 404 | return (c - 'a' + 10); |
WiredHome | 0:729320f63c5c | 405 | else if (c >= 'A' && c <= 'F') |
WiredHome | 0:729320f63c5c | 406 | return (c - 'A' + 10); |
WiredHome | 0:729320f63c5c | 407 | else if (c >= '0' && c <= '9') |
WiredHome | 0:729320f63c5c | 408 | return c - '0'; |
WiredHome | 0:729320f63c5c | 409 | else |
WiredHome | 0:729320f63c5c | 410 | return 0; |
WiredHome | 0:729320f63c5c | 411 | } |
WiredHome | 0:729320f63c5c | 412 | |
WiredHome | 0:729320f63c5c | 413 | char HTTPServer::HexPairToChar(char * p) |
WiredHome | 0:729320f63c5c | 414 | { |
WiredHome | 0:729320f63c5c | 415 | return 16 * HexCharToInt(*p) + HexCharToInt(*(p+1)); |
WiredHome | 0:729320f63c5c | 416 | } |
WiredHome | 0:729320f63c5c | 417 | |
WiredHome | 0:729320f63c5c | 418 | void HTTPServer::UnescapeString(char * encoded) |
WiredHome | 0:729320f63c5c | 419 | { |
WiredHome | 0:729320f63c5c | 420 | char *p; |
WiredHome | 0:729320f63c5c | 421 | |
WiredHome | 0:729320f63c5c | 422 | // first convert '+' to ' ' |
WiredHome | 0:729320f63c5c | 423 | p = strchr(encoded, '+'); |
WiredHome | 0:729320f63c5c | 424 | while (p) { |
WiredHome | 0:729320f63c5c | 425 | *p = ' '; |
WiredHome | 0:729320f63c5c | 426 | p = strchr(encoded, '+'); |
WiredHome | 0:729320f63c5c | 427 | } |
WiredHome | 0:729320f63c5c | 428 | // then convert hex '%xx' to char 'x' |
WiredHome | 0:729320f63c5c | 429 | p = strchr(encoded, '%'); |
WiredHome | 0:729320f63c5c | 430 | while (p) { |
WiredHome | 0:729320f63c5c | 431 | if (strchr("0123456789ABCDEFabcdef", *(p+1)) |
WiredHome | 0:729320f63c5c | 432 | && strchr("0123456789ABCDEFabcdef", *(p+2)) ) { |
WiredHome | 0:729320f63c5c | 433 | *p = HexPairToChar(p+1); |
WiredHome | 0:729320f63c5c | 434 | p++; // advance past the % |
WiredHome | 0:729320f63c5c | 435 | char * a = p; |
WiredHome | 0:729320f63c5c | 436 | char * b = p + 2; |
WiredHome | 0:729320f63c5c | 437 | do { |
WiredHome | 0:729320f63c5c | 438 | *a++ = *b++; |
WiredHome | 0:729320f63c5c | 439 | } while (*b); |
WiredHome | 0:729320f63c5c | 440 | *a = '\0'; |
WiredHome | 0:729320f63c5c | 441 | } |
WiredHome | 0:729320f63c5c | 442 | p = strchr(p, '%'); |
WiredHome | 0:729320f63c5c | 443 | } |
WiredHome | 0:729320f63c5c | 444 | } |
WiredHome | 0:729320f63c5c | 445 | |
WiredHome | 0:729320f63c5c | 446 | const char * HTTPServer::GetParameter(const char * name) |
WiredHome | 0:729320f63c5c | 447 | { |
WiredHome | 0:729320f63c5c | 448 | for (int i=0; i<paramcount; i++) { |
WiredHome | 0:729320f63c5c | 449 | if (strcmp(params[i].name, name) == 0) { |
WiredHome | 0:729320f63c5c | 450 | return params[i].value; |
WiredHome | 0:729320f63c5c | 451 | } |
WiredHome | 0:729320f63c5c | 452 | } |
WiredHome | 0:729320f63c5c | 453 | return NULL; |
WiredHome | 0:729320f63c5c | 454 | } |
WiredHome | 0:729320f63c5c | 455 | |
WiredHome | 0:729320f63c5c | 456 | // this=that&who=what&more=stuff... |
WiredHome | 0:729320f63c5c | 457 | // ^ ^ ^ |
WiredHome | 0:729320f63c5c | 458 | void HTTPServer::ParseParameters(char * pName) |
WiredHome | 0:729320f63c5c | 459 | { |
WiredHome | 0:729320f63c5c | 460 | char * pVal; |
WiredHome | 0:729320f63c5c | 461 | char * pNextName; |
WiredHome | 0:729320f63c5c | 462 | |
WiredHome | 0:729320f63c5c | 463 | // Parse params |
WiredHome | 0:729320f63c5c | 464 | pVal = strchr(pName, '#'); // If there is a '#fragment_id', we can ignore it |
WiredHome | 0:729320f63c5c | 465 | if (pVal) |
WiredHome | 0:729320f63c5c | 466 | *pVal = '\0'; |
WiredHome | 0:729320f63c5c | 467 | do { |
WiredHome | 0:729320f63c5c | 468 | //pc->printf("Parse(%s)\r\n", pName); |
WiredHome | 0:729320f63c5c | 469 | //*pName++ = '\0'; // already '\0' on the first entry |
WiredHome | 0:729320f63c5c | 470 | params[paramcount].name = pName; |
WiredHome | 0:729320f63c5c | 471 | pVal = strchr(pName, '='); |
WiredHome | 0:729320f63c5c | 472 | pNextName = strchr(pName,'&'); |
WiredHome | 0:729320f63c5c | 473 | if (pVal) { |
WiredHome | 0:729320f63c5c | 474 | if (pNextName == NULL || (pNextName && pNextName > pVal)) { |
WiredHome | 0:729320f63c5c | 475 | *pVal++ = '\0'; |
WiredHome | 0:729320f63c5c | 476 | params[paramcount].value = pVal; |
WiredHome | 0:729320f63c5c | 477 | pName = pVal; |
WiredHome | 0:729320f63c5c | 478 | } |
WiredHome | 0:729320f63c5c | 479 | } |
WiredHome | 0:729320f63c5c | 480 | //pc->printf(" [%s]=[%s]\r\n", params[paramcount].name, params[paramcount].value); |
WiredHome | 0:729320f63c5c | 481 | paramcount++; |
WiredHome | 0:729320f63c5c | 482 | if (pNextName) { |
WiredHome | 0:729320f63c5c | 483 | pName = pNextName; |
WiredHome | 0:729320f63c5c | 484 | *pName++ = '\0'; |
WiredHome | 0:729320f63c5c | 485 | } else { |
WiredHome | 0:729320f63c5c | 486 | pName = NULL; |
WiredHome | 0:729320f63c5c | 487 | } |
WiredHome | 0:729320f63c5c | 488 | } while (pName && paramcount < maxparams); |
WiredHome | 0:729320f63c5c | 489 | } |
WiredHome | 0:729320f63c5c | 490 | |
WiredHome | 0:729320f63c5c | 491 | |
WiredHome | 0:729320f63c5c | 492 | void HTTPServer::GetRemoteAddr(char * str, int size) |
WiredHome | 0:729320f63c5c | 493 | { |
WiredHome | 0:729320f63c5c | 494 | bool res = false; |
WiredHome | 0:729320f63c5c | 495 | char *p; |
WiredHome | 0:729320f63c5c | 496 | |
WiredHome | 0:729320f63c5c | 497 | res = wifly->sendCommand("show z\r", "NO", str, 5000); |
WiredHome | 0:729320f63c5c | 498 | wait(0.2); // how long to wait is fragile, but need the rest of the chars to come in... |
WiredHome | 0:729320f63c5c | 499 | if (res) { |
WiredHome | 0:729320f63c5c | 500 | p = strchr(str, '\n'); // truncate after the octets. |
WiredHome | 0:729320f63c5c | 501 | if (p) *p = '\0'; |
WiredHome | 0:729320f63c5c | 502 | p = strchr(str, ' '); // or a space |
WiredHome | 0:729320f63c5c | 503 | if (p) *p = '\0'; |
WiredHome | 0:729320f63c5c | 504 | p = strchr(str, '<'); // or a < |
WiredHome | 0:729320f63c5c | 505 | if (p) *p = '\0'; |
WiredHome | 0:729320f63c5c | 506 | } |
WiredHome | 0:729320f63c5c | 507 | wifly->exit(); |
WiredHome | 0:729320f63c5c | 508 | } |
WiredHome | 0:729320f63c5c | 509 | |
WiredHome | 0:729320f63c5c | 510 | |
WiredHome | 0:729320f63c5c | 511 | void HTTPServer::header(int code, const char * code_text, const char * content_type, const char * optional_text) |
WiredHome | 0:729320f63c5c | 512 | { |
WiredHome | 0:729320f63c5c | 513 | char http[100]; |
WiredHome | 0:729320f63c5c | 514 | |
WiredHome | 0:729320f63c5c | 515 | sprintf(http, "%s %i %s\r\n", hdr_httpver, code, code_text); |
WiredHome | 0:729320f63c5c | 516 | send(http); |
WiredHome | 0:729320f63c5c | 517 | send(hdr_age); |
WiredHome | 0:729320f63c5c | 518 | send(hdr_server); |
WiredHome | 0:729320f63c5c | 519 | if (content_type) { |
WiredHome | 0:729320f63c5c | 520 | send(content_type); |
WiredHome | 0:729320f63c5c | 521 | } |
WiredHome | 0:729320f63c5c | 522 | if (optional_text) { |
WiredHome | 0:729320f63c5c | 523 | send(optional_text); |
WiredHome | 0:729320f63c5c | 524 | } |
WiredHome | 2:a29c32190037 | 525 | send(hdr_dnt); |
WiredHome | 0:729320f63c5c | 526 | send(hdr_close); |
WiredHome | 0:729320f63c5c | 527 | send(nl); |
WiredHome | 0:729320f63c5c | 528 | } |
WiredHome | 0:729320f63c5c | 529 | |
WiredHome | 0:729320f63c5c | 530 | void HTTPServer::close_connection( ) |
WiredHome | 0:729320f63c5c | 531 | { |
WiredHome | 0:729320f63c5c | 532 | #ifndef DEBUG |
WiredHome | 0:729320f63c5c | 533 | wifly->close(); |
WiredHome | 0:729320f63c5c | 534 | #else // DEBUG |
WiredHome | 0:729320f63c5c | 535 | if (!wifly->close()) |
WiredHome | 0:729320f63c5c | 536 | pc->printf("Couldn't close connection\r\n"); |
WiredHome | 0:729320f63c5c | 537 | #endif |
WiredHome | 0:729320f63c5c | 538 | } |
WiredHome | 0:729320f63c5c | 539 | |
WiredHome | 0:729320f63c5c | 540 | bool HTTPServer::Extract(char * haystack, char * needle, char ** string) |
WiredHome | 0:729320f63c5c | 541 | { |
WiredHome | 0:729320f63c5c | 542 | bool ret = false; // assume failure until proven otherwise |
WiredHome | 0:729320f63c5c | 543 | char * qs = NULL; |
WiredHome | 0:729320f63c5c | 544 | char * eqs = NULL; |
WiredHome | 0:729320f63c5c | 545 | char * container = NULL; |
WiredHome | 0:729320f63c5c | 546 | char * get = strstr(haystack, needle); // what if not at the front? |
WiredHome | 0:729320f63c5c | 547 | if (get) { |
WiredHome | 0:729320f63c5c | 548 | // Seems to be a valid "...GET /QueryString HTTP/1.1" |
WiredHome | 0:729320f63c5c | 549 | qs = get + strlen(needle); // in case the needle didn't have space delimiters |
WiredHome | 0:729320f63c5c | 550 | while (*qs == ' ') |
WiredHome | 0:729320f63c5c | 551 | qs++; |
WiredHome | 0:729320f63c5c | 552 | // /QueryString\0HTTP/1.1\0\0 |
WiredHome | 0:729320f63c5c | 553 | if (*string) // recycle old string when working a new one |
WiredHome | 0:729320f63c5c | 554 | free(*string); |
WiredHome | 0:729320f63c5c | 555 | container = (char *)malloc(strlen(qs)); |
WiredHome | 0:729320f63c5c | 556 | if (container) { |
WiredHome | 0:729320f63c5c | 557 | strcpy(container, qs); |
WiredHome | 0:729320f63c5c | 558 | eqs = strchr(container, ' '); |
WiredHome | 0:729320f63c5c | 559 | if (eqs) |
WiredHome | 0:729320f63c5c | 560 | *eqs = '\0'; |
WiredHome | 0:729320f63c5c | 561 | *string = container; |
WiredHome | 0:729320f63c5c | 562 | ret = true; |
WiredHome | 0:729320f63c5c | 563 | } else { |
WiredHome | 0:729320f63c5c | 564 | *string = NULL; // something bad happened... no memory |
WiredHome | 0:729320f63c5c | 565 | } |
WiredHome | 0:729320f63c5c | 566 | } |
WiredHome | 0:729320f63c5c | 567 | return ret; |
WiredHome | 0:729320f63c5c | 568 | } |
WiredHome | 0:729320f63c5c | 569 | |
WiredHome | 0:729320f63c5c | 570 | char * HTTPServer::rewriteWithDefaultFile(char * queryString) |
WiredHome | 0:729320f63c5c | 571 | { |
WiredHome | 0:729320f63c5c | 572 | char * temp = (char *)malloc(strlen(queryString) + strlen(DEFAULT_FILENAME) + 1); |
WiredHome | 0:729320f63c5c | 573 | |
WiredHome | 0:729320f63c5c | 574 | if (temp) { |
WiredHome | 0:729320f63c5c | 575 | *temp = '\0'; |
WiredHome | 0:729320f63c5c | 576 | strcpy(temp, queryString); |
WiredHome | 0:729320f63c5c | 577 | strcat(temp, DEFAULT_FILENAME); |
WiredHome | 0:729320f63c5c | 578 | free(queryString); |
WiredHome | 0:729320f63c5c | 579 | return temp; |
WiredHome | 0:729320f63c5c | 580 | } else { |
WiredHome | 0:729320f63c5c | 581 | return queryString; |
WiredHome | 0:729320f63c5c | 582 | } |
WiredHome | 0:729320f63c5c | 583 | } |
WiredHome | 0:729320f63c5c | 584 | |
WiredHome | 0:729320f63c5c | 585 | char * HTTPServer::rewritePrependWebroot(char * queryString) |
WiredHome | 0:729320f63c5c | 586 | { |
WiredHome | 0:729320f63c5c | 587 | char * temp = (char *)malloc(strlen(webroot) + strlen(queryString) + 1); |
WiredHome | 0:729320f63c5c | 588 | |
WiredHome | 0:729320f63c5c | 589 | if (temp) { |
WiredHome | 0:729320f63c5c | 590 | *temp = '\0'; |
WiredHome | 0:729320f63c5c | 591 | strcpy(temp, webroot); |
WiredHome | 0:729320f63c5c | 592 | if (temp[strlen(temp)-1] == '/' && *queryString == '/') |
WiredHome | 0:729320f63c5c | 593 | temp[strlen(temp)-1] = '\0'; |
WiredHome | 0:729320f63c5c | 594 | strcat(temp, queryString); |
WiredHome | 0:729320f63c5c | 595 | free(queryString); |
WiredHome | 0:729320f63c5c | 596 | return temp; |
WiredHome | 0:729320f63c5c | 597 | } else { |
WiredHome | 0:729320f63c5c | 598 | return queryString; |
WiredHome | 0:729320f63c5c | 599 | } |
WiredHome | 0:729320f63c5c | 600 | } |
WiredHome | 0:729320f63c5c | 601 | |
WiredHome | 0:729320f63c5c | 602 |