HTTPD bug fix which is caused by stack overflow.

Dependents:   mbed_controller_demo

Fork of HTTPD by Suga koubou

Original HTTPD implementation of Suga koubou is great but has some bug inside unfortunately. The most critical bug was accessing buffer with the index of out of range like following.

problematic code

char buf[256];

n = httpd->_state[id].client->receive(buf, sizeof(buf));
buf[n] =0;

With above code, it could set buf[256] = 0 when more that 255 data is received. Setting buf[256] causes some other area of memory is corrupted so that system can be predictive status since than.

bug fixed code

n = httpd->_state[id].client->receive(buf, sizeof(buf)-1);
buf[n] =0;
Committer:
hillkim7
Date:
Fri Apr 10 09:04:38 2015 +0000
Revision:
2:584ce0a1a76e
Parent:
0:d18dff347122
Fix critical bug cause by accessing buffer with index of out of range.; Set reasonable stack size for server task.

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 "sha1.h"
okini3939 0:d18dff347122 21
okini3939 0:d18dff347122 22 void HTTPD::recvWS (int id, char c) {
okini3939 0:d18dff347122 23
okini3939 0:d18dff347122 24 switch (_state[id].mode) {
okini3939 0:d18dff347122 25 case MODE_WEBSOCKET:
okini3939 0:d18dff347122 26 if (_state[id].n == 0) {
okini3939 0:d18dff347122 27 // flag
okini3939 0:d18dff347122 28 _state[id].websocket_opcode = c & 0x0f;
okini3939 0:d18dff347122 29 _state[id].websocket_flg = c << 8;
okini3939 0:d18dff347122 30 _state[id].n ++;
okini3939 0:d18dff347122 31 } else
okini3939 0:d18dff347122 32 if (_state[id].n == 1) {
okini3939 0:d18dff347122 33 // length 7bit
okini3939 0:d18dff347122 34 _state[id].websocket_flg |= c;
okini3939 0:d18dff347122 35 _state[id].length = c & 0x7f;
okini3939 0:d18dff347122 36 _state[id].n ++;
okini3939 0:d18dff347122 37 if (_state[id].length < 126) {
okini3939 0:d18dff347122 38 _state[id].n = 0;
okini3939 0:d18dff347122 39 if (_state[id].length) {
okini3939 0:d18dff347122 40 if (_state[id].websocket_flg & 0x0080) {
okini3939 0:d18dff347122 41 _state[id].mode = MODE_WEBSOCKET_MASK;
okini3939 0:d18dff347122 42 } else {
okini3939 0:d18dff347122 43 _state[id].mode = MODE_WEBSOCKET_BODY;
okini3939 0:d18dff347122 44 }
okini3939 0:d18dff347122 45 } else {
okini3939 0:d18dff347122 46 _state[id].mode = MODE_WEBSOCKET_ENTER;
okini3939 0:d18dff347122 47 }
okini3939 0:d18dff347122 48 DBG("ws length %d\r\n", _state[id].length);
okini3939 0:d18dff347122 49 }
okini3939 0:d18dff347122 50 } else {
okini3939 0:d18dff347122 51 // length 16bit,64bit
okini3939 0:d18dff347122 52 if (_state[id].n == 2) {
okini3939 0:d18dff347122 53 _state[id].length = c;
okini3939 0:d18dff347122 54 _state[id].n ++;
okini3939 0:d18dff347122 55 } else
okini3939 0:d18dff347122 56 if (_state[id].n < 9 && (_state[id].websocket_flg & 0x7f) == 127) {
okini3939 0:d18dff347122 57 // 64bit
okini3939 0:d18dff347122 58 _state[id].length = (_state[id].length << 8) | c;
okini3939 0:d18dff347122 59 _state[id].n ++;
okini3939 0:d18dff347122 60 } else {
okini3939 0:d18dff347122 61 // end
okini3939 0:d18dff347122 62 _state[id].length = (_state[id].length << 8) | c;
okini3939 0:d18dff347122 63 _state[id].n = 0;
okini3939 0:d18dff347122 64 if (_state[id].websocket_flg & 0x0080) {
okini3939 0:d18dff347122 65 _state[id].mode = MODE_WEBSOCKET_MASK;
okini3939 0:d18dff347122 66 } else {
okini3939 0:d18dff347122 67 _state[id].mode = MODE_WEBSOCKET_BODY;
okini3939 0:d18dff347122 68 }
okini3939 0:d18dff347122 69 DBG("ws length2 %d\r\n", _state[id].length);
okini3939 0:d18dff347122 70 }
okini3939 0:d18dff347122 71 }
okini3939 0:d18dff347122 72 break;
okini3939 0:d18dff347122 73 case MODE_WEBSOCKET_MASK:
okini3939 0:d18dff347122 74 // masking key
okini3939 0:d18dff347122 75 _state[id].websocket_mask[_state[id].n] = c;
okini3939 0:d18dff347122 76 _state[id].n ++;
okini3939 0:d18dff347122 77 if (_state[id].n >= 4) {
okini3939 0:d18dff347122 78 _state[id].n = 0;
okini3939 0:d18dff347122 79 _state[id].mode = MODE_WEBSOCKET_BODY;
okini3939 0:d18dff347122 80 DBG("ws mask\r\n");
okini3939 0:d18dff347122 81 }
okini3939 0:d18dff347122 82 break;
okini3939 0:d18dff347122 83 case MODE_WEBSOCKET_BODY:
okini3939 0:d18dff347122 84 // payload
okini3939 0:d18dff347122 85 if (_state[id].websocket_flg & 0x0080) {
okini3939 0:d18dff347122 86 // un-mask
okini3939 0:d18dff347122 87 _state[id].buf->queue(c ^ _state[id].websocket_mask[_state[id].n & 0x03]);
okini3939 0:d18dff347122 88 } else {
okini3939 0:d18dff347122 89 _state[id].buf->queue(c);
okini3939 0:d18dff347122 90 }
okini3939 0:d18dff347122 91 _state[id].n ++;
okini3939 0:d18dff347122 92 if (_state[id].n >= _state[id].length) {
okini3939 0:d18dff347122 93 _state[id].mode = MODE_WEBSOCKET_ENTER;
okini3939 0:d18dff347122 94 }
okini3939 0:d18dff347122 95 break;
okini3939 0:d18dff347122 96 }
okini3939 0:d18dff347122 97 }
okini3939 0:d18dff347122 98
okini3939 0:d18dff347122 99 int HTTPD::parseWebsocket (int id) {
okini3939 0:d18dff347122 100 int i;
okini3939 0:d18dff347122 101
okini3939 0:d18dff347122 102 DBG("ws opcode %d\r\n", _state[id].websocket_opcode);
okini3939 0:d18dff347122 103 switch (_state[id].websocket_opcode) {
okini3939 0:d18dff347122 104 case 0x00: // continuation
okini3939 0:d18dff347122 105 break;
okini3939 0:d18dff347122 106 case 0x01: // text
okini3939 0:d18dff347122 107 case 0x02: // binary
okini3939 0:d18dff347122 108 i = getHandler(_state[id].uri);
okini3939 0:d18dff347122 109 if (i >= 0) {
okini3939 0:d18dff347122 110 if (_handler[i].funcCgi) {
okini3939 0:d18dff347122 111 // cgi
okini3939 0:d18dff347122 112 _handler[i].funcCgi(id);
okini3939 0:d18dff347122 113 }
okini3939 0:d18dff347122 114 }
okini3939 0:d18dff347122 115 break;
okini3939 0:d18dff347122 116 case 0x08: // close
okini3939 0:d18dff347122 117 _state[id].client->close();
okini3939 0:d18dff347122 118 break;
okini3939 0:d18dff347122 119 case 0x09: // ping
okini3939 0:d18dff347122 120 {
okini3939 0:d18dff347122 121 char pong[_state[id].n + 2];
okini3939 0:d18dff347122 122 pong[0] = 0x8a;
okini3939 0:d18dff347122 123 pong[1] = 0x04;
okini3939 0:d18dff347122 124 for (i = 0; i < _state[id].length; i ++) {
okini3939 0:d18dff347122 125 if (_state[id].buf->dequeue(&pong[i + 2]) == false) break;
okini3939 0:d18dff347122 126 }
okini3939 0:d18dff347122 127 _state[id].client->send_all(pong, _state[id].length + 2);
okini3939 0:d18dff347122 128 }
okini3939 0:d18dff347122 129 break;
okini3939 0:d18dff347122 130 case 0x0a: // pong
okini3939 0:d18dff347122 131 break;
okini3939 0:d18dff347122 132 default:
okini3939 0:d18dff347122 133 break;
okini3939 0:d18dff347122 134 }
okini3939 0:d18dff347122 135 _state[id].n = 0;
okini3939 0:d18dff347122 136 _state[id].length = 0;
okini3939 0:d18dff347122 137 return 0;
okini3939 0:d18dff347122 138 }
okini3939 0:d18dff347122 139
okini3939 0:d18dff347122 140 int HTTPD::acceptWebsocket (int id) {
okini3939 0:d18dff347122 141 char buf[HTTPD_CMD_SIZE], buf2[HTTPD_CMD_SIZE];
okini3939 0:d18dff347122 142
okini3939 0:d18dff347122 143 DBG("websocket accept: %d\r\n", id);
okini3939 0:d18dff347122 144
okini3939 0:d18dff347122 145 strcpy(buf, "HTTP/1.1 101 Switching Protocols\r\n");
okini3939 0:d18dff347122 146 _state[id].client->send_all(buf, strlen(buf));
okini3939 0:d18dff347122 147 strcpy(buf, "Upgrade: websocket\r\n");
okini3939 0:d18dff347122 148 _state[id].client->send_all(buf, strlen(buf));
okini3939 0:d18dff347122 149 strcpy(buf, "Connection: Upgrade\r\n");
okini3939 0:d18dff347122 150 _state[id].client->send_all(buf, strlen(buf));
okini3939 0:d18dff347122 151
okini3939 0:d18dff347122 152 strcpy(buf, "Sec-WebSocket-Accept: ");
okini3939 0:d18dff347122 153 _state[id].client->send_all(buf, strlen(buf));
okini3939 0:d18dff347122 154 strcpy(buf, _state[id].websocket_key);
okini3939 0:d18dff347122 155 strcat(buf, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
okini3939 0:d18dff347122 156 sha1(buf, strlen(buf), buf2);
okini3939 0:d18dff347122 157 base64encode(buf2, 20, buf, sizeof(buf));
okini3939 0:d18dff347122 158 _state[id].client->send_all(buf, strlen(buf));
okini3939 0:d18dff347122 159 strcpy(buf, "\r\n\r\n");
okini3939 0:d18dff347122 160 _state[id].client->send_all(buf, strlen(buf));
okini3939 0:d18dff347122 161 _state[id].client->set_blocking(true, HTTPD_TIMEOUT * 100);
okini3939 0:d18dff347122 162 return 0;
okini3939 0:d18dff347122 163 }
okini3939 0:d18dff347122 164
okini3939 0:d18dff347122 165 int HTTPD::sendWebsocket (int id, const char *buf, int len, const char *mask) {
okini3939 0:d18dff347122 166 HTTPD *httpd = HTTPD::getInstance();
okini3939 0:d18dff347122 167 int i = 0, r;
okini3939 0:d18dff347122 168 char tmp[10];
okini3939 0:d18dff347122 169
okini3939 0:d18dff347122 170 tmp[i++] = 0x81; // single, text frame
okini3939 0:d18dff347122 171 if (len < 126) {
okini3939 0:d18dff347122 172 tmp[i++] = (mask == NULL ? 0 : 0x80) | len;
okini3939 0:d18dff347122 173 } else {
okini3939 0:d18dff347122 174 tmp[i++] = (mask == NULL ? 0 : 0x80) | 126;
okini3939 0:d18dff347122 175 tmp[i++] = (len >> 8) & 0xff;
okini3939 0:d18dff347122 176 tmp[i++] = len & 0xff;
okini3939 0:d18dff347122 177 }
okini3939 0:d18dff347122 178 if (mask) {
okini3939 0:d18dff347122 179 memcpy(&tmp[i], mask, 4);
okini3939 0:d18dff347122 180 i += 4;
okini3939 0:d18dff347122 181 }
okini3939 0:d18dff347122 182 r = httpd->_state[id].client->send_all(tmp, i);
okini3939 0:d18dff347122 183
okini3939 0:d18dff347122 184 if (r >= 0) {
okini3939 0:d18dff347122 185 if (mask) {
okini3939 0:d18dff347122 186 char tmp2[len];
okini3939 0:d18dff347122 187 for (i = 0; i < len; i ++) {
okini3939 0:d18dff347122 188 tmp2[i] = buf[i] ^ mask[i & 0x03];
okini3939 0:d18dff347122 189 }
okini3939 0:d18dff347122 190 r = httpd->_state[id].client->send_all(tmp2, len);
okini3939 0:d18dff347122 191 } else {
okini3939 0:d18dff347122 192 r = httpd->_state[id].client->send_all((char*)buf, len);
okini3939 0:d18dff347122 193 }
okini3939 0:d18dff347122 194 }
okini3939 0:d18dff347122 195 return r;
okini3939 0:d18dff347122 196 }
okini3939 0:d18dff347122 197
okini3939 0:d18dff347122 198