https://github.com/php-ion/websocket-parser
Streaming websocket frame parser and frame builder for c
https://github.com/php-ion/websocket-parser
builder c parser rfc6455 websocket websocket-parser
Last synced: 4 months ago
JSON representation
Streaming websocket frame parser and frame builder for c
- Host: GitHub
- URL: https://github.com/php-ion/websocket-parser
- Owner: php-ion
- License: bsd-3-clause
- Created: 2016-01-20T10:33:23.000Z (almost 10 years ago)
- Default Branch: master
- Last Pushed: 2019-05-08T14:07:02.000Z (over 6 years ago)
- Last Synced: 2025-04-03T05:12:20.817Z (9 months ago)
- Topics: builder, c, parser, rfc6455, websocket, websocket-parser
- Language: C
- Homepage:
- Size: 38.1 KB
- Stars: 67
- Watchers: 6
- Forks: 22
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Authors: AUTHORS
Awesome Lists containing this project
README
WebSocket frame parser and builder
----------------------------------
This is a parser and builder for WebSocket messages (see [RFC6455](https://tools.ietf.org/html/rfc6455)) written in C.
Table of Contents
-----------------
* [Features](#features)
* [Status](#status)
* [Usage](#usage)
* [Frame builder](#frame-builder)
* [UUID](#uuid)
* [Frame example](#frame-example)
Features
--------
* Fast parsing and building of websocket messages
* No dependencies
* No internal buffering
* No need to buffer the whole frame — works with chunks of a data
* No syscalls
* No allocations
* It can be interrupted at anytime
Tested as part of [PHP-ION](https://github.com/php-ion/php-ion) extension.
Inspired by [http-parser](https://github.com/joyent/http-parser) by [Ryan Dahl](https://github.com/ry)
and [multipart-parser](https://github.com/iafonov/multipart-parser-c) by [Igor Afonov](https://github.com/iafonov).
Status
------
Production ready.
Usage
-----
Use [http-parser](https://github.com/joyent/http-parser) for parsing headers. This library parse only websocket frames.
This parser library works with several callbacks, which the user may set up at application initialization time.
```c
websocket_parser_settings settings;
websocket_parser_settings_init(&settings);
settings.on_frame_header = websocket_frame_header;
settings.on_frame_body = websocket_frame_body;
settings.on_frame_end = websocket_frame_end;
```
These functions must match the signatures defined in the websocket-parser header file.
Returning a value other than 0 from the callbacks will abort message processing.
One websocket_parser object is used per TCP connection. Initialize `websocket_parser` struct using `websocket_parser_init()` and set callbacks:
```c
websocket_parser_settings settings;
websocket_parser_settings_init(&settings);
settings.on_frame_header = websocket_frame_header;
settings.on_frame_body = websocket_frame_body;
settings.on_frame_end = websocket_frame_end;
parser = malloc(sizeof(websocket_parser));
websocket_parser_init(parser);
// Attention! Sets your after websocket_parser_init
parser->data = my_frame_struct;
```
Basically, callback looks like that:
```c
int websocket_frame_header(websocket_parser * parser) {
parser->data->opcode = parser->flags & WS_OP_MASK; // gets opcode
parser->data->is_final = parser->flags & WS_FIN; // checks is final frame
if(parser->length) {
parser->data->body = malloc(parser->length); // allocate memory for frame body, if body exists
}
return 0;
}
int ion_websocket_frame_body(websocket_parser * parser, const char *at, size_t size) {
if(parser->flags & WS_HAS_MASK) {
// if frame has mask, we have to copy and decode data via websocket_parser_copy_masked function
websocket_parser_decode(&parser->data->body[parser->offset], at, length, parser);
} else {
memcpy(&parser->data->body[parser->offset], at, length);
}
return 0;
}
int websocket_frame_end(websocket_parser * parser) {
my_app_push_frame(parser->data); // use parsed frame
}
```
When data is received execute the parser and check for errors.
```c
size_t nread;
// .. init settitngs and parser ...
nread = websocket_parser_execute(parser, &settings, data, data_len);
if(nread != data_len) {
// some callback return a value other than 0
}
// ...
free(parser);
```
Frame builder
-------------
To calculate how many bytes to allocate for a frame, use the `websocket_calc_frame_size` function:
```c
size_t frame_len = websocket_calc_frame_size(WS_OP_TEXT | WS_FINAL_FRAME | WS_HAS_MASK, data_len);
char * frame = malloc(sizeof(char) * frame_len);
```
After that you can build a frame
```c
websocket_build_frame(frame, WS_OP_TEXT | WS_FINAL_FRAME | WS_HAS_MASK, mask, data, data_len);
```
and send binary string to the socket
```c
write(sock, frame, frame_len);
```
UUID
----
Macros WEBSOCKET_UUID contains unique ID for handshake
```c
#define WEBSOCKET_UUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
```
Frame example
-------------
There is binary websocket frame example:
* Raw frame: `\x81\x8Amask\x0B\x13\x12\x06\x08\x41\x17\x0A\x19\x00`
* Has mask: yes
* Mask: `mask`
* Payload: `frame data`
* Fin: yes
* Opcode: `WS_OP_TEXT`