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