MTD_FLASHMEM bool MultipartFormDataProcessor::extractParameter(char const *name, CharChunksIterator curpos,
                                                               CharChunksIterator *nameBegin, CharChunksIterator *begin,
                                                               CharChunksIterator *end) {
  if (curpos != CharChunksIterator()) {
    *nameBegin = t_strstr(curpos, CharIterator(name));
    if (*nameBegin != CharChunksIterator()) {
      // bypass "name"
      CharChunksIterator it = *nameBegin + f_strlen(name);

      // bypass spaces and a quote
      bool hasQuote = false;
      for (; it != CharChunksIterator() && (isspace(*it) || *it == '"'); ++it)
        if (*it == '"')
          hasQuote = true;
      *begin = it;

      // look for spaces or a quote
      while (it != CharChunksIterator() && ((!hasQuote && !isspace(*it)) || (hasQuote && *it != '"')))
        ++it;
      *end = it;

      return true;
    }
  }
  return false;
}
CharChunksIterator MTD_FLASHMEM
    HTTPHandler::extractHeaders(CharChunksIterator begin, CharChunksIterator end, Fields *fields) {
  CharChunksIterator curc = begin;
  CharChunksIterator key;
  CharChunksIterator value;
  while (curc != end) {
    if (*curc == 0x0D && key.isValid() && value.isValid()) // CR?
    {
      *curc = 0; // ends key
      // store header
      fields->add(key, value);
      key = value = CharChunksIterator(); // reset
    } else if (!isspace(*curc) && !key.isValid()) {
      // bookmark "key"
      key = curc;
    } else if (!value.isValid() && *curc == ':') {
      *curc++ = 0; // ends value
      // bypass spaces
      while (curc != end && isspace(*curc))
        ++curc;
      // bookmark value
      value = curc;
    }
    ++curc;
  }
  return curc;
}
CharChunksIterator MTD_FLASHMEM
    HTTPHandler::extractURLEncodedFields(CharChunksIterator begin, CharChunksIterator end, Fields *fields) {
  fields->setUrlDecode(true);
  CharChunksIterator curc = begin;
  CharChunksIterator key = curc;
  CharChunksIterator value;
  while (curc != end) {
    if (*curc == '=') {
      *curc = 0; // ends key
      value = curc;
      ++value; // bypass '='
    } else if (*curc == '&' || *curc == ' ' || curc.isLast()) {
      bool endLoop = (*curc == ' ' || curc.isLast());
      *curc++ = 0; // zero-ends value
      if (key.isValid() && value.isValid()) {
        fields->add(key, value);            // store parameter
        key = value = CharChunksIterator(); // reset
      }
      if (endLoop)
        break;
      key = curc;
    } else
      ++curc;
  }
  return curc;
}
void MTD_FLASHMEM HTTPHandler::processMultipartFormData(CharChunksIterator headerEnd, int32_t contentLength,
                                                        char const *contentType) {
  char const *boundary = f_strstr(contentType, FSTR("boundary="));
  if (boundary) {
    // go to begin of boundary string
    boundary += 9;

    MultipartFormDataProcessor proc(boundary, &m_request.form);

    // consume already received data
    CharChunksIterator contentStart = headerEnd;
    while (contentStart != CharChunksIterator())
      proc.push(*contentStart++);

    // consume new data
    while (getSocket()->isConnected() && proc.state != MultipartFormDataProcessor::EndOfContent) {
      char c;
      int32_t bytesRecv = getSocket()->read(&c, 1);
      if (bytesRecv <= 0)
        break;
      proc.push(c);
    }

    // dispatch must be inside this block, to have MultipartFormDataProcessor content available
    dispatch();
  } else
    dispatch();
}
void MTD_FLASHMEM MultipartFormDataProcessor::handle_GettingFile_GettingValue(char c) {
  static char const BOB[4] = {0x0D, 0x0A, '-', '-'}; // begin of boundary (just before every boundary)
  if (substate < 4 && c == BOB[substate]) {
    ++substate;
  } else if (substate >= 4 && c == boundary[substate - 4]) {
    ++substate;
    if (substate - 4 == boundarylen) {
      // found boundary, end file or value
      if (state == GettingFile)
        file.close();
      else
        formfields->add(nameBegin, nameEnd, valueStorage->getIterator(), CharChunksIterator());
      state = BoundaryFound;
      substate = 0;
    }
  } else {
    if (substate > 0) {
      // first "substate" bytes seemed the BOB or Boundary, but they were not!
      int32_t cnt = substate;
      substate = 0;
      if (state == GettingFile)
        file.write(BOB, 1);
      else
        valueStorage->append(BOB[0], FORM_CHUNK_SIZE);
      for (int32_t i = 1; i != cnt; ++i)
        push(i < 4 ? BOB[i] : boundary[i - 4]);
      push(c);
    } else {
      if (state == GettingFile)
        file.write(&c, 1);
      else
        valueStorage->append(c, FORM_CHUNK_SIZE);
    }
  }
}
void MTD_FLASHMEM HTTPHandler::processXWWWFormUrlEncoded(CharChunksIterator headerEnd, int32_t contentLength) {
  // look for data (maybe POST data)
  if (contentLength > 0) {
    // download additional content
    int32_t missingBytes = headerEnd.getPosition() + contentLength - m_receivedData.getItemsCount();
    while (getSocket()->isConnected() && missingBytes > 0) {
      int32_t bytesToRead = (CHUNK_CAPACITY < missingBytes ? CHUNK_CAPACITY : missingBytes);
      CharChunkBase *chunk = m_receivedData.addChunk(bytesToRead);
      int32_t bytesRecv = getSocket()->read(chunk->data, bytesToRead);
      if (bytesRecv <= 0)
        break;
      chunk->setItems(bytesRecv);
      missingBytes -= chunk->getItems();
    }
    m_receivedData.append(0); // add additional terminating "0"

    CharChunksIterator contentStart = m_receivedData.getIterator(); // cannot use directly headerEnd because added data
    contentStart += headerEnd.getPosition();
    extractURLEncodedFields(contentStart, CharChunksIterator(), &m_request.form);
  }

  dispatch();
}
示例#7
0
CharChunksIterator MTD_FLASHMEM LinkedCharChunks::getIterator()
{
	return CharChunksIterator(m_chunks);
}
bool MTD_FLASHMEM HTTPHandler::processRequest() {
  // look for 0x0D 0x0A 0x0D 0x0A
  CharChunksIterator headerEnd =
      t_strstr(m_receivedData.getIterator(), CharChunksIterator(), CharIterator(FSTR("\x0D\x0A\x0D\x0A")));
  if (headerEnd.isValid()) {
    // move header end after CRLFCRLF
    headerEnd += 4;

    CharChunksIterator curc = m_receivedData.getIterator();

    // extract method (GET, POST, etc..)
    CharChunksIterator method = curc;
    while (curc != headerEnd && *curc != ' ')
      ++curc;
    *curc++ = 0; // ends method
    if (t_strcmp(method, CharIterator(FSTR("GET"))) == 0)
      m_request.method = Get;
    else if (t_strcmp(method, CharIterator(FSTR("POST"))) == 0)
      m_request.method = Post;
    else if (t_strcmp(method, CharIterator(FSTR("HEAD"))) == 0)
      m_request.method = Head;
    else
      m_request.method = Unsupported;

    // extract requested page and query parameters
    m_request.requestedPage = curc;
    while (curc != headerEnd) {
      if (*curc == '?') {
        *curc++ = 0; // ends requestedPage
        curc = extractURLEncodedFields(curc, headerEnd, &m_request.query);
        break;
      } else if (*curc == ' ') {
        *curc++ = 0; // ends requestedPage
        break;
      }
      ++curc;
    }

    // bypass HTTP version
    while (curc != headerEnd && *curc != 0x0D)
      ++curc;

    // extract headers
    curc = extractHeaders(curc, headerEnd, &m_request.headers);

    // get content length (may be NULL)
    char const *contentLengthStr = m_request.headers[STR_Content_Length];
    int32_t contentLength = contentLengthStr ? strtol(contentLengthStr, NULL, 10) : 0;

    if (m_request.method == Post) {
      // check content type (POST)
      char const *contentType = m_request.headers[STR_Content_Type];
      if (contentType && f_strstr(contentType, FSTR("multipart/form-data"))) {
        //// content type is multipart/form-data
        processMultipartFormData(headerEnd, contentLength, contentType);
      } else if (contentType == NULL ||
                 (contentType && f_strstr(contentType, FSTR("application/x-www-form-urlencoded")))) {
        //// content type is application/x-www-form-urlencoded
        processXWWWFormUrlEncoded(headerEnd, contentLength);
      }
    } else
      dispatch();

    return true;
  } else {
    // header is not complete
    return false;
  }
}