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(); }
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; } }