Home | History | Annotate | Download | only in foundation
      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