• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
WebSocketFrameHandler()15 WebSocketFrameHandler::WebSocketFrameHandler()
16     : current_buffer_size_(0),
17       original_current_buffer_size_(0) {
18 }
19 
~WebSocketFrameHandler()20 WebSocketFrameHandler::~WebSocketFrameHandler() {
21 }
22 
AppendData(const char * data,int length)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 
UpdateCurrentBuffer(bool buffered)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 
ReleaseCurrentBuffer()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 */
ParseWebSocketFrame(const char * buffer,int size,std::vector<FrameInfo> * frame_info)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