| // Copyright 2017 Google Inc. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| #ifndef COBALT_WEBSOCKET_WEB_SOCKET_FRAME_CONTAINER_H_ |
| #define COBALT_WEBSOCKET_WEB_SOCKET_FRAME_CONTAINER_H_ |
| |
| #include <algorithm> |
| #include <deque> |
| |
| #include "base/basictypes.h" |
| #include "net/base/io_buffer.h" |
| #include "net/websockets/websocket_frame.h" |
| |
| namespace cobalt { |
| namespace websocket { |
| |
| const size_t kMaxFramePayloadInBytes = 4 * 1024 * 1024; |
| |
| class WebSocketFrameContainer { |
| public: |
| typedef std::deque<const net::WebSocketFrameChunk*> WebSocketFrameChunks; |
| typedef WebSocketFrameChunks::iterator iterator; |
| typedef WebSocketFrameChunks::const_iterator const_iterator; |
| |
| WebSocketFrameContainer() |
| : frame_completed_(false), |
| payload_size_bytes_(0), |
| expected_payload_size_bytes_(0) {} |
| ~WebSocketFrameContainer() { clear(); } |
| |
| void clear(); |
| |
| const net::WebSocketFrameHeader* GetHeader() const { |
| if (empty()) { |
| return NULL; |
| } |
| |
| return (*begin())->header.get(); |
| } |
| |
| bool IsControlFrame() const; |
| bool IsDataFrame() const; |
| bool IsContinuationFrame() const; |
| |
| enum ErrorCode { |
| kErrorNone, |
| kErrorMaxFrameSizeViolation, |
| kErrorFirstChunkMissingHeader, |
| kErrorHasExtraHeader, |
| kErrorFrameAlreadyComplete, |
| kErrorPayloadSizeSmallerThanHeader, |
| kErrorPayloadSizeLargerThanHeader |
| }; |
| |
| bool IsFrameComplete() const { return frame_completed_; } |
| |
| bool IsFinalFrame() const { |
| const net::WebSocketFrameHeader* const header = GetHeader(); |
| if (!header) { |
| return false; |
| } |
| return (header && header->final); |
| } |
| |
| // Note that this takes always ownership of the chunk. |
| // Should only be called if IsFrameComplete() is false. |
| // Note that if there is an error produced in the function, it will |
| // leave the state of this object unchanged. |
| ErrorCode Take(const net::WebSocketFrameChunk* chunk); |
| |
| iterator begin() { return chunks_.begin(); } |
| iterator end() { return chunks_.end(); } |
| const_iterator begin() const { return chunks_.begin(); } |
| const_iterator end() const { return chunks_.end(); } |
| const_iterator cbegin() const { return chunks_.begin(); } |
| const_iterator cend() const { return chunks_.end(); } |
| bool empty() const { return begin() == end(); } |
| |
| std::size_t GetCurrentPayloadSizeBytes() const { return payload_size_bytes_; } |
| std::size_t GetChunkCount() const { return chunks_.size(); } |
| |
| void swap(WebSocketFrameContainer& other) { |
| std::swap(frame_completed_, other.frame_completed_); |
| std::swap(payload_size_bytes_, other.payload_size_bytes_); |
| std::swap(expected_payload_size_bytes_, other.expected_payload_size_bytes_); |
| chunks_.swap(other.chunks_); |
| } |
| |
| // Returns false if op_code was not found, and returns true otherwise. |
| bool GetFrameOpCode(net::WebSocketFrameHeader::OpCode* op_code) const { |
| DCHECK(op_code); |
| if (empty()) { |
| return false; |
| } |
| |
| const net::WebSocketFrameChunk* first_chunk(*begin()); |
| DCHECK(first_chunk); |
| const scoped_ptr<net::WebSocketFrameHeader>& first_chunk_header = |
| first_chunk->header; |
| if (!first_chunk_header) { |
| NOTREACHED() << "No header found in the first chunk."; |
| return false; |
| } |
| |
| *op_code = first_chunk_header->opcode; |
| return true; |
| } |
| |
| private: |
| // Note: If you add a field, please remember to update swap() above. |
| bool frame_completed_; |
| std::size_t payload_size_bytes_; |
| std::size_t expected_payload_size_bytes_; |
| WebSocketFrameChunks chunks_; |
| }; |
| |
| } // namespace websocket |
| } // namespace cobalt |
| |
| #endif // COBALT_WEBSOCKET_WEB_SOCKET_FRAME_CONTAINER_H_ |