Go to the documentation of this file.
32 #define TRACE_LEVEL WEB_SOCKET_TRACE_LEVEL
48 #if (WEB_SOCKET_SUPPORT == ENABLED)
66 {301,
"Moved Permanently"},
68 {304,
"Not Modified"},
71 {401,
"Unauthorized"},
75 {500,
"Internal Server Error"},
76 {501,
"Not Implemented"},
78 {503,
"Service Unavailable"}
91 webSocket->state = newState;
114 rxContext = &webSocket->rxContext;
148 webSocket->handshakeContext.statusCode = 0;
149 webSocket->handshakeContext.upgradeWebSocket =
FALSE;
150 webSocket->handshakeContext.connectionUpgrade =
FALSE;
151 webSocket->handshakeContext.connectionClose =
FALSE;
152 webSocket->handshakeContext.contentLength = 0;
153 webSocket->handshakeContext.closingFrameSent =
FALSE;
154 webSocket->handshakeContext.closingFrameReceived =
FALSE;
156 #if (WEB_SOCKET_BASIC_AUTH_SUPPORT == ENABLED || WEB_SOCKET_DIGEST_AUTH_SUPPORT == ENABLED)
160 #if (WEB_SOCKET_DIGEST_AUTH_SUPPORT == ENABLED)
161 osStrcpy(webSocket->authContext.nonce,
"");
162 osStrcpy(webSocket->authContext.opaque,
"");
163 webSocket->authContext.stale =
FALSE;
170 osStrcpy(webSocket->handshakeContext.serverKey,
"");
178 osStrcpy(webSocket->handshakeContext.clientKey,
"");
314 if(!error &&
n ==
sizeof(
char_t))
317 if(nextChar ==
' ' || nextChar ==
'\t')
336 rxContext->
buffer[0] = nextChar;
427 webSocket->queryString[0] =
'\0';
439 webSocket->handshakeContext.connectionClose =
TRUE;
447 webSocket->handshakeContext.connectionClose =
TRUE;
455 webSocket->handshakeContext.connectionClose =
FALSE;
522 handshakeContext = &webSocket->handshakeContext;
531 if(separator != NULL)
575 #if (WEB_SOCKET_BASIC_AUTH_SUPPORT == ENABLED || WEB_SOCKET_DIGEST_AUTH_SUPPORT == ENABLED)
619 webSocket->handshakeContext.connectionClose =
FALSE;
624 webSocket->handshakeContext.connectionClose =
TRUE;
629 webSocket->handshakeContext.connectionUpgrade =
TRUE;
651 txContext = &webSocket->txContext;
657 p +=
osSprintf(
p,
"GET %s HTTP/1.1\r\n", webSocket->uri);
660 if(webSocket->host[0] !=
'\0')
664 p +=
osSprintf(
p,
"Host: %s:%d\r\n", webSocket->host, serverPort);
673 #if (WEB_SOCKET_BASIC_AUTH_SUPPORT == ENABLED || WEB_SOCKET_DIGEST_AUTH_SUPPORT == ENABLED)
683 if(webSocket->origin[0] !=
'\0')
685 p +=
osSprintf(
p,
"Origin: %s\r\n", webSocket->origin);
698 if(webSocket->subProtocol[0] !=
'\0')
699 p +=
osSprintf(
p,
"Sec-WebSocket-Protocol: %s\r\n", webSocket->subProtocol);
703 webSocket->handshakeContext.clientKey);
706 p +=
osSprintf(
p,
"Sec-WebSocket-Version: 13\r\n");
737 txContext = &webSocket->txContext;
742 p +=
osSprintf(
p,
"HTTP/1.1 101 Switching Protocols\r\n");
750 if(webSocket->subProtocol[0] !=
'\0')
751 p +=
osSprintf(
p,
"Sec-WebSocket-Protocol: %s\r\n", webSocket->subProtocol);
755 webSocket->handshakeContext.serverKey);
792 static const char_t template[] =
793 "<!doctype html>\r\n"
795 "<head><title>Error %03d</title></head>\r\n"
797 "<h2>Error %03d</h2>\r\n"
803 txContext = &webSocket->txContext;
810 p +=
osSprintf(
p,
"HTTP/%u.%u %u ",
MSB(webSocket->handshakeContext.version),
811 LSB(webSocket->handshakeContext.version), statusCode);
814 for(i = 0; i <
arraysize(statusCodeList); i++)
817 if(statusCodeList[i].
value == statusCode)
830 p +=
osSprintf(
p,
"Content-Type: %s\r\n",
"text/html");
865 TRACE_DEBUG(
"WebSocket: verifying client handshake\r\n");
868 handshakeContext = &webSocket->handshakeContext;
914 TRACE_DEBUG(
"WebSocket: verifying server handshake\r\n");
917 handshakeContext = &webSocket->handshakeContext;
979 TRACE_DEBUG(
"WebSocket: Generating client's key...\r\n");
982 handshakeContext = &webSocket->handshakeContext;
1022 TRACE_DEBUG(
"WebSocket: Generating server's key...\r\n");
1025 handshakeContext = &webSocket->handshakeContext;
1063 TRACE_DEBUG(
"WebSocket: Verifying client's key...\r\n");
1066 buffer = (
char_t *) webSocket->txContext.buffer;
1069 handshakeContext = &webSocket->handshakeContext;
1104 TRACE_DEBUG(
"WebSocket: Verifying server's key...\r\n");
1107 buffer = (
char_t *) webSocket->txContext.buffer;
1110 handshakeContext = &webSocket->handshakeContext;
1128 TRACE_DEBUG(
" Calculated key: %s\r\n", webSocket->txContext.buffer);
1163 else if(statusCode >= 3000)
1186 char_t *output,
size_t outputSize)
1192 if(input == NULL || output == NULL)
1196 for(i = 0; *input !=
'\0' && i < outputSize; i++)
1206 else if(input[0] ==
'%' && input[1] !=
'\0' && input[2] !=
'\0')
1209 buffer[0] = input[1];
1210 buffer[1] = input[2];
1213 output[i] = (uint8_t)
osStrtoul(buffer, NULL, 16);
1248 const uint8_t *
data,
size_t length,
size_t remaining)
1257 for(i = 0; i <
length && valid; i++)
1263 if((
data[i] & 0x80) == 0x00)
1271 else if((
data[i] & 0xE0) == 0xC0)
1279 else if((
data[i] & 0xF0) == 0xE0)
1287 else if((
data[i] & 0xF8) == 0xF0)
1317 if((
data[i] & 0xC0) == 0x80)
#define WEB_SOCKET_BUFFER_SIZE
@ WS_STATUS_CODE_GOING_AWAY
@ WS_STATUS_CODE_UNSUPPORTED_DATA
String manipulation helper functions.
void sha1Update(Sha1Context *context, const void *data, size_t length)
Update the SHA-1 context with a portion of the message being hashed.
#define WEB_SOCKET_CLIENT_KEY_SIZE
SHA-1 (Secure Hash Algorithm 1)
char_t * strTrimWhitespace(char_t *s)
Removes all leading and trailing whitespace from a string.
error_t webSocketFormatErrorResponse(WebSocket *webSocket, uint_t statusCode, const char_t *message)
Format HTTP error response.
WebSocket API (client and server)
HTTP authentication for WebSockets.
bool_t webSocketCheckUtf8Stream(WebSocketUtf8Context *context, const uint8_t *data, size_t length, size_t remaining)
Check whether a an UTF-8 stream is valid.
void base64Encode(const void *input, size_t inputLen, char_t *output, size_t *outputLen)
Base64 encoding algorithm.
Helper functions for WebSockets.
@ WS_STATUS_CODE_NO_STATUS_RCVD
error_t webSocketParseHeaderField(WebSocket *webSocket, char_t *line)
Parse a header field.
void webSocketParseConnectionField(WebSocket *webSocket, char_t *value)
Parse Connection header field.
WebSocket frame parsing and formatting.
const char_t webSocketGuid[]
@ WS_SUB_STATE_HANDSHAKE_HEADER_FIELD
error_t base64Decode(const char_t *input, size_t inputLen, void *output, size_t *outputLen)
Base64 decoding algorithm.
char_t serverKey[WEB_SOCKET_SERVER_KEY_SIZE+1]
@ ERROR_INVALID_PARAMETER
Invalid parameter.
void sha1Init(Sha1Context *context)
Initialize SHA-1 message digest context.
size_t bufferLen
Length of the data buffer.
Frame encoding/decoding context.
#define osSprintf(dest,...)
#define osStrtok_r(s, delim, last)
error_t webSocketGenerateClientKey(WebSocket *webSocket)
Generate client's key.
bool_t webSocketCheckStatusCode(uint16_t statusCode)
Check whether a status code is valid.
@ ERROR_FAILURE
Generic error code.
error_t webSocketVerifyServerKey(WebSocket *webSocket)
Verify server's key.
error_t webSocketReceiveData(WebSocket *webSocket, void *data, size_t size, size_t *received, uint_t flags)
Receive data using the relevant transport protocol.
char_t clientKey[WEB_SOCKET_CLIENT_KEY_SIZE+1]
WebSocketRandCallback webSockRandCallback
#define osStrcasecmp(s1, s2)
error_t webSocketParseStatusLine(WebSocket *webSocket, char_t *line)
Parse the Status-Line of the server's handshake.
@ WS_STATUS_CODE_MESSAGE_TOO_BIG
@ WS_STATUS_CODE_INTERNAL_ERROR
WebSocketState
WebSocket states.
@ WS_SUB_STATE_HANDSHAKE_LEADING_LINE
error_t webSocketFormatClientHandshake(WebSocket *webSocket, uint16_t serverPort)
Format client's handshake.
error_t webSocketVerifyServerHandshake(WebSocket *webSocket)
Verify server's handshake.
@ WS_STATUS_CODE_POLICY_VIOLATION
#define osStrtoul(s, endptr, base)
error_t webSocketFormatServerHandshake(WebSocket *webSocket)
Format server's handshake.
error_t strSafeCopy(char_t *dest, const char_t *src, size_t destSize)
Copy string.
@ WS_STATUS_CODE_INVALID_PAYLOAD_DATA
uint8_t buffer[WEB_SOCKET_BUFFER_SIZE]
Data buffer.
error_t webSocketVerifyClientHandshake(WebSocket *webSocket)
Verify client's handshake.
error_t webSocketParseRequestLine(WebSocket *webSocket, char_t *line)
Parse the Request-Line of the client's handshake.
error_t webSocketDecodePercentEncodedString(const char_t *input, char_t *output, size_t outputSize)
Decode a percent-encoded string.
bool_t fin
Final fragment in a message.
@ WS_STATUS_CODE_MANDATORY_EXT
@ WS_SUB_STATE_HANDSHAKE_LWSP
#define WEB_SOCKET_QUERY_STRING_MAX_LEN
@ WS_STATE_SERVER_HANDSHAKE
#define WEB_SOCKET_SERVER_KEY_SIZE
#define osStrncmp(s1, s2, length)
@ WS_STATUS_CODE_PROTOCOL_ERROR
error_t webSocketParseHandshake(WebSocket *webSocket)
Parse client or server handshake.
WebSocket transport layer.
size_t bufferPos
Current position.
size_t webSocketAddAuthorizationField(WebSocket *webSocket, char_t *output)
Format Authorization header field.
error_t webSocketVerifyClientKey(WebSocket *webSocket)
Verify client's key.
#define WEB_SOCKET_URI_MAX_LEN
error_t webSocketGenerateServerKey(WebSocket *webSocket)
Generate server's key.
void sha1Final(Sha1Context *context, uint8_t *digest)
Finish the SHA-1 message digest.
error_t webSocketParseAuthenticateField(WebSocket *webSocket, char_t *value)
Parse WWW-Authenticate header field.
@ WS_STATUS_CODE_NORMAL_CLOSURE
void webSocketChangeState(WebSocket *webSocket, WebSocketState newState)
Update WebSocket state.
systime_t osGetSystemTime(void)
Retrieve system time.