[ 
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)

Reply via email to