HTTP Server, WebSocket support

Fork of HTTPD by Suga koubou

Committer:
dgriffin65
Date:
Thu Jun 15 20:17:24 2017 +0000
Revision:
1:b724fdb741e7
Parent:
0:d18dff347122
Updated to mbed-os

Who changed what in which revision?

UserRevisionLine numberNew contents of line
okini3939 0:d18dff347122 1 /* Copyright (C) 2013 Hiroshi Suga, MIT License
okini3939 0:d18dff347122 2 *
okini3939 0:d18dff347122 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
okini3939 0:d18dff347122 4 * and associated documentation files (the "Software"), to deal in the Software without restriction,
okini3939 0:d18dff347122 5 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
okini3939 0:d18dff347122 6 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
okini3939 0:d18dff347122 7 * furnished to do so, subject to the following conditions:
okini3939 0:d18dff347122 8 *
okini3939 0:d18dff347122 9 * The above copyright notice and this permission notice shall be included in all copies or
okini3939 0:d18dff347122 10 * substantial portions of the Software.
okini3939 0:d18dff347122 11 *
okini3939 0:d18dff347122 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
okini3939 0:d18dff347122 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
okini3939 0:d18dff347122 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
okini3939 0:d18dff347122 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
okini3939 0:d18dff347122 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
okini3939 0:d18dff347122 17 */
okini3939 0:d18dff347122 18
okini3939 0:d18dff347122 19 #include "HTTPD.h"
okini3939 0:d18dff347122 20 #include <ctype.h>
okini3939 0:d18dff347122 21 #include <stdlib.h>
okini3939 0:d18dff347122 22 #include <string.h>
okini3939 0:d18dff347122 23
okini3939 0:d18dff347122 24 #define MIMETABLE_NUM 9
okini3939 0:d18dff347122 25 static const struct {
okini3939 0:d18dff347122 26 char ext[5];
okini3939 0:d18dff347122 27 char type[24];
okini3939 0:d18dff347122 28 } mimetable[MIMETABLE_NUM] = {
okini3939 0:d18dff347122 29 {"txt", "text/plain"}, // default
okini3939 0:d18dff347122 30 {"html", "text/html"},
okini3939 0:d18dff347122 31 {"htm", "text/html"},
okini3939 0:d18dff347122 32 {"css", "text/css"},
okini3939 0:d18dff347122 33 {"js", "application/javascript"},
okini3939 0:d18dff347122 34 {"jpg", "image/jpeg"},
okini3939 0:d18dff347122 35 {"png", "image/png"},
okini3939 0:d18dff347122 36 {"gif", "image/gif"},
okini3939 0:d18dff347122 37 {"ico", "image/x-icon"},
okini3939 0:d18dff347122 38 };
okini3939 0:d18dff347122 39
okini3939 0:d18dff347122 40 char *HTTPD::getUri (int id) {
okini3939 0:d18dff347122 41 return _state[id].uri;
okini3939 0:d18dff347122 42 }
okini3939 0:d18dff347122 43
okini3939 0:d18dff347122 44 char *HTTPD::getFilename (int id) {
okini3939 0:d18dff347122 45 return _state[id].filename;
okini3939 0:d18dff347122 46 }
okini3939 0:d18dff347122 47
okini3939 0:d18dff347122 48 char *HTTPD::getQueryString (int id) {
okini3939 0:d18dff347122 49 return _state[id].querystring;
okini3939 0:d18dff347122 50 }
okini3939 0:d18dff347122 51
okini3939 0:d18dff347122 52 int HTTPD::receive (int id, char *buf, int len) {
okini3939 0:d18dff347122 53 int i;
okini3939 0:d18dff347122 54
okini3939 0:d18dff347122 55 for (i = 0; i < len; i ++) {
okini3939 0:d18dff347122 56 if (_state[id].buf->dequeue(&buf[i]) == false) break;
okini3939 0:d18dff347122 57 }
okini3939 0:d18dff347122 58 return i;
okini3939 0:d18dff347122 59 }
okini3939 0:d18dff347122 60
okini3939 0:d18dff347122 61 int HTTPD::send (int id, const char *body, int len, const char *header) {
okini3939 0:d18dff347122 62 char buf[HTTPD_CMD_SIZE];
okini3939 0:d18dff347122 63
okini3939 0:d18dff347122 64 strcpy(buf, "HTTP/1.1 200 OK\r\n");
dgriffin65 1:b724fdb741e7 65 _state[id].client->send(buf, strlen(buf));
okini3939 0:d18dff347122 66 strcpy(buf, "Server: GSwifi httpd\r\n");
dgriffin65 1:b724fdb741e7 67 _state[id].client->send(buf, strlen(buf));
okini3939 0:d18dff347122 68 if (_state[id].keepalive) {
okini3939 0:d18dff347122 69 strcpy(buf, "Connection: Keep-Alive\r\n");
okini3939 0:d18dff347122 70 } else {
okini3939 0:d18dff347122 71 strcpy(buf, "Connection: close\r\n");
okini3939 0:d18dff347122 72 }
dgriffin65 1:b724fdb741e7 73 _state[id].client->send(buf, strlen(buf));
okini3939 0:d18dff347122 74 if (header) {
dgriffin65 1:b724fdb741e7 75 _state[id].client->send((char*)header, strlen(header));
okini3939 0:d18dff347122 76 }
okini3939 0:d18dff347122 77 sprintf(buf, "Content-Length: %d\r\n\r\n", len);
dgriffin65 1:b724fdb741e7 78 _state[id].client->send(buf, strlen(buf));
dgriffin65 1:b724fdb741e7 79
dgriffin65 1:b724fdb741e7 80 return _state[id].client->send((char*)body, len);
dgriffin65 1:b724fdb741e7 81 }
dgriffin65 1:b724fdb741e7 82
dgriffin65 1:b724fdb741e7 83 int HTTPD::sendstr (int id, const char *buf) {
dgriffin65 1:b724fdb741e7 84 return _state[id].client->send((char*)buf, strlen(buf));
dgriffin65 1:b724fdb741e7 85 }
dgriffin65 1:b724fdb741e7 86
okini3939 0:d18dff347122 87
dgriffin65 1:b724fdb741e7 88 int HTTPD::hprintf(int id, const char* format, ...) {
dgriffin65 1:b724fdb741e7 89 //FIX ME: This could result in memory overruns if the buffer size is exceeded
dgriffin65 1:b724fdb741e7 90 static Mutex _mtx;
dgriffin65 1:b724fdb741e7 91 static char _buf[1024];
dgriffin65 1:b724fdb741e7 92
dgriffin65 1:b724fdb741e7 93 std::va_list arg;
dgriffin65 1:b724fdb741e7 94
dgriffin65 1:b724fdb741e7 95 _mtx.lock();
dgriffin65 1:b724fdb741e7 96
dgriffin65 1:b724fdb741e7 97 va_start(arg, format);
dgriffin65 1:b724fdb741e7 98 vsprintf(_buf, format, arg);
dgriffin65 1:b724fdb741e7 99 va_end(arg);
dgriffin65 1:b724fdb741e7 100
dgriffin65 1:b724fdb741e7 101 int r = _state[id].client->send(_buf, strlen(_buf));
dgriffin65 1:b724fdb741e7 102
dgriffin65 1:b724fdb741e7 103 _mtx.unlock();
dgriffin65 1:b724fdb741e7 104 return r;
okini3939 0:d18dff347122 105 }
okini3939 0:d18dff347122 106
okini3939 0:d18dff347122 107 int HTTPD::getHandler (const char *uri) {
okini3939 0:d18dff347122 108 int i;
okini3939 0:d18dff347122 109
okini3939 0:d18dff347122 110 for (i = 0; i < _handler_count; i ++) {
okini3939 0:d18dff347122 111 if (strncmp(uri, _handler[i].uri, strlen(_handler[i].uri)) == NULL) {
okini3939 0:d18dff347122 112 // found
okini3939 0:d18dff347122 113 return i;
okini3939 0:d18dff347122 114 }
okini3939 0:d18dff347122 115 }
okini3939 0:d18dff347122 116 return -1;
okini3939 0:d18dff347122 117 }
okini3939 0:d18dff347122 118
okini3939 0:d18dff347122 119 int HTTPD::attach (const char *uri, const char *dir) {
okini3939 0:d18dff347122 120 if (_handler_count < HTTPD_MAX_HANDLES) {
okini3939 0:d18dff347122 121 _handler[_handler_count].uri = (char*)malloc(strlen(uri) + 1);
okini3939 0:d18dff347122 122 strcpy(_handler[_handler_count].uri, uri);
okini3939 0:d18dff347122 123 _handler[_handler_count].dir = (char*)malloc(strlen(dir) + 1);
okini3939 0:d18dff347122 124 strcpy(_handler[_handler_count].dir, dir);
okini3939 0:d18dff347122 125 _handler[_handler_count].funcCgi = NULL;
okini3939 0:d18dff347122 126 _handler_count ++;
okini3939 0:d18dff347122 127 return 0;
okini3939 0:d18dff347122 128 } else {
okini3939 0:d18dff347122 129 return -1;
okini3939 0:d18dff347122 130 }
okini3939 0:d18dff347122 131 }
okini3939 0:d18dff347122 132
okini3939 0:d18dff347122 133 int HTTPD::attach (const char *uri, void (*funcCgi)(int)) {
okini3939 0:d18dff347122 134 if (_handler_count < HTTPD_MAX_HANDLES) {
okini3939 0:d18dff347122 135 _handler[_handler_count].uri = (char*)malloc(strlen(uri) + 1);
okini3939 0:d18dff347122 136 strcpy(_handler[_handler_count].uri, uri);
okini3939 0:d18dff347122 137 _handler[_handler_count].dir = NULL;
okini3939 0:d18dff347122 138 _handler[_handler_count].funcCgi = funcCgi;
okini3939 0:d18dff347122 139 _handler_count ++;
okini3939 0:d18dff347122 140 return 0;
okini3939 0:d18dff347122 141 } else {
okini3939 0:d18dff347122 142 return -1;
okini3939 0:d18dff347122 143 }
okini3939 0:d18dff347122 144 }
okini3939 0:d18dff347122 145
okini3939 0:d18dff347122 146
okini3939 0:d18dff347122 147 char *HTTPD::mimetype (char *file) {
okini3939 0:d18dff347122 148 int i, j;
okini3939 0:d18dff347122 149
okini3939 0:d18dff347122 150 for (i = 0; i < MIMETABLE_NUM; i ++) {
okini3939 0:d18dff347122 151 j = strlen(mimetable[i].ext);
okini3939 0:d18dff347122 152 if (file[strlen(file) - j - 1] == '.' &&
okini3939 0:d18dff347122 153 strnicmp(&file[strlen(file) - j], mimetable[i].ext, j) == NULL) {
okini3939 0:d18dff347122 154 return (char*)mimetable[i].type;
okini3939 0:d18dff347122 155 }
okini3939 0:d18dff347122 156 }
okini3939 0:d18dff347122 157 return (char*)mimetable[0].type;
okini3939 0:d18dff347122 158 }
okini3939 0:d18dff347122 159
okini3939 0:d18dff347122 160 int HTTPD::strnicmp (const char *p1, const char *p2, int n) {
okini3939 0:d18dff347122 161 int i, r = -1;
okini3939 0:d18dff347122 162 char c1, c2;
okini3939 0:d18dff347122 163
okini3939 0:d18dff347122 164 for (i = 0; i < n; i ++) {
okini3939 0:d18dff347122 165 c1 = (p1[i] >= 'a' && p1[i] <= 'z') ? p1[i] - ('a' - 'A'): p1[i];
okini3939 0:d18dff347122 166 c2 = (p2[i] >= 'a' && p2[i] <= 'z') ? p2[i] - ('a' - 'A'): p2[i];
okini3939 0:d18dff347122 167 r = c1 - c2;
okini3939 0:d18dff347122 168 if (r) break;
okini3939 0:d18dff347122 169 }
okini3939 0:d18dff347122 170 return r;
okini3939 0:d18dff347122 171 }
okini3939 0:d18dff347122 172
okini3939 0:d18dff347122 173
okini3939 0:d18dff347122 174 /* base64encode code from
okini3939 0:d18dff347122 175 * Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
okini3939 0:d18dff347122 176 */
okini3939 0:d18dff347122 177 int HTTPD::base64encode (const char *input, int length, char *output, int len) {
okini3939 0:d18dff347122 178 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
okini3939 0:d18dff347122 179 unsigned int c, c1, c2, c3;
okini3939 0:d18dff347122 180
okini3939 0:d18dff347122 181 if (len < ((((length-1)/3)+1)<<2)) return -1;
okini3939 0:d18dff347122 182 for(unsigned int i = 0, j = 0; i<length; i+=3,j+=4) {
okini3939 0:d18dff347122 183 c1 = ((((unsigned char)*((unsigned char *)&input[i]))));
okini3939 0:d18dff347122 184 c2 = (length>i+1)?((((unsigned char)*((unsigned char *)&input[i+1])))):0;
okini3939 0:d18dff347122 185 c3 = (length>i+2)?((((unsigned char)*((unsigned char *)&input[i+2])))):0;
okini3939 0:d18dff347122 186
okini3939 0:d18dff347122 187 c = ((c1 & 0xFC) >> 2);
okini3939 0:d18dff347122 188 output[j+0] = base64[c];
okini3939 0:d18dff347122 189 c = ((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4);
okini3939 0:d18dff347122 190 output[j+1] = base64[c];
okini3939 0:d18dff347122 191 c = ((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6);
okini3939 0:d18dff347122 192 output[j+2] = (length>i+1)?base64[c]:'=';
okini3939 0:d18dff347122 193 c = (c3 & 0x3F);
okini3939 0:d18dff347122 194 output[j+3] = (length>i+2)?base64[c]:'=';
okini3939 0:d18dff347122 195 }
okini3939 0:d18dff347122 196 output[(((length-1)/3)+1)<<2] = '\0';
okini3939 0:d18dff347122 197 return 0;
okini3939 0:d18dff347122 198 }
okini3939 0:d18dff347122 199
okini3939 0:d18dff347122 200
okini3939 0:d18dff347122 201 /* urlencode code from
okini3939 0:d18dff347122 202 * Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
okini3939 0:d18dff347122 203 */
okini3939 0:d18dff347122 204 int HTTPD::urlencode (const char *str, char *buf, int len) {
okini3939 0:d18dff347122 205 // char *pstr = str, *buf = (char*)malloc(strlen(str) * 3 + 1), *pbuf = buf;
okini3939 0:d18dff347122 206 const char *pstr = str;
okini3939 0:d18dff347122 207 char *pbuf = buf;
okini3939 0:d18dff347122 208
okini3939 0:d18dff347122 209 if (len < (strlen(str) * 3 + 1)) return -1;
okini3939 0:d18dff347122 210 while (*pstr) {
okini3939 0:d18dff347122 211 if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~')
okini3939 0:d18dff347122 212 *pbuf++ = *pstr;
okini3939 0:d18dff347122 213 else if (*pstr == ' ')
okini3939 0:d18dff347122 214 *pbuf++ = '+';
okini3939 0:d18dff347122 215 else
okini3939 0:d18dff347122 216 *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15);
okini3939 0:d18dff347122 217 pstr++;
okini3939 0:d18dff347122 218 }
okini3939 0:d18dff347122 219 *pbuf = '\0';
okini3939 0:d18dff347122 220 return 0;
okini3939 0:d18dff347122 221 }
okini3939 0:d18dff347122 222
okini3939 0:d18dff347122 223 /* urldecode code from
okini3939 0:d18dff347122 224 * Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
okini3939 0:d18dff347122 225 */
okini3939 0:d18dff347122 226 int HTTPD::urldecode (const char *str, char *buf, int len) {
okini3939 0:d18dff347122 227 // char *pstr = str, *buf = (char*)malloc(strlen(str) + 1), *pbuf = buf;
okini3939 0:d18dff347122 228 const char *pstr = str;
okini3939 0:d18dff347122 229 char *pbuf = buf;
okini3939 0:d18dff347122 230
okini3939 0:d18dff347122 231 if (len < (strlen(str) / 3 - 1)) return -1;
okini3939 0:d18dff347122 232 while (*pstr) {
okini3939 0:d18dff347122 233 if (*pstr == '%') {
okini3939 0:d18dff347122 234 if (pstr[1] && pstr[2]) {
okini3939 0:d18dff347122 235 *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
okini3939 0:d18dff347122 236 pstr += 2;
okini3939 0:d18dff347122 237 }
okini3939 0:d18dff347122 238 } else if (*pstr == '+') {
okini3939 0:d18dff347122 239 *pbuf++ = ' ';
okini3939 0:d18dff347122 240 } else {
okini3939 0:d18dff347122 241 *pbuf++ = *pstr;
okini3939 0:d18dff347122 242 }
okini3939 0:d18dff347122 243 pstr++;
okini3939 0:d18dff347122 244 }
okini3939 0:d18dff347122 245 *pbuf = '\0';
okini3939 0:d18dff347122 246 return 0;
okini3939 0:d18dff347122 247 }
okini3939 0:d18dff347122 248
okini3939 0:d18dff347122 249 int HTTPD::from_hex (int ch) {
okini3939 0:d18dff347122 250 return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
okini3939 0:d18dff347122 251 }
okini3939 0:d18dff347122 252
okini3939 0:d18dff347122 253 int HTTPD::to_hex (int code) {
okini3939 0:d18dff347122 254 static char hex[] = "0123456789abcdef";
okini3939 0:d18dff347122 255 return hex[code & 15];
okini3939 0:d18dff347122 256 }