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 23 namespace android { 24 25 // static 26 sp<ParsedMessage> ParsedMessage::Parse( 27 const char *data, size_t size, bool noMoreData, size_t *length) { 28 sp<ParsedMessage> msg = new ParsedMessage; 29 ssize_t res = msg->parse(data, size, noMoreData); 30 31 if (res < 0) { 32 *length = 0; 33 return NULL; 34 } 35 36 *length = res; 37 return msg; 38 } 39 40 ParsedMessage::ParsedMessage() { 41 } 42 43 ParsedMessage::~ParsedMessage() { 44 } 45 46 bool ParsedMessage::findString(const char *name, AString *value) const { 47 AString key = name; 48 key.tolower(); 49 50 ssize_t index = mDict.indexOfKey(key); 51 52 if (index < 0) { 53 value->clear(); 54 55 return false; 56 } 57 58 *value = mDict.valueAt(index); 59 return true; 60 } 61 62 bool ParsedMessage::findInt32(const char *name, int32_t *value) const { 63 AString stringValue; 64 65 if (!findString(name, &stringValue)) { 66 return false; 67 } 68 69 char *end; 70 *value = strtol(stringValue.c_str(), &end, 10); 71 72 if (end == stringValue.c_str() || *end != '\0') { 73 *value = 0; 74 return false; 75 } 76 77 return true; 78 } 79 80 const char *ParsedMessage::getContent() const { 81 return mContent.c_str(); 82 } 83 84 ssize_t ParsedMessage::parse(const char *data, size_t size, bool noMoreData) { 85 if (size == 0) { 86 return -1; 87 } 88 89 ssize_t lastDictIndex = -1; 90 91 size_t offset = 0; 92 while (offset < size) { 93 size_t lineEndOffset = offset; 94 while (lineEndOffset + 1 < size 95 && (data[lineEndOffset] != '\r' 96 || data[lineEndOffset + 1] != '\n')) { 97 ++lineEndOffset; 98 } 99 100 if (lineEndOffset + 1 >= size) { 101 return -1; 102 } 103 104 AString line(&data[offset], lineEndOffset - offset); 105 106 if (offset == 0) { 107 // Special handling for the request/status line. 108 109 mDict.add(AString("_"), line); 110 offset = lineEndOffset + 2; 111 112 continue; 113 } 114 115 if (lineEndOffset == offset) { 116 offset += 2; 117 break; 118 } 119 120 if (line.c_str()[0] == ' ' || line.c_str()[0] == '\t') { 121 // Support for folded header values. 122 123 if (lastDictIndex >= 0) { 124 // Otherwise it's malformed since the first header line 125 // cannot continue anything... 126 127 AString &value = mDict.editValueAt(lastDictIndex); 128 value.append(line); 129 } 130 131 offset = lineEndOffset + 2; 132 continue; 133 } 134 135 ssize_t colonPos = line.find(":"); 136 if (colonPos >= 0) { 137 AString key(line, 0, colonPos); 138 key.trim(); 139 key.tolower(); 140 141 line.erase(0, colonPos + 1); 142 143 lastDictIndex = mDict.add(key, line); 144 } 145 146 offset = lineEndOffset + 2; 147 } 148 149 for (size_t i = 0; i < mDict.size(); ++i) { 150 mDict.editValueAt(i).trim(); 151 } 152 153 // Found the end of headers. 154 155 int32_t contentLength; 156 if (!findInt32("content-length", &contentLength) || contentLength < 0) { 157 contentLength = 0; 158 } 159 160 size_t totalLength = offset + contentLength; 161 162 if (size < totalLength) { 163 return -1; 164 } 165 166 mContent.setTo(&data[offset], contentLength); 167 168 return totalLength; 169 } 170 171 void ParsedMessage::getRequestField(size_t index, AString *field) const { 172 AString line; 173 CHECK(findString("_", &line)); 174 175 size_t prevOffset = 0; 176 size_t offset = 0; 177 for (size_t i = 0; i <= index; ++i) { 178 ssize_t spacePos = line.find(" ", offset); 179 180 if (spacePos < 0) { 181 spacePos = line.size(); 182 } 183 184 prevOffset = offset; 185 offset = spacePos + 1; 186 } 187 188 field->setTo(line, prevOffset, offset - prevOffset - 1); 189 } 190 191 bool ParsedMessage::getStatusCode(int32_t *statusCode) const { 192 AString statusCodeString; 193 getRequestField(1, &statusCodeString); 194 195 char *end; 196 *statusCode = strtol(statusCodeString.c_str(), &end, 10); 197 198 if (*end != '\0' || end == statusCodeString.c_str() 199 || (*statusCode) < 100 || (*statusCode) > 999) { 200 *statusCode = 0; 201 return false; 202 } 203 204 return true; 205 } 206 207 AString ParsedMessage::debugString() const { 208 AString line; 209 CHECK(findString("_", &line)); 210 211 line.append("\n"); 212 213 for (size_t i = 0; i < mDict.size(); ++i) { 214 const AString &key = mDict.keyAt(i); 215 const AString &value = mDict.valueAt(i); 216 217 if (key == AString("_")) { 218 continue; 219 } 220 221 line.append(key); 222 line.append(": "); 223 line.append(value); 224 line.append("\n"); 225 } 226 227 line.append("\n"); 228 line.append(mContent); 229 230 return line; 231 } 232 233 // static 234 bool ParsedMessage::GetAttribute( 235 const char *s, const char *key, AString *value) { 236 value->clear(); 237 238 size_t keyLen = strlen(key); 239 240 for (;;) { 241 while (isspace(*s)) { 242 ++s; 243 } 244 245 const char *colonPos = strchr(s, ';'); 246 247 size_t len = 248 (colonPos == NULL) ? strlen(s) : colonPos - s; 249 250 if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) { 251 value->setTo(&s[keyLen + 1], len - keyLen - 1); 252 return true; 253 } 254 255 if (colonPos == NULL) { 256 return false; 257 } 258 259 s = colonPos + 1; 260 } 261 } 262 263 // static 264 bool ParsedMessage::GetInt32Attribute( 265 const char *s, const char *key, int32_t *value) { 266 AString stringValue; 267 if (!GetAttribute(s, key, &stringValue)) { 268 *value = 0; 269 return false; 270 } 271 272 char *end; 273 *value = strtol(stringValue.c_str(), &end, 10); 274 275 if (end == stringValue.c_str() || *end != '\0') { 276 *value = 0; 277 return false; 278 } 279 280 return true; 281 } 282 283 } // namespace android 284 285