BVB Source Codes

uWebSockets Show HTTPSocket.cpp Source code

Return Download uWebSockets: download HTTPSocket.cpp Source code - Download uWebSockets Source code - Type:.cpp
  1. #include "HTTPSocket.h"
  2. #include "Group.h"
  3. #include "Extensions.h"
  4. #include <cstdio>
  5.  
  6. #define MAX_HEADERS 100
  7. #define MAX_HEADER_BUFFER_SIZE 4096
  8. #define FORCE_SLOW_PATH false
  9.  
  10. namespace uWS {
  11.  
  12. // UNSAFETY NOTE: assumes *end == '\r' (might unref end pointer)
  13. char *getHeaders(char *buffer, char *end, Header *headers, size_t maxHeaders) {
  14.     for (unsigned int i = 0; i < maxHeaders; i++) {
  15.         for (headers->key = buffer; (*buffer != ':') & (*buffer > 32); *(buffer++) |= 32);
  16.         if (*buffer == '\r') {
  17.             if ((buffer != end) & (buffer[1] == '\n') & (i > 0)) {
  18.                 headers->key = nullptr;
  19.                 return buffer + 2;
  20.             } else {
  21.                 return nullptr;
  22.             }
  23.         } else {
  24.             headers->keyLength = buffer - headers->key;
  25.             for (buffer++; (*buffer == ':' || *buffer < 33) && *buffer != '\r'; buffer++);
  26.             headers->value = buffer;
  27.             buffer = (char *) memchr(buffer, '\r', end - buffer); //for (; *buffer != '\r'; buffer++);
  28.             if (buffer /*!= end*/ && buffer[1] == '\n') {
  29.                 headers->valueLength = buffer - headers->value;
  30.                 buffer += 2;
  31.                 headers++;
  32.             } else {
  33.                 return nullptr;
  34.             }
  35.         }
  36.     }
  37.     return nullptr;
  38. }
  39.  
  40. // UNSAFETY NOTE: assumes 24 byte input length
  41. static void base64(unsigned char *src, char *dst) {
  42.     static const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  43.     for (int i = 0; i < 18; i += 3) {
  44.         *dst++ = b64[(src[i] >> 2) & 63];
  45.         *dst++ = b64[((src[i] & 3) << 4) | ((src[i + 1] & 240) >> 4)];
  46.         *dst++ = b64[((src[i + 1] & 15) << 2) | ((src[i + 2] & 192) >> 6)];
  47.         *dst++ = b64[src[i + 2] & 63];
  48.     }
  49.     *dst++ = b64[(src[18] >> 2) & 63];
  50.     *dst++ = b64[((src[18] & 3) << 4) | ((src[19] & 240) >> 4)];
  51.     *dst++ = b64[((src[19] & 15) << 2)];
  52.     *dst++ = '=';
  53. }
  54.  
  55. template <bool isServer>
  56. uS::Socket *HttpSocket<isServer>::onData(uS::Socket *s, char *data, size_t length) {
  57.     HttpSocket<isServer> *httpSocket = (HttpSocket<isServer> *) s;
  58.  
  59.     httpSocket->cork(true);
  60.  
  61.     if (httpSocket->contentLength) {
  62.         httpSocket->missedDeadline = false;
  63.         if (httpSocket->contentLength >= length) {
  64.             Group<isServer>::from(httpSocket)->httpDataHandler(httpSocket->outstandingResponsesTail, data, length, httpSocket->contentLength -= length);
  65.             return httpSocket;
  66.         } else {
  67.             Group<isServer>::from(httpSocket)->httpDataHandler(httpSocket->outstandingResponsesTail, data, httpSocket->contentLength, 0);
  68.             data += httpSocket->contentLength;
  69.             length -= httpSocket->contentLength;
  70.             httpSocket->contentLength = 0;
  71.         }
  72.     }
  73.  
  74.     if (FORCE_SLOW_PATH || httpSocket->httpBuffer.length()) {
  75.         if (httpSocket->httpBuffer.length() + length > MAX_HEADER_BUFFER_SIZE) {
  76.             httpSocket->onEnd(httpSocket);
  77.             return httpSocket;
  78.         }
  79.  
  80.         httpSocket->httpBuffer.reserve(httpSocket->httpBuffer.length() + length + WebSocketProtocol<uWS::CLIENT, WebSocket<uWS::CLIENT>>::CONSUME_POST_PADDING);
  81.         httpSocket->httpBuffer.append(data, length);
  82.         data = (char *) httpSocket->httpBuffer.data();
  83.         length = httpSocket->httpBuffer.length();
  84.     }
  85.  
  86.     char *end = data + length;
  87.     char *cursor = data;
  88.     *end = '\r';
  89.     Header headers[MAX_HEADERS];
  90.     do {
  91.         char *lastCursor = cursor;
  92.         if ((cursor = getHeaders(cursor, end, headers, MAX_HEADERS))) {
  93.             HttpRequest req(headers);
  94.  
  95.             if (isServer) {
  96.                 headers->valueLength = std::max<int>(0, headers->valueLength - 9);
  97.                 httpSocket->missedDeadline = false;
  98.                 if (req.getHeader("upgrade", 7)) {
  99.                     if (Group<SERVER>::from(httpSocket)->httpUpgradeHandler) {
  100.                         Group<SERVER>::from(httpSocket)->httpUpgradeHandler((HttpSocket<SERVER> *) httpSocket, req);
  101.                     } else {
  102.                         Header secKey = req.getHeader("sec-websocket-key", 17);
  103.                         Header extensions = req.getHeader("sec-websocket-extensions", 24);
  104.                         Header subprotocol = req.getHeader("sec-websocket-protocol", 22);
  105.                         if (secKey.valueLength == 24) {
  106.                             bool perMessageDeflate;
  107.                             httpSocket->upgrade(secKey.value, extensions.value, extensions.valueLength,
  108.                                                subprotocol.value, subprotocol.valueLength, &perMessageDeflate);
  109.                             Group<isServer>::from(httpSocket)->removeHttpSocket(httpSocket);
  110.  
  111.                             // Warning: changes socket, needs to inform the stack of Poll address change!
  112.                             WebSocket<isServer> *webSocket = new WebSocket<isServer>(perMessageDeflate, httpSocket);
  113.                             webSocket->template setState<WebSocket<isServer>>();
  114.                             webSocket->change(webSocket->nodeData->loop, webSocket, webSocket->setPoll(UV_READABLE));
  115.                             Group<isServer>::from(webSocket)->addWebSocket(webSocket);
  116.  
  117.                             webSocket->cork(true);
  118.                             Group<isServer>::from(webSocket)->connectionHandler(webSocket, req);
  119.                             // todo: should not uncork if closed!
  120.                             webSocket->cork(false);
  121.                             delete httpSocket;
  122.  
  123.                             return webSocket;
  124.                         } else {
  125.                             httpSocket->onEnd(httpSocket);
  126.                         }
  127.                     }
  128.                     return httpSocket;
  129.                 } else {
  130.                     if (Group<SERVER>::from(httpSocket)->httpRequestHandler) {
  131.  
  132.                         HttpResponse *res = HttpResponse::allocateResponse(httpSocket);
  133.                         if (httpSocket->outstandingResponsesTail) {
  134.                             httpSocket->outstandingResponsesTail->next = res;
  135.                         } else {
  136.                             httpSocket->outstandingResponsesHead = res;
  137.                         }
  138.                         httpSocket->outstandingResponsesTail = res;
  139.  
  140.                         Header contentLength;
  141.                         if (req.getMethod() != HttpMethod::METHOD_GET && (contentLength = req.getHeader("content-length", 14))) {
  142.                             httpSocket->contentLength = atoi(contentLength.value);
  143.                             size_t bytesToRead = std::min<int>(httpSocket->contentLength, end - cursor);
  144.                             Group<SERVER>::from(httpSocket)->httpRequestHandler(res, req, cursor, bytesToRead, httpSocket->contentLength -= bytesToRead);
  145.                             cursor += bytesToRead;
  146.                         } else {
  147.                             Group<SERVER>::from(httpSocket)->httpRequestHandler(res, req, nullptr, 0, 0);
  148.                         }
  149.  
  150.                         if (httpSocket->isClosed() || httpSocket->isShuttingDown()) {
  151.                             return httpSocket;
  152.                         }
  153.                     } else {
  154.                         httpSocket->onEnd(httpSocket);
  155.                         return httpSocket;
  156.                     }
  157.                 }
  158.             } else {
  159.                 if (req.getHeader("upgrade", 7)) {
  160.  
  161.                     // Warning: changes socket, needs to inform the stack of Poll address change!
  162.                     WebSocket<isServer> *webSocket = new WebSocket<isServer>(false, httpSocket);
  163.                     httpSocket->cancelTimeout();
  164.                     webSocket->setUserData(httpSocket->httpUser);
  165.                     webSocket->template setState<WebSocket<isServer>>();
  166.                     webSocket->change(webSocket->nodeData->loop, webSocket, webSocket->setPoll(UV_READABLE));
  167.                     Group<isServer>::from(webSocket)->addWebSocket(webSocket);
  168.  
  169.                     webSocket->cork(true);
  170.                     Group<isServer>::from(webSocket)->connectionHandler(webSocket, req);
  171.                     if (!(webSocket->isClosed() || webSocket->isShuttingDown())) {
  172.                         WebSocketProtocol<isServer, WebSocket<isServer>>::consume(cursor, end - cursor, webSocket);
  173.                     }
  174.                     webSocket->cork(false);
  175.                     delete httpSocket;
  176.  
  177.                     return webSocket;
  178.                 } else {
  179.                     httpSocket->onEnd(httpSocket);
  180.                 }
  181.                 return httpSocket;
  182.             }
  183.         } else {
  184.             if (!httpSocket->httpBuffer.length()) {
  185.                 if (length > MAX_HEADER_BUFFER_SIZE) {
  186.                     httpSocket->onEnd(httpSocket);
  187.                 } else {
  188.                     httpSocket->httpBuffer.append(lastCursor, end - lastCursor);
  189.                 }
  190.             }
  191.             return httpSocket;
  192.         }
  193.     } while(cursor != end);
  194.  
  195.     httpSocket->cork(false);
  196.     httpSocket->httpBuffer.clear();
  197.  
  198.     return httpSocket;
  199. }
  200.  
  201. // todo: make this into a transformer and make use of sendTransformed
  202. template <bool isServer>
  203. void HttpSocket<isServer>::upgrade(const char *secKey, const char *extensions, size_t extensionsLength,
  204.                                    const char *subprotocol, size_t subprotocolLength, bool *perMessageDeflate) {
  205.  
  206.     Queue::Message *messagePtr;
  207.  
  208.     if (isServer) {
  209.         *perMessageDeflate = false;
  210.         std::string extensionsResponse;
  211.         if (extensionsLength) {
  212.             Group<isServer> *group = Group<isServer>::from(this);
  213.             ExtensionsNegotiator<uWS::SERVER> extensionsNegotiator(group->extensionOptions);
  214.             extensionsNegotiator.readOffer(std::string(extensions, extensionsLength));
  215.             extensionsResponse = extensionsNegotiator.generateOffer();
  216.             if (extensionsNegotiator.getNegotiatedOptions() & PERMESSAGE_DEFLATE) {
  217.                 *perMessageDeflate = true;
  218.             }
  219.         }
  220.  
  221.         unsigned char shaInput[] = "XXXXXXXXXXXXXXXXXXXXXXXX258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
  222.         memcpy(shaInput, secKey, 24);
  223.         unsigned char shaDigest[SHA_DIGEST_LENGTH];
  224.         SHA1(shaInput, sizeof(shaInput) - 1, shaDigest);
  225.  
  226.         char upgradeBuffer[1024];
  227.         memcpy(upgradeBuffer, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ", 97);
  228.         base64(shaDigest, upgradeBuffer + 97);
  229.         memcpy(upgradeBuffer + 125, "\r\n", 2);
  230.         size_t upgradeResponseLength = 127;
  231.         if (extensionsResponse.length() && extensionsResponse.length() < 200) {
  232.             memcpy(upgradeBuffer + upgradeResponseLength, "Sec-WebSocket-Extensions: ", 26);
  233.             memcpy(upgradeBuffer + upgradeResponseLength + 26, extensionsResponse.data(), extensionsResponse.length());
  234.             memcpy(upgradeBuffer + upgradeResponseLength + 26 + extensionsResponse.length(), "\r\n", 2);
  235.             upgradeResponseLength += 26 + extensionsResponse.length() + 2;
  236.         }
  237.         if (subprotocolLength && subprotocolLength < 200) {
  238.             memcpy(upgradeBuffer + upgradeResponseLength, "Sec-WebSocket-Protocol: ", 24);
  239.             memcpy(upgradeBuffer + upgradeResponseLength + 24, subprotocol, subprotocolLength);
  240.             memcpy(upgradeBuffer + upgradeResponseLength + 24 + subprotocolLength, "\r\n", 2);
  241.             upgradeResponseLength += 24 + subprotocolLength + 2;
  242.         }
  243.         static char stamp[] = "Sec-WebSocket-Version: 13\r\nWebSocket-Server: uWebSockets\r\n\r\n";
  244.         memcpy(upgradeBuffer + upgradeResponseLength, stamp, sizeof(stamp) - 1);
  245.         upgradeResponseLength += sizeof(stamp) - 1;
  246.  
  247.         messagePtr = allocMessage(upgradeResponseLength, upgradeBuffer);
  248.     } else {
  249.         messagePtr = allocMessage(httpBuffer.length(), httpBuffer.data());
  250.         httpBuffer.clear();
  251.     }
  252.  
  253.     bool wasTransferred;
  254.     if (write(messagePtr, wasTransferred)) {
  255.         if (!wasTransferred) {
  256.             freeMessage(messagePtr);
  257.         } else {
  258.             messagePtr->callback = nullptr;
  259.         }
  260.     } else {
  261.         freeMessage(messagePtr);
  262.     }
  263. }
  264.  
  265. template <bool isServer>
  266. void HttpSocket<isServer>::onEnd(uS::Socket *s) {
  267.     HttpSocket<isServer> *httpSocket = (HttpSocket<isServer> *) s;
  268.  
  269.     if (!httpSocket->isShuttingDown()) {
  270.         if (isServer) {
  271.             Group<isServer>::from(httpSocket)->removeHttpSocket(httpSocket);
  272.             Group<isServer>::from(httpSocket)->httpDisconnectionHandler(httpSocket);
  273.         }
  274.     } else {
  275.         httpSocket->cancelTimeout();
  276.     }
  277.  
  278.     httpSocket->template closeSocket<HttpSocket<isServer>>();
  279.  
  280.     while (!httpSocket->messageQueue.empty()) {
  281.         Queue::Message *message = httpSocket->messageQueue.front();
  282.         if (message->callback) {
  283.             message->callback(nullptr, message->callbackData, true, nullptr);
  284.         }
  285.         httpSocket->messageQueue.pop();
  286.     }
  287.  
  288.     while (httpSocket->outstandingResponsesHead) {
  289.         Group<isServer>::from(httpSocket)->httpCancelledRequestHandler(httpSocket->outstandingResponsesHead);
  290.         HttpResponse *next = httpSocket->outstandingResponsesHead->next;
  291.         delete httpSocket->outstandingResponsesHead;
  292.         httpSocket->outstandingResponsesHead = next;
  293.     }
  294.  
  295.     if (httpSocket->preAllocatedResponse) {
  296.         delete httpSocket->preAllocatedResponse;
  297.     }
  298.  
  299.     httpSocket->nodeData->clearPendingPollChanges(httpSocket);
  300.  
  301.     if (!isServer) {
  302.         httpSocket->cancelTimeout();
  303.         Group<CLIENT>::from(httpSocket)->errorHandler(httpSocket->httpUser);
  304.     }
  305. }
  306.  
  307. template struct HttpSocket<SERVER>;
  308. template struct HttpSocket<CLIENT>;
  309.  
  310. }
  311.  
downloadHTTPSocket.cpp Source code - Download uWebSockets Source code
Related Source Codes/Software:
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
postal - 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11

 Back to top