| #include "private-libwebsockets.h" |
| |
| #include "extension-deflate-frame.h" |
| #include "extension-deflate-stream.h" |
| |
| struct libwebsocket_extension libwebsocket_internal_extensions[] = { |
| #ifdef LWS_EXT_DEFLATE_STREAM |
| { |
| "deflate-stream", |
| lws_extension_callback_deflate_stream, |
| sizeof(struct lws_ext_deflate_stream_conn) |
| }, |
| #else |
| { |
| "x-webkit-deflate-frame", |
| lws_extension_callback_deflate_frame, |
| sizeof(struct lws_ext_deflate_frame_conn) |
| }, |
| { |
| "deflate-frame", |
| lws_extension_callback_deflate_frame, |
| sizeof(struct lws_ext_deflate_frame_conn) |
| }, |
| #endif |
| { /* terminator */ |
| NULL, NULL, 0 |
| } |
| }; |
| |
| LWS_VISIBLE void |
| lws_context_init_extensions(struct lws_context_creation_info *info, |
| struct libwebsocket_context *context) |
| { |
| context->extensions = info->extensions; |
| lwsl_info(" LWS_MAX_EXTENSIONS_ACTIVE: %u\n", LWS_MAX_EXTENSIONS_ACTIVE); |
| } |
| |
| LWS_VISIBLE struct libwebsocket_extension *libwebsocket_get_internal_extensions() |
| { |
| return libwebsocket_internal_extensions; |
| } |
| |
| |
| /* 0 = nobody had nonzero return, 1 = somebody had positive return, -1 = fail */ |
| |
| int lws_ext_callback_for_each_active(struct libwebsocket *wsi, int reason, |
| void *arg, int len) |
| { |
| int n, m, handled = 0; |
| |
| for (n = 0; n < wsi->count_active_extensions; n++) { |
| m = wsi->active_extensions[n]->callback( |
| wsi->protocol->owning_server, |
| wsi->active_extensions[n], wsi, |
| reason, |
| wsi->active_extensions_user[n], |
| arg, len); |
| if (m < 0) { |
| lwsl_ext( |
| "Extension '%s' failed to handle callback %d!\n", |
| wsi->active_extensions[n]->name, reason); |
| return -1; |
| } |
| if (m > handled) |
| handled = m; |
| } |
| |
| return handled; |
| } |
| |
| int lws_ext_callback_for_each_extension_type( |
| struct libwebsocket_context *context, struct libwebsocket *wsi, |
| int reason, void *arg, int len) |
| { |
| int n = 0, m, handled = 0; |
| struct libwebsocket_extension *ext = context->extensions; |
| |
| while (ext && ext->callback && !handled) { |
| m = ext->callback(context, ext, wsi, reason, |
| (void *)(long)n, arg, len); |
| if (m < 0) { |
| lwsl_ext( |
| "Extension '%s' failed to handle callback %d!\n", |
| wsi->active_extensions[n]->name, reason); |
| return -1; |
| } |
| if (m) |
| handled = 1; |
| |
| ext++; |
| n++; |
| } |
| |
| return 0; |
| } |
| |
| int |
| lws_issue_raw_ext_access(struct libwebsocket *wsi, |
| unsigned char *buf, size_t len) |
| { |
| int ret; |
| struct lws_tokens eff_buf; |
| int m; |
| int n = 0; |
| |
| eff_buf.token = (char *)buf; |
| eff_buf.token_len = len; |
| |
| /* |
| * while we have original buf to spill ourselves, or extensions report |
| * more in their pipeline |
| */ |
| |
| ret = 1; |
| while (ret == 1) { |
| |
| /* default to nobody has more to spill */ |
| |
| ret = 0; |
| |
| /* show every extension the new incoming data */ |
| m = lws_ext_callback_for_each_active(wsi, |
| LWS_EXT_CALLBACK_PACKET_TX_PRESEND, &eff_buf, 0); |
| if (m < 0) |
| return -1; |
| if (m) /* handled */ |
| ret = 1; |
| |
| if ((char *)buf != eff_buf.token) |
| /* |
| * extension recreated it: |
| * need to buffer this if not all sent |
| */ |
| wsi->u.ws.clean_buffer = 0; |
| |
| /* assuming they left us something to send, send it */ |
| |
| if (eff_buf.token_len) { |
| n = lws_issue_raw(wsi, (unsigned char *)eff_buf.token, |
| eff_buf.token_len); |
| if (n < 0) { |
| lwsl_info("closing from ext access\n"); |
| return -1; |
| } |
| |
| /* always either sent it all or privately buffered */ |
| if (wsi->u.ws.clean_buffer) |
| len = n; |
| } |
| |
| lwsl_parser("written %d bytes to client\n", n); |
| |
| /* no extension has more to spill? Then we can go */ |
| |
| if (!ret) |
| break; |
| |
| /* we used up what we had */ |
| |
| eff_buf.token = NULL; |
| eff_buf.token_len = 0; |
| |
| /* |
| * Did that leave the pipe choked? |
| * Or we had to hold on to some of it? |
| */ |
| |
| if (!lws_send_pipe_choked(wsi) && !wsi->truncated_send_len) |
| /* no we could add more, lets's do that */ |
| continue; |
| |
| lwsl_debug("choked\n"); |
| |
| /* |
| * Yes, he's choked. Don't spill the rest now get a callback |
| * when he is ready to send and take care of it there |
| */ |
| libwebsocket_callback_on_writable( |
| wsi->protocol->owning_server, wsi); |
| wsi->extension_data_pending = 1; |
| ret = 0; |
| } |
| |
| return len; |
| } |
| |
| int |
| lws_any_extension_handled(struct libwebsocket_context *context, |
| struct libwebsocket *wsi, |
| enum libwebsocket_extension_callback_reasons r, |
| void *v, size_t len) |
| { |
| int n; |
| int handled = 0; |
| |
| /* maybe an extension will take care of it for us */ |
| |
| for (n = 0; n < wsi->count_active_extensions && !handled; n++) { |
| if (!wsi->active_extensions[n]->callback) |
| continue; |
| |
| handled |= wsi->active_extensions[n]->callback(context, |
| wsi->active_extensions[n], wsi, |
| r, wsi->active_extensions_user[n], v, len); |
| } |
| |
| return handled; |
| } |