+static int httpHandleWebSocket(struct HttpConnection *http, int offset,
+ const char *buf, int bytes) {
+ check(http->websocketHandler);
+ int ch = 0x00;
+ while (bytes > offset) {
+ if (http->websocketType & WS_UNDEFINED) {
+ ch = httpGetChar(http, buf, bytes, &offset);
+ check(ch >= 0);
+ if (http->websocketType & 0xFF) {
+ // Reading another byte of length information.
+ if (http->expecting > 0xFFFFFF) {
+ return 0;
+ }
+ http->expecting = (128 * http->expecting) + (ch & 0x7F);
+ if ((ch & 0x80) == 0) {
+ // Done reading length information.
+ http->websocketType &= ~WS_UNDEFINED;
+
+ // ch is used to detect when we read the terminating byte in text
+ // mode. In binary mode, it must be set to something other than 0xFF.
+ ch = 0x00;
+ }
+ } else {
+ // Reading first byte of frame.
+ http->websocketType = (ch & 0xFF) | WS_START_OF_FRAME;
+ if (ch & 0x80) {
+ // For binary data, we have to read the length before we can start
+ // processing payload.
+ http->websocketType |= WS_UNDEFINED;
+ http->expecting = 0;
+ }
+ }
+ } else if (http->websocketType & 0x80) {
+ // Binary data
+ if (http->expecting) {
+ if (offset < 0) {
+ handle_partial:
+ check(-offset <= http->partialLength);
+ int len = -offset;
+ if (len >= http->expecting) {
+ len = http->expecting;
+ http->websocketType |= WS_END_OF_FRAME;
+ }
+ if (len &&
+ http->websocketHandler(http, http->arg, http->websocketType,
+ http->partial + http->partialLength + offset,
+ len) != HTTP_DONE) {
+ return 0;
+ }
+
+ if (ch == 0xFF) {
+ // In text mode, we jump to handle_partial, when we find the
+ // terminating 0xFF byte. If so, we should try to consume it now.
+ if (len < http->partialLength) {
+ len++;
+ http->websocketType = WS_UNDEFINED;
+ }
+ }
+
+ if (len == http->partialLength) {
+ free(http->partial);
+ http->partial = NULL;
+ http->partialLength = 0;
+ } else {
+ memmove(http->partial, http->partial + len,
+ http->partialLength - len);
+ http->partialLength -= len;
+ }
+ offset += len;
+ http->expecting -= len;
+ } else {
+ handle_buffered:;
+ int len = bytes - offset;
+ if (len >= http->expecting) {
+ len = http->expecting;
+ http->websocketType |= WS_END_OF_FRAME;
+ }
+ if (len &&
+ http->websocketHandler(http, http->arg, http->websocketType,
+ buf + offset, len) != HTTP_DONE) {
+ return 0;
+ }
+
+ if (ch == 0xFF) {
+ // In text mode, we jump to handle_buffered, when we find the
+ // terminating 0xFF byte. If so, we should consume it now.
+ check(offset + len < bytes);
+ len++;
+ http->websocketType = WS_UNDEFINED;
+ }
+ offset += len;
+ http->expecting -= len;
+ }
+ http->websocketType &= ~(WS_START_OF_FRAME | WS_END_OF_FRAME);
+ } else {
+ // Read all data. Go back to looking for a new frame header.
+ http->websocketType = WS_UNDEFINED;
+ }
+ } else {
+ // Process text data until we find a 0xFF bytes.
+ int i = offset;
+
+ // If we have partial data, process that first.
+ while (i < 0) {
+ ch = httpGetChar(http, buf, bytes, &i);
+ check(ch != -1);
+
+ // Terminate when we either find the 0xFF, or we have reached the end
+ // of partial data.
+ if (ch == 0xFF || !i) {
+ // Set WS_END_OF_FRAME, iff we have found the 0xFF marker.
+ http->expecting = i - offset - (ch == 0xFF);
+ goto handle_partial;
+ }
+ }
+
+ // Read all remaining buffered bytes (i.e. positive offset).
+ while (bytes > i) {
+ ch = httpGetChar(http, buf, bytes, &i);
+ check(ch != -1);
+
+ // Terminate when we either find the 0xFF, or we have reached the end
+ // of buffered data.
+ if (ch == 0xFF || bytes == i) {
+ // Set WS_END_OF_FRAME, iff we have found the 0xFF marker.
+ http->expecting = i - offset - (ch == 0xFF);
+ goto handle_buffered;
+ }
+ }
+ }
+ }
+ return 1;
+}
+