Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / websockets / websocket_extension_parser.cc
blobb737d5eab6fb9fc18577d3bdc2451fc8a8e77426
1 // Copyright 2013 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.
5 #include "net/websockets/websocket_extension_parser.h"
7 #include "base/strings/string_util.h"
9 namespace net {
11 WebSocketExtensionParser::WebSocketExtensionParser() {}
13 WebSocketExtensionParser::~WebSocketExtensionParser() {}
15 bool WebSocketExtensionParser::Parse(const char* data, size_t size) {
16 current_ = data;
17 end_ = data + size;
18 extensions_.clear();
20 bool failed = false;
22 while (true) {
23 WebSocketExtension extension;
24 if (!ConsumeExtension(&extension)) {
25 failed = true;
26 break;
28 extensions_.push_back(extension);
30 ConsumeSpaces();
32 if (!ConsumeIfMatch(',')) {
33 break;
37 if (!failed && current_ == end_)
38 return true;
40 extensions_.clear();
41 return false;
44 bool WebSocketExtensionParser::Consume(char c) {
45 ConsumeSpaces();
46 if (current_ == end_ || c != current_[0]) {
47 return false;
49 ++current_;
50 return true;
53 bool WebSocketExtensionParser::ConsumeExtension(WebSocketExtension* extension) {
54 base::StringPiece name;
55 if (!ConsumeToken(&name))
56 return false;
57 *extension = WebSocketExtension(name.as_string());
59 while (ConsumeIfMatch(';')) {
60 WebSocketExtension::Parameter parameter((std::string()));
61 if (!ConsumeExtensionParameter(&parameter))
62 return false;
63 extension->Add(parameter);
66 return true;
69 bool WebSocketExtensionParser::ConsumeExtensionParameter(
70 WebSocketExtension::Parameter* parameter) {
71 base::StringPiece name, value;
72 std::string value_string;
74 if (!ConsumeToken(&name))
75 return false;
77 if (!ConsumeIfMatch('=')) {
78 *parameter = WebSocketExtension::Parameter(name.as_string());
79 return true;
82 if (Lookahead('\"')) {
83 if (!ConsumeQuotedToken(&value_string))
84 return false;
85 } else {
86 if (!ConsumeToken(&value))
87 return false;
88 value_string = value.as_string();
90 *parameter = WebSocketExtension::Parameter(name.as_string(), value_string);
91 return true;
94 bool WebSocketExtensionParser::ConsumeToken(base::StringPiece* token) {
95 ConsumeSpaces();
96 const char* head = current_;
97 while (current_ < end_ &&
98 !IsControl(current_[0]) && !IsSeparator(current_[0]))
99 ++current_;
100 if (current_ == head) {
101 return false;
103 *token = base::StringPiece(head, current_ - head);
104 return true;
107 bool WebSocketExtensionParser::ConsumeQuotedToken(std::string* token) {
108 if (!Consume('"'))
109 return false;
111 *token = "";
112 while (current_ < end_ && !IsControl(current_[0])) {
113 if (UnconsumedBytes() >= 2 && current_[0] == '\\') {
114 char next = current_[1];
115 if (IsControl(next) || IsSeparator(next)) break;
116 *token += next;
117 current_ += 2;
118 } else if (IsSeparator(current_[0])) {
119 break;
120 } else {
121 *token += current_[0];
122 ++current_;
125 // We can't use Consume here because we don't want to consume spaces.
126 if (current_ >= end_ || current_[0] != '"')
127 return false;
129 ++current_;
131 return !token->empty();
134 void WebSocketExtensionParser::ConsumeSpaces() {
135 while (current_ < end_ && (current_[0] == ' ' || current_[0] == '\t'))
136 ++current_;
137 return;
140 bool WebSocketExtensionParser::Lookahead(char c) {
141 const char* head = current_;
142 bool result = Consume(c);
143 current_ = head;
144 return result;
147 bool WebSocketExtensionParser::ConsumeIfMatch(char c) {
148 const char* head = current_;
149 if (!Consume(c)) {
150 current_ = head;
151 return false;
154 return true;
157 // static
158 bool WebSocketExtensionParser::IsControl(char c) {
159 return (0 <= c && c <= 31) || c == 127;
162 // static
163 bool WebSocketExtensionParser::IsSeparator(char c) {
164 const char separators[] = "()<>@,;:\\\"/[]?={} \t";
165 return strchr(separators, c) != NULL;
168 } // namespace net