1 /*
2 * Copyright 2012, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "ParsedMessage.h"
18
19 #include <ctype.h>
20 #include <media/stagefright/foundation/ABuffer.h>
21 #include <media/stagefright/foundation/ADebug.h>
22 #include <media/stagefright/foundation/hexdump.h>
23
24 namespace android {
25
26 // static
Parse(const char * data,size_t size,bool noMoreData,size_t * length)27 sp<ParsedMessage> ParsedMessage::Parse(
28 const char *data, size_t size, bool noMoreData, size_t *length) {
29 sp<ParsedMessage> msg = new ParsedMessage;
30 ssize_t res = msg->parse(data, size, noMoreData);
31
32 if (res < 0) {
33 *length = 0;
34 return NULL;
35 }
36
37 *length = res;
38 return msg;
39 }
40
ParsedMessage()41 ParsedMessage::ParsedMessage() {
42 }
43
~ParsedMessage()44 ParsedMessage::~ParsedMessage() {
45 }
46
findString(const char * name,AString * value) const47 bool ParsedMessage::findString(const char *name, AString *value) const {
48 AString key = name;
49 key.tolower();
50
51 ssize_t index = mDict.indexOfKey(key);
52
53 if (index < 0) {
54 value->clear();
55
56 return false;
57 }
58
59 *value = mDict.valueAt(index);
60 return true;
61 }
62
findInt32(const char * name,int32_t * value) const63 bool ParsedMessage::findInt32(const char *name, int32_t *value) const {
64 AString stringValue;
65
66 if (!findString(name, &stringValue)) {
67 return false;
68 }
69
70 char *end;
71 *value = strtol(stringValue.c_str(), &end, 10);
72
73 if (end == stringValue.c_str() || *end != '\0') {
74 *value = 0;
75 return false;
76 }
77
78 return true;
79 }
80
getContent() const81 const char *ParsedMessage::getContent() const {
82 return mContent.c_str();
83 }
84
parse(const char * data,size_t size,bool noMoreData)85 ssize_t ParsedMessage::parse(const char *data, size_t size, bool noMoreData) {
86 if (size == 0) {
87 return -1;
88 }
89
90 ssize_t lastDictIndex = -1;
91
92 size_t offset = 0;
93 bool headersComplete = false;
94 while (offset < size) {
95 size_t lineEndOffset = offset;
96 while (lineEndOffset + 1 < size
97 && (data[lineEndOffset] != '\r'
98 || data[lineEndOffset + 1] != '\n')) {
99 ++lineEndOffset;
100 }
101
102 if (lineEndOffset + 1 >= size) {
103 return -1;
104 }
105
106 AString line(&data[offset], lineEndOffset - offset);
107
108 if (offset == 0) {
109 // Special handling for the request/status line.
110
111 mDict.add(AString("_"), line);
112 offset = lineEndOffset + 2;
113
114 continue;
115 }
116
117 if (lineEndOffset == offset) {
118 // An empty line separates headers from body.
119 headersComplete = true;
120 offset += 2;
121 break;
122 }
123
124 if (line.c_str()[0] == ' ' || line.c_str()[0] == '\t') {
125 // Support for folded header values.
126
127 if (lastDictIndex >= 0) {
128 // Otherwise it's malformed since the first header line
129 // cannot continue anything...
130
131 AString &value = mDict.editValueAt(lastDictIndex);
132 value.append(line);
133 }
134
135 offset = lineEndOffset + 2;
136 continue;
137 }
138
139 ssize_t colonPos = line.find(":");
140 if (colonPos >= 0) {
141 AString key(line, 0, colonPos);
142 key.trim();
143 key.tolower();
144
145 line.erase(0, colonPos + 1);
146
147 lastDictIndex = mDict.add(key, line);
148 }
149
150 offset = lineEndOffset + 2;
151 }
152
153 if (!headersComplete && (!noMoreData || offset == 0)) {
154 // We either saw the empty line separating headers from body
155 // or we saw at least the status line and know that no more data
156 // is going to follow.
157 return -1;
158 }
159
160 for (size_t i = 0; i < mDict.size(); ++i) {
161 mDict.editValueAt(i).trim();
162 }
163
164 int32_t contentLength;
165 if (!findInt32("content-length", &contentLength) || contentLength < 0) {
166 contentLength = 0;
167 }
168
169 size_t totalLength = offset + contentLength;
170
171 if (size < totalLength) {
172 return -1;
173 }
174
175 mContent.setTo(&data[offset], contentLength);
176
177 return totalLength;
178 }
179
getRequestField(size_t index,AString * field) const180 bool ParsedMessage::getRequestField(size_t index, AString *field) const {
181 AString line;
182 CHECK(findString("_", &line));
183
184 size_t prevOffset = 0;
185 size_t offset = 0;
186 for (size_t i = 0; i <= index; ++i) {
187 if (offset >= line.size()) {
188 return false;
189 }
190
191 ssize_t spacePos = line.find(" ", offset);
192
193 if (spacePos < 0) {
194 spacePos = line.size();
195 }
196
197 prevOffset = offset;
198 offset = spacePos + 1;
199 }
200
201 field->setTo(line, prevOffset, offset - prevOffset - 1);
202
203 return true;
204 }
205
getStatusCode(int32_t * statusCode) const206 bool ParsedMessage::getStatusCode(int32_t *statusCode) const {
207 AString statusCodeString;
208 if (!getRequestField(1, &statusCodeString)) {
209 *statusCode = 0;
210 return false;
211 }
212
213 char *end;
214 *statusCode = strtol(statusCodeString.c_str(), &end, 10);
215
216 if (*end != '\0' || end == statusCodeString.c_str()
217 || (*statusCode) < 100 || (*statusCode) > 999) {
218 *statusCode = 0;
219 return false;
220 }
221
222 return true;
223 }
224
debugString() const225 AString ParsedMessage::debugString() const {
226 AString line;
227 CHECK(findString("_", &line));
228
229 line.append("\n");
230
231 for (size_t i = 0; i < mDict.size(); ++i) {
232 const AString &key = mDict.keyAt(i);
233 const AString &value = mDict.valueAt(i);
234
235 if (key == AString("_")) {
236 continue;
237 }
238
239 line.append(key);
240 line.append(": ");
241 line.append(value);
242 line.append("\n");
243 }
244
245 line.append("\n");
246 line.append(mContent);
247
248 return line;
249 }
250
251 // static
GetAttribute(const char * s,const char * key,AString * value)252 bool ParsedMessage::GetAttribute(
253 const char *s, const char *key, AString *value) {
254 value->clear();
255
256 size_t keyLen = strlen(key);
257
258 for (;;) {
259 while (isspace(*s)) {
260 ++s;
261 }
262
263 const char *colonPos = strchr(s, ';');
264
265 size_t len =
266 (colonPos == NULL) ? strlen(s) : colonPos - s;
267
268 if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) {
269 value->setTo(&s[keyLen + 1], len - keyLen - 1);
270 return true;
271 }
272
273 if (colonPos == NULL) {
274 return false;
275 }
276
277 s = colonPos + 1;
278 }
279 }
280
281 // static
GetInt32Attribute(const char * s,const char * key,int32_t * value)282 bool ParsedMessage::GetInt32Attribute(
283 const char *s, const char *key, int32_t *value) {
284 AString stringValue;
285 if (!GetAttribute(s, key, &stringValue)) {
286 *value = 0;
287 return false;
288 }
289
290 char *end;
291 *value = strtol(stringValue.c_str(), &end, 10);
292
293 if (end == stringValue.c_str() || *end != '\0') {
294 *value = 0;
295 return false;
296 }
297
298 return true;
299 }
300
301 } // namespace android
302
303