HTTP Server, WebSocket support

Dependents:   YoPlegma

Fork of HTTPD by Suga koubou

Committer:
mitsarionas
Date:
Fri Sep 04 08:41:12 2015 +0000
Revision:
1:f30e7b210e53
Parent:
0:d18dff347122
redirect

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");
okini3939 0:d18dff347122 65 _state[id].client->send_all(buf, strlen(buf));
okini3939 0:d18dff347122 66 strcpy(buf, "Server: GSwifi httpd\r\n");
okini3939 0:d18dff347122 67 _state[id].client->send_all(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 }
okini3939 0:d18dff347122 73 _state[id].client->send_all(buf, strlen(buf));
okini3939 0:d18dff347122 74 if (header) {
okini3939 0:d18dff347122 75 _state[id].client->send_all((char*)header, strlen(header));
okini3939 0:d18dff347122 76 }
okini3939 0:d18dff347122 77 sprintf(buf, "Content-Length: %d\r\n\r\n", len);
okini3939 0:d18dff347122 78 _state[id].client->send_all(buf, strlen(buf));
okini3939 0:d18dff347122 79
okini3939 0:d18dff347122 80 return _state[id].client->send_all((char*)body, len);
okini3939 0:d18dff347122 81 }
okini3939 0:d18dff347122 82
mitsarionas 1:f30e7b210e53 83 int HTTPD::redirect (int id, int code, char *location, const char *body, int len, const char *header) {
mitsarionas 1:f30e7b210e53 84 char buf[HTTPD_CMD_SIZE];
mitsarionas 1:f30e7b210e53 85 strcpy(buf, "HTTP/1.1 ");
mitsarionas 1:f30e7b210e53 86 switch (code) {
mitsarionas 1:f30e7b210e53 87 case 301:
mitsarionas 1:f30e7b210e53 88 strcat(buf, "301 Moved Permanently\r\n");
mitsarionas 1:f30e7b210e53 89 break;
mitsarionas 1:f30e7b210e53 90 case 302:
mitsarionas 1:f30e7b210e53 91 strcat(buf, "302 Found\r\n");
mitsarionas 1:f30e7b210e53 92 break;
mitsarionas 1:f30e7b210e53 93 case 307:
mitsarionas 1:f30e7b210e53 94 strcat(buf, "307 Temporary Redirect\r\n");
mitsarionas 1:f30e7b210e53 95 break;
mitsarionas 1:f30e7b210e53 96 default:
mitsarionas 1:f30e7b210e53 97 return -1;
mitsarionas 1:f30e7b210e53 98 }
mitsarionas 1:f30e7b210e53 99 _state[id].client->send_all(buf, strlen(buf));
mitsarionas 1:f30e7b210e53 100 strcpy(buf, "Server: GSwifi httpd\r\n");
mitsarionas 1:f30e7b210e53 101 _state[id].client->send_all(buf, strlen(buf));
mitsarionas 1:f30e7b210e53 102 if (_state[id].keepalive) {
mitsarionas 1:f30e7b210e53 103 strcpy(buf, "Connection: Keep-Alive\r\n");
mitsarionas 1:f30e7b210e53 104 } else {
mitsarionas 1:f30e7b210e53 105 strcpy(buf, "Connection: close\r\n");
mitsarionas 1:f30e7b210e53 106 }
mitsarionas 1:f30e7b210e53 107 _state[id].client->send_all(buf, strlen(buf));
mitsarionas 1:f30e7b210e53 108 sprintf(buf, "Location: %s\r\n\r\n", location);
mitsarionas 1:f30e7b210e53 109 _state[id].client->send_all(buf, strlen(buf));
mitsarionas 1:f30e7b210e53 110 if (header) {
mitsarionas 1:f30e7b210e53 111 _state[id].client->send_all((char*)header, strlen(header));
mitsarionas 1:f30e7b210e53 112 }
mitsarionas 1:f30e7b210e53 113 sprintf(buf, "Content-Length: %d\r\n\r\n", len);
mitsarionas 1:f30e7b210e53 114 _state[id].client->send_all(buf, strlen(buf));
mitsarionas 1:f30e7b210e53 115
mitsarionas 1:f30e7b210e53 116 return _state[id].client->send_all((char*)body, len);
mitsarionas 1:f30e7b210e53 117 }
mitsarionas 1:f30e7b210e53 118
okini3939 0:d18dff347122 119 int HTTPD::getHandler (const char *uri) {
okini3939 0:d18dff347122 120 int i;
okini3939 0:d18dff347122 121
okini3939 0:d18dff347122 122 for (i = 0; i < _handler_count; i ++) {
okini3939 0:d18dff347122 123 if (strncmp(uri, _handler[i].uri, strlen(_handler[i].uri)) == NULL) {
okini3939 0:d18dff347122 124 // found
okini3939 0:d18dff347122 125 return i;
okini3939 0:d18dff347122 126 }
okini3939 0:d18dff347122 127 }
okini3939 0:d18dff347122 128 return -1;
okini3939 0:d18dff347122 129 }
okini3939 0:d18dff347122 130
okini3939 0:d18dff347122 131 int HTTPD::attach (const char *uri, const char *dir) {
okini3939 0:d18dff347122 132 if (_handler_count < HTTPD_MAX_HANDLES) {
okini3939 0:d18dff347122 133 _handler[_handler_count].uri = (char*)malloc(strlen(uri) + 1);
okini3939 0:d18dff347122 134 strcpy(_handler[_handler_count].uri, uri);
okini3939 0:d18dff347122 135 _handler[_handler_count].dir = (char*)malloc(strlen(dir) + 1);
okini3939 0:d18dff347122 136 strcpy(_handler[_handler_count].dir, dir);
okini3939 0:d18dff347122 137 _handler[_handler_count].funcCgi = NULL;
okini3939 0:d18dff347122 138 _handler_count ++;
okini3939 0:d18dff347122 139 return 0;
okini3939 0:d18dff347122 140 } else {
okini3939 0:d18dff347122 141 return -1;
okini3939 0:d18dff347122 142 }
okini3939 0:d18dff347122 143 }
okini3939 0:d18dff347122 144
okini3939 0:d18dff347122 145 int HTTPD::attach (const char *uri, void (*funcCgi)(int)) {
okini3939 0:d18dff347122 146 if (_handler_count < HTTPD_MAX_HANDLES) {
okini3939 0:d18dff347122 147 _handler[_handler_count].uri = (char*)malloc(strlen(uri) + 1);
okini3939 0:d18dff347122 148 strcpy(_handler[_handler_count].uri, uri);
okini3939 0:d18dff347122 149 _handler[_handler_count].dir = NULL;
okini3939 0:d18dff347122 150 _handler[_handler_count].funcCgi = funcCgi;
okini3939 0:d18dff347122 151 _handler_count ++;
okini3939 0:d18dff347122 152 return 0;
okini3939 0:d18dff347122 153 } else {
okini3939 0:d18dff347122 154 return -1;
okini3939 0:d18dff347122 155 }
okini3939 0:d18dff347122 156 }
okini3939 0:d18dff347122 157
okini3939 0:d18dff347122 158
okini3939 0:d18dff347122 159 char *HTTPD::mimetype (char *file) {
okini3939 0:d18dff347122 160 int i, j;
okini3939 0:d18dff347122 161
okini3939 0:d18dff347122 162 for (i = 0; i < MIMETABLE_NUM; i ++) {
okini3939 0:d18dff347122 163 j = strlen(mimetable[i].ext);
okini3939 0:d18dff347122 164 if (file[strlen(file) - j - 1] == '.' &&
okini3939 0:d18dff347122 165 strnicmp(&file[strlen(file) - j], mimetable[i].ext, j) == NULL) {
okini3939 0:d18dff347122 166 return (char*)mimetable[i].type;
okini3939 0:d18dff347122 167 }
okini3939 0:d18dff347122 168 }
okini3939 0:d18dff347122 169 return (char*)mimetable[0].type;
okini3939 0:d18dff347122 170 }
okini3939 0:d18dff347122 171
okini3939 0:d18dff347122 172 int HTTPD::strnicmp (const char *p1, const char *p2, int n) {
okini3939 0:d18dff347122 173 int i, r = -1;
okini3939 0:d18dff347122 174 char c1, c2;
okini3939 0:d18dff347122 175
okini3939 0:d18dff347122 176 for (i = 0; i < n; i ++) {
okini3939 0:d18dff347122 177 c1 = (p1[i] >= 'a' && p1[i] <= 'z') ? p1[i] - ('a' - 'A'): p1[i];
okini3939 0:d18dff347122 178 c2 = (p2[i] >= 'a' && p2[i] <= 'z') ? p2[i] - ('a' - 'A'): p2[i];
okini3939 0:d18dff347122 179 r = c1 - c2;
okini3939 0:d18dff347122 180 if (r) break;
okini3939 0:d18dff347122 181 }
okini3939 0:d18dff347122 182 return r;
okini3939 0:d18dff347122 183 }
okini3939 0:d18dff347122 184
okini3939 0:d18dff347122 185
okini3939 0:d18dff347122 186 /* base64encode code from
okini3939 0:d18dff347122 187 * Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
okini3939 0:d18dff347122 188 */
okini3939 0:d18dff347122 189 int HTTPD::base64encode (const char *input, int length, char *output, int len) {
okini3939 0:d18dff347122 190 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
okini3939 0:d18dff347122 191 unsigned int c, c1, c2, c3;
okini3939 0:d18dff347122 192
okini3939 0:d18dff347122 193 if (len < ((((length-1)/3)+1)<<2)) return -1;
okini3939 0:d18dff347122 194 for(unsigned int i = 0, j = 0; i<length; i+=3,j+=4) {
okini3939 0:d18dff347122 195 c1 = ((((unsigned char)*((unsigned char *)&input[i]))));
okini3939 0:d18dff347122 196 c2 = (length>i+1)?((((unsigned char)*((unsigned char *)&input[i+1])))):0;
okini3939 0:d18dff347122 197 c3 = (length>i+2)?((((unsigned char)*((unsigned char *)&input[i+2])))):0;
okini3939 0:d18dff347122 198
okini3939 0:d18dff347122 199 c = ((c1 & 0xFC) >> 2);
okini3939 0:d18dff347122 200 output[j+0] = base64[c];
okini3939 0:d18dff347122 201 c = ((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4);
okini3939 0:d18dff347122 202 output[j+1] = base64[c];
okini3939 0:d18dff347122 203 c = ((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6);
okini3939 0:d18dff347122 204 output[j+2] = (length>i+1)?base64[c]:'=';
okini3939 0:d18dff347122 205 c = (c3 & 0x3F);
okini3939 0:d18dff347122 206 output[j+3] = (length>i+2)?base64[c]:'=';
okini3939 0:d18dff347122 207 }
okini3939 0:d18dff347122 208 output[(((length-1)/3)+1)<<2] = '\0';
okini3939 0:d18dff347122 209 return 0;
okini3939 0:d18dff347122 210 }
okini3939 0:d18dff347122 211
okini3939 0:d18dff347122 212
okini3939 0:d18dff347122 213 /* urlencode code from
okini3939 0:d18dff347122 214 * Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
okini3939 0:d18dff347122 215 */
okini3939 0:d18dff347122 216 int HTTPD::urlencode (const char *str, char *buf, int len) {
okini3939 0:d18dff347122 217 // char *pstr = str, *buf = (char*)malloc(strlen(str) * 3 + 1), *pbuf = buf;
okini3939 0:d18dff347122 218 const char *pstr = str;
okini3939 0:d18dff347122 219 char *pbuf = buf;
okini3939 0:d18dff347122 220
okini3939 0:d18dff347122 221 if (len < (strlen(str) * 3 + 1)) return -1;
okini3939 0:d18dff347122 222 while (*pstr) {
okini3939 0:d18dff347122 223 if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~')
okini3939 0:d18dff347122 224 *pbuf++ = *pstr;
okini3939 0:d18dff347122 225 else if (*pstr == ' ')
okini3939 0:d18dff347122 226 *pbuf++ = '+';
okini3939 0:d18dff347122 227 else
okini3939 0:d18dff347122 228 *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15);
okini3939 0:d18dff347122 229 pstr++;
okini3939 0:d18dff347122 230 }
okini3939 0:d18dff347122 231 *pbuf = '\0';
okini3939 0:d18dff347122 232 return 0;
okini3939 0:d18dff347122 233 }
okini3939 0:d18dff347122 234
okini3939 0:d18dff347122 235 /* urldecode code from
okini3939 0:d18dff347122 236 * Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
okini3939 0:d18dff347122 237 */
okini3939 0:d18dff347122 238 int HTTPD::urldecode (const char *str, char *buf, int len) {
okini3939 0:d18dff347122 239 // char *pstr = str, *buf = (char*)malloc(strlen(str) + 1), *pbuf = buf;
okini3939 0:d18dff347122 240 const char *pstr = str;
okini3939 0:d18dff347122 241 char *pbuf = buf;
okini3939 0:d18dff347122 242
okini3939 0:d18dff347122 243 if (len < (strlen(str) / 3 - 1)) return -1;
okini3939 0:d18dff347122 244 while (*pstr) {
okini3939 0:d18dff347122 245 if (*pstr == '%') {
okini3939 0:d18dff347122 246 if (pstr[1] && pstr[2]) {
okini3939 0:d18dff347122 247 *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
okini3939 0:d18dff347122 248 pstr += 2;
okini3939 0:d18dff347122 249 }
okini3939 0:d18dff347122 250 } else if (*pstr == '+') {
okini3939 0:d18dff347122 251 *pbuf++ = ' ';
okini3939 0:d18dff347122 252 } else {
okini3939 0:d18dff347122 253 *pbuf++ = *pstr;
okini3939 0:d18dff347122 254 }
okini3939 0:d18dff347122 255 pstr++;
okini3939 0:d18dff347122 256 }
okini3939 0:d18dff347122 257 *pbuf = '\0';
okini3939 0:d18dff347122 258 return 0;
okini3939 0:d18dff347122 259 }
okini3939 0:d18dff347122 260
okini3939 0:d18dff347122 261 int HTTPD::from_hex (int ch) {
okini3939 0:d18dff347122 262 return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
okini3939 0:d18dff347122 263 }
okini3939 0:d18dff347122 264
okini3939 0:d18dff347122 265 int HTTPD::to_hex (int code) {
okini3939 0:d18dff347122 266 static char hex[] = "0123456789abcdef";
okini3939 0:d18dff347122 267 return hex[code & 15];
okini3939 0:d18dff347122 268 }