Home | History | Annotate | Download | only in websockets
      1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <algorithm>
      6 #include <limits>
      7 
      8 #include "net/websockets/websocket_frame_handler.h"
      9 
     10 #include "net/base/io_buffer.h"
     11 #include "net/base/net_errors.h"
     12 
     13 namespace net {
     14 
     15 WebSocketFrameHandler::WebSocketFrameHandler()
     16     : current_buffer_size_(0),
     17       original_current_buffer_size_(0) {
     18 }
     19 
     20 WebSocketFrameHandler::~WebSocketFrameHandler() {
     21 }
     22 
     23 void WebSocketFrameHandler::AppendData(const char* data, int length) {
     24   scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(length);
     25   memcpy(buffer->data(), data, length);
     26   pending_buffers_.push_back(buffer);
     27 }
     28 
     29 int WebSocketFrameHandler::UpdateCurrentBuffer(bool buffered) {
     30   if (current_buffer_)
     31     return 0;
     32   DCHECK(!current_buffer_size_);
     33   DCHECK(!original_current_buffer_size_);
     34 
     35   if (pending_buffers_.empty())
     36     return 0;
     37   scoped_refptr<IOBufferWithSize> buffer = pending_buffers_.front();
     38 
     39   int buffer_size = 0;
     40   if (buffered) {
     41     std::vector<FrameInfo> frame_info;
     42     buffer_size =
     43         ParseWebSocketFrame(buffer->data(), buffer->size(), &frame_info);
     44     if (buffer_size <= 0)
     45       return buffer_size;
     46 
     47     original_current_buffer_size_ = buffer_size;
     48 
     49     // TODO(ukai): filter(e.g. compress or decompress) frame messages.
     50   } else {
     51     original_current_buffer_size_ = buffer->size();
     52     buffer_size = buffer->size();
     53   }
     54 
     55   current_buffer_ = buffer;
     56   current_buffer_size_ = buffer_size;
     57   return buffer_size;
     58 }
     59 
     60 void WebSocketFrameHandler::ReleaseCurrentBuffer() {
     61   DCHECK(!pending_buffers_.empty());
     62   scoped_refptr<IOBufferWithSize> front_buffer = pending_buffers_.front();
     63   pending_buffers_.pop_front();
     64   int remaining_size = front_buffer->size() - original_current_buffer_size_;
     65   if (remaining_size > 0) {
     66     scoped_refptr<IOBufferWithSize> next_buffer = NULL;
     67     int buffer_size = remaining_size;
     68     if (!pending_buffers_.empty()) {
     69       next_buffer = pending_buffers_.front();
     70       buffer_size += next_buffer->size();
     71       pending_buffers_.pop_front();
     72     }
     73     // TODO(ukai): don't copy data.
     74     scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(buffer_size);
     75     memcpy(buffer->data(), front_buffer->data() + original_current_buffer_size_,
     76            remaining_size);
     77     if (next_buffer)
     78       memcpy(buffer->data() + remaining_size,
     79              next_buffer->data(), next_buffer->size());
     80     pending_buffers_.push_front(buffer);
     81   }
     82   current_buffer_ = NULL;
     83   current_buffer_size_ = 0;
     84   original_current_buffer_size_ = 0;
     85 }
     86 
     87 /* static */
     88 int WebSocketFrameHandler::ParseWebSocketFrame(
     89     const char* buffer, int size, std::vector<FrameInfo>* frame_info) {
     90   const char* end = buffer + size;
     91   const char* p = buffer;
     92   int buffer_size = 0;
     93   while (p < end) {
     94     FrameInfo frame;
     95     frame.frame_start = p;
     96     frame.message_length = -1;
     97     unsigned char frame_byte = static_cast<unsigned char>(*p++);
     98     if ((frame_byte & 0x80) == 0x80) {
     99       int length = 0;
    100       while (p < end) {
    101         // Note: might overflow later if numeric_limits<int>::max() is not
    102         // n*128-1.
    103         if (length > std::numeric_limits<int>::max() / 128) {
    104           // frame length overflow.
    105           return ERR_INSUFFICIENT_RESOURCES;
    106         }
    107         unsigned char c = static_cast<unsigned char>(*p);
    108         length = length * 128 + (c & 0x7f);
    109         ++p;
    110         if ((c & 0x80) != 0x80)
    111           break;
    112       }
    113       if (end - p >= length) {
    114         frame.message_start = p;
    115         frame.message_length = length;
    116         p += length;
    117       } else {
    118         break;
    119       }
    120     } else {
    121       frame.message_start = p;
    122       while (p < end && *p != '\xff')
    123         ++p;
    124       if (p < end && *p == '\xff') {
    125         frame.message_length = p - frame.message_start;
    126         ++p;
    127       } else {
    128         break;
    129       }
    130     }
    131     if (frame.message_length >= 0 && p <= end) {
    132       frame.frame_length = p - frame.frame_start;
    133       buffer_size += frame.frame_length;
    134       frame_info->push_back(frame);
    135     }
    136   }
    137   return buffer_size;
    138 }
    139 
    140 }  // namespace net
    141