more handlers

Dependents:   bandwidth-meter-net mbedRail24v

Fork of Tiny-HTTPD by ban4jp -

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HTTPD_ws.cpp Source File

HTTPD_ws.cpp

00001 /* Copyright (C) 2013 Hiroshi Suga, MIT License
00002  *
00003  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00004  * and associated documentation files (the "Software"), to deal in the Software without restriction,
00005  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
00006  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
00007  * furnished to do so, subject to the following conditions:
00008  *
00009  * The above copyright notice and this permission notice shall be included in all copies or
00010  * substantial portions of the Software.
00011  *
00012  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00013  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00014  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00015  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00016  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00017  */
00018 
00019 #include "HTTPD.h"
00020 #include "sha1.h"
00021 
00022 void HTTPD::recvWS (int id, char c) {
00023 
00024     switch (_state[id].mode) {
00025     case MODE_WEBSOCKET:
00026         if (_state[id].n == 0) {
00027             // flag
00028             _state[id].websocket_opcode = c & 0x0f;
00029             _state[id].websocket_flg = c << 8;
00030             _state[id].n ++;
00031         } else
00032         if (_state[id].n == 1) {
00033             // length 7bit
00034             _state[id].websocket_flg |= c;
00035             _state[id].length = c & 0x7f;
00036             _state[id].n ++;
00037             if (_state[id].length < 126) {
00038                 _state[id].n = 0;
00039                 if (_state[id].length) {
00040                     if (_state[id].websocket_flg & 0x0080) {
00041                         _state[id].mode = MODE_WEBSOCKET_MASK;
00042                     } else {
00043                         _state[id].mode = MODE_WEBSOCKET_BODY;
00044                     }
00045                 } else {
00046                     _state[id].mode = MODE_WEBSOCKET_ENTER;
00047                 }
00048                 DBG("ws length %d\r\n", _state[id].length);
00049             }
00050         } else {
00051             // length 16bit,64bit
00052             if (_state[id].n == 2) {
00053                 _state[id].length = c;
00054                 _state[id].n ++;
00055             } else
00056             if (_state[id].n < 9 && (_state[id].websocket_flg & 0x7f) == 127) {
00057                 // 64bit
00058                 _state[id].length = (_state[id].length << 8) | c;
00059                 _state[id].n ++;
00060             } else {
00061                 // end
00062                 _state[id].length = (_state[id].length << 8) | c;
00063                 _state[id].n = 0;
00064                 if (_state[id].websocket_flg & 0x0080) {
00065                     _state[id].mode = MODE_WEBSOCKET_MASK;
00066                 } else {
00067                     _state[id].mode = MODE_WEBSOCKET_BODY;
00068                 }
00069                 DBG("ws length2 %d\r\n", _state[id].length);
00070             }
00071         }
00072         break;
00073     case MODE_WEBSOCKET_MASK:
00074         // masking key
00075         _state[id].websocket_mask[_state[id].n] = c;
00076         _state[id].n ++;
00077         if (_state[id].n >= 4) {
00078             _state[id].n = 0;
00079             _state[id].mode = MODE_WEBSOCKET_BODY;
00080             DBG("ws mask\r\n");
00081         }
00082         break;
00083     case MODE_WEBSOCKET_BODY:
00084         // payload
00085         if (_state[id].websocket_flg & 0x0080) {
00086             // un-mask
00087             _state[id].buf->queue(c ^ _state[id].websocket_mask[_state[id].n & 0x03]); 
00088         } else {
00089             _state[id].buf->queue(c); 
00090         }
00091         _state[id].n ++;
00092         if (_state[id].n >= _state[id].length) {
00093             _state[id].mode = MODE_WEBSOCKET_ENTER;
00094         }
00095         break;
00096     }
00097 }
00098 
00099 int HTTPD::parseWebsocket (int id) {
00100     int i;
00101 
00102     DBG("ws opcode %d\r\n", _state[id].websocket_opcode);
00103     switch (_state[id].websocket_opcode) {
00104     case 0x00: // continuation
00105         break;
00106     case 0x01: // text
00107     case 0x02: // binary
00108         i = getHandler(_state[id].uri);
00109         if (i >= 0) {
00110             if (_handler[i].funcCgi) {
00111                 // cgi
00112                 _handler[i].funcCgi(id);
00113             }
00114         }
00115         break;
00116     case 0x08: // close
00117         _state[id].client->close();
00118         break;
00119     case 0x09: // ping
00120         {
00121         char pong[_state[id].n + 2];
00122         pong[0] = 0x8a;
00123         pong[1] = 0x04;
00124         for (i = 0; i < _state[id].length; i ++) {
00125             if (_state[id].buf->dequeue(&pong[i + 2]) == false) break;
00126         }
00127         _state[id].client->send_all(pong, _state[id].length + 2);
00128         }
00129         break;
00130     case 0x0a: // pong
00131         break;
00132     default:
00133         break;
00134     }
00135     _state[id].n = 0;
00136     _state[id].length = 0;
00137     return 0;
00138 }
00139 
00140 int HTTPD::acceptWebsocket (int id) {
00141     char buf[HTTPD_CMD_SIZE], buf2[HTTPD_CMD_SIZE];
00142     
00143     DBG("websocket accept: %d\r\n", id);
00144 
00145     strcpy(buf, "HTTP/1.1 101 Switching Protocols\r\n");
00146     _state[id].client->send_all(buf, strlen(buf));
00147     strcpy(buf, "Upgrade: websocket\r\n");
00148     _state[id].client->send_all(buf, strlen(buf));
00149     strcpy(buf, "Connection: Upgrade\r\n");
00150     _state[id].client->send_all(buf, strlen(buf));
00151 
00152     strcpy(buf, "Sec-WebSocket-Accept: ");
00153     _state[id].client->send_all(buf, strlen(buf));
00154     strcpy(buf, _state[id].websocket_key);
00155     strcat(buf, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
00156     sha1(buf, strlen(buf), buf2);
00157     base64encode(buf2, 20, buf, sizeof(buf));
00158     _state[id].client->send_all(buf, strlen(buf));
00159     strcpy(buf, "\r\n\r\n");
00160     _state[id].client->send_all(buf, strlen(buf));
00161     _state[id].client->set_blocking(true, HTTPD_TIMEOUT * 100);
00162     return 0;
00163 }
00164 
00165 int HTTPD::sendWebsocket (int id, const char *buf, int len, const char *mask) {
00166     HTTPD *httpd = HTTPD::getInstance();
00167     int i = 0, r;
00168     char tmp[10];
00169 
00170     tmp[i++] = 0x81; // single, text frame
00171     if (len < 126) {
00172         tmp[i++] = (mask == NULL ? 0 : 0x80) | len;
00173     } else {
00174         tmp[i++] = (mask == NULL ? 0 : 0x80) | 126;
00175         tmp[i++] = (len >> 8) & 0xff;
00176         tmp[i++] = len & 0xff;
00177     }
00178     if (mask) {
00179         memcpy(&tmp[i], mask, 4);
00180         i += 4;
00181     }
00182     r = httpd->_state[id].client->send_all(tmp, i);
00183 
00184     if (r >= 0) {
00185         if (mask) {
00186             char tmp2[len];
00187             for (i = 0; i < len; i ++) {
00188                 tmp2[i] = buf[i] ^ mask[i & 0x03];
00189             }
00190             r = httpd->_state[id].client->send_all(tmp2, len);
00191         } else {
00192             r = httpd->_state[id].client->send_all((char*)buf, len);
00193         }
00194     }
00195     return r;
00196 }
00197 
00198