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 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 41 ParsedMessage::ParsedMessage() { 42 } 43 44 ParsedMessage::~ParsedMessage() { 45 } 46 47 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 63 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 81 const char *ParsedMessage::getContent() const { 82 return mContent.c_str(); 83 } 84 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 180 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 206 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 225 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 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 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