[
https://issues.apache.org/jira/browse/TS-4699?focusedWorklogId=26085&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-26085
]
ASF GitHub Bot logged work on TS-4699:
--------------------------------------
Author: ASF GitHub Bot
Created on: 29/Jul/16 01:59
Start Date: 29/Jul/16 01:59
Worklog Time Spent: 10m
Work Description: Github user jpeach commented on a diff in the pull
request:
https://github.com/apache/trafficserver/pull/824#discussion_r72732848
--- Diff: lib/atscppapi/examples/experimental/websocket/WSBuffer.cc ---
@@ -0,0 +1,206 @@
+#include "WSBuffer.hh"
+
+#include "ts/ink_base64.h"
+#include "openssl/evp.h"
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#define WS_DIGEST_MAX ATS_BASE64_ENCODE_DSTLEN(20)
+static const std::string magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+
+WSBuffer::WSBuffer()
+{
+}
+
+void
+WSBuffer::buffer(std::string const &data)
+{
+ ws_buf_ += data;
+}
+
+bool
+WSBuffer::read_buffered_message(std::string &message, int &code)
+{
+ // There are two basic states depending on whether or
+ // not we have parsed a message length. If we're looking
+ // for a message length, we don't advance pos_ until we
+ // have read one (as well as control bytes and mask).
+ //
+ // Once we have a message length, we don't advance
+ // pos_ until we have a complete message. (If the message
+ // length is 0 we will produce the message immediately
+ // and revert to looking for the next message length.)
+ //
+ // When incoming data is fragmented we may be called several
+ // times before we get a length or a complete message.
+
+ char mask[4];
+
+ size_t avail = ws_buf_.size();
+
+ // Check if there is a mask (there should be).
+ if (avail < 2)
+ return false;
+ size_t mask_len = (ws_buf_[1] & WS_MASKED) ? 4 : 0;
+
+ int frame = ws_buf_[0] & WS_OPCODE;
+ bool first = frame != WS_FRAME_CONTINUATION;
+ auto final = ws_buf_[0] & WS_FIN;
+
+ // Save/restore frame type on first/continuation.
+ if (first) {
+ frame_ = frame;
+ msg_buf_.clear();
+ } else
+ frame = frame_;
+
+ // Read the msg_length if we have enough data.
+ if (avail < 2 + mask_len)
+ return false;
+
+ size_t msg_len = ws_buf_[1] & WS_LENGTH;
+ size_t pos;
+ if (msg_len == WS_16BIT_LEN) {
+ if (avail < 4 + mask_len) { // 2 + 2 + length bytes + mask.
+ return false;
+ }
+ msg_len = ntohs(*(uint16_t *)(ws_buf_.data() + 2));
+ pos = 4;
+ } else if (msg_len == WS_64BIT_LEN) {
+ if (avail < 10 + mask_len) { // 2 + 8 length bytes + mask.
+ return false;
+ }
+ msg_len = be64toh(*(uint64_t *)(ws_buf_.data() + 2));
+ pos = 10;
+ } else {
+ pos = 2;
+ }
+
+ // Check if we have enough data to read the message.
+ if (ws_buf_.size() < pos + msg_len)
+ return false; // not enough data.
+
+ // Copy any mask.
+ for (size_t i = 0; i < mask_len; ++i, ++pos) {
+ mask[i] = ws_buf_[pos];
+ }
+
+ // Apply any mask.
+ if (mask_len) {
+ for (size_t i = 0, p = pos; i < msg_len; ++i, ++p) {
+ ws_buf_[p] ^= mask[i & 3];
+ }
+ }
+
+ // Copy the message out.
+ if (final) {
+ message = msg_buf_;
+ message += ws_buf_.substr(pos, msg_len);
+ code = frame;
+ } else {
+ msg_buf_ += ws_buf_.substr(pos, msg_len);
+ }
+
+ // Discard consumed data.
+ ws_buf_.erase(0, pos + msg_len);
+
+ return true;
+}
+
+std::string
+WSBuffer::ws_digest(std::string const &key)
+{
+ EVP_MD_CTX digest;
+ EVP_MD_CTX_init(&digest);
+
+ if (!EVP_DigestInit_ex(&digest, EVP_sha1(), NULL)) {
+ EVP_MD_CTX_cleanup(&digest);
+ return "init-failed";
+ }
+ if (!EVP_DigestUpdate(&digest, key.data(), key.length())) {
+ EVP_MD_CTX_cleanup(&digest);
+ return "update1-failed";
+ }
+ if (!EVP_DigestUpdate(&digest, magic.data(), magic.length())) {
+ EVP_MD_CTX_cleanup(&digest);
+ return "update2-failed";
+ }
+
+ unsigned char hash_buf[EVP_MAX_MD_SIZE];
+ unsigned int hash_len = 0;
+ if (!EVP_DigestFinal_ex(&digest, hash_buf, &hash_len)) {
+ EVP_MD_CTX_cleanup(&digest);
+ return "final-failed";
+ }
+ EVP_MD_CTX_cleanup(&digest);
+ if (hash_len != 20) {
+ return "bad-hash-length";
+ }
+
+ char digest_buf[WS_DIGEST_MAX];
+ size_t digest_len = 0;
+
+ ats_base64_encode(hash_buf, hash_len, digest_buf, WS_DIGEST_MAX,
&digest_len);
--- End diff --
This is an example plugin, so you should avoid internal libraries. Use
``TSBase64Encode``.
Issue Time Tracking
-------------------
Worklog Id: (was: 26085)
Time Spent: 1h (was: 50m)
> Add an example websocket termination plugin using the C++ API
> -------------------------------------------------------------
>
> Key: TS-4699
> URL: https://issues.apache.org/jira/browse/TS-4699
> Project: Traffic Server
> Issue Type: Improvement
> Components: CPP API
> Reporter: Oliver Goodman
> Assignee: Brian Geffon
> Fix For: 7.0.0
>
> Time Spent: 1h
> Remaining Estimate: 0h
>
> It may be of interest to users to have an experimental example plugin showing
> how to terminate incoming websocket connections. A minimal example could
> implement the protocol and use it to set up a simple websocket echo server.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)