• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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