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``.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastruct...@apache.org or file a JIRA ticket
with INFRA.
---

Reply via email to