PUBLIC bool websProcessUploadData(Webs *wp) { char *line, *nextTok; ssize len, nbytes; bool canProceed; line = 0; canProceed = 1; while (canProceed && !wp->finalized && wp->uploadState != UPLOAD_CONTENT_END) { if (wp->uploadState == UPLOAD_BOUNDARY || wp->uploadState == UPLOAD_CONTENT_HEADER) { /* Parse the next input line */ line = wp->input.servp; if ((nextTok = memchr(line, '\n', bufLen(&wp->input))) == 0) { /* Incomplete line */ canProceed = 0; break; } *nextTok++ = '\0'; nbytes = nextTok - line; websConsumeInput(wp, nbytes); strim(line, "\r", WEBS_TRIM_END); len = strlen(line); if (line[len - 1] == '\r') { line[len - 1] = '\0'; } } switch (wp->uploadState) { case 0: initUpload(wp); break; case UPLOAD_BOUNDARY: processContentBoundary(wp, line); break; case UPLOAD_CONTENT_HEADER: processUploadHeader(wp, line); break; case UPLOAD_CONTENT_DATA: canProceed = processContentData(wp); if (bufLen(&wp->input) < wp->boundaryLen) { /* Incomplete boundary - return to get more data */ canProceed = 0; } break; case UPLOAD_CONTENT_END: break; } } bufCompact(&wp->input); return canProceed; }
PUBLIC int websProcessUploadData(Webs *wp) { char *line, *nextTok; ssize len, nbytes; int done, rc; for (done = 0, line = 0; !done; ) { if (wp->uploadState == UPLOAD_BOUNDARY || wp->uploadState == UPLOAD_CONTENT_HEADER) { /* Parse the next input line */ line = wp->input.servp; if ((nextTok = memchr(line, '\n', bufLen(&wp->input))) == 0) { /* Incomplete line */ break; } *nextTok++ = '\0'; nbytes = nextTok - line; websConsumeInput(wp, nbytes); strim(line, "\r", WEBS_TRIM_END); len = strlen(line); if (line[len - 1] == '\r') { line[len - 1] = '\0'; } } switch (wp->uploadState) { case 0: if (initUpload(wp) < 0) { done++; } break; case UPLOAD_BOUNDARY: if (processContentBoundary(wp, line) < 0) { done++; } break; case UPLOAD_CONTENT_HEADER: if (processUploadHeader(wp, line) < 0) { done++; } break; case UPLOAD_CONTENT_DATA: if ((rc = processContentData(wp)) < 0) { done++; } if (bufLen(&wp->input) < wp->boundaryLen) { /* Incomplete boundary - return to get more data */ done++; } break; case UPLOAD_CONTENT_END: done++; break; } } if (!websValid(wp)) { return -1; } bufCompact(&wp->input); return 0; }
/* Incoming data acceptance routine. The service queue is used, but not a service routine as the data is processed immediately. Partial data is buffered on the service queue until a correct mime boundary is seen. */ static void incomingUpload(HttpQueue *q, HttpPacket *packet) { HttpConn *conn; HttpRx *rx; MprBuf *content; Upload *up; char *line, *nextTok; ssize count; int done, rc; assert(packet); conn = q->conn; rx = conn->rx; up = q->queueData; if (conn->error) { return; } if (httpGetPacketLength(packet) == 0) { if (up->contentState != HTTP_UPLOAD_CONTENT_END) { httpError(conn, HTTP_CODE_BAD_REQUEST, "Client supplied insufficient upload data"); } httpPutPacketToNext(q, packet); return; } /* Put the packet data onto the service queue for buffering. This aggregates input data incase we don't have a complete mime record yet. */ httpJoinPacketForService(q, packet, 0); packet = q->first; content = packet->content; count = httpGetPacketLength(packet); for (done = 0, line = 0; !done; ) { if (up->contentState == HTTP_UPLOAD_BOUNDARY || up->contentState == HTTP_UPLOAD_CONTENT_HEADER) { /* Parse the next input line */ line = mprGetBufStart(content); if ((nextTok = memchr(line, '\n', mprGetBufLength(content))) == 0) { /* Incomplete line */ break; } *nextTok++ = '\0'; mprAdjustBufStart(content, (int) (nextTok - line)); line = strim(line, "\r", MPR_TRIM_END); } switch (up->contentState) { case HTTP_UPLOAD_BOUNDARY: if (processUploadBoundary(q, line) < 0) { done++; } break; case HTTP_UPLOAD_CONTENT_HEADER: if (processUploadHeader(q, line) < 0) { done++; } break; case HTTP_UPLOAD_CONTENT_DATA: rc = processUploadData(q); if (rc < 0) { done++; } if (httpGetPacketLength(packet) < up->boundaryLen) { /* Incomplete boundary - return to get more data */ done++; } break; case HTTP_UPLOAD_CONTENT_END: done++; break; } } q->count -= (count - httpGetPacketLength(packet)); assert(q->count >= 0); if (httpGetPacketLength(packet) == 0) { /* Quicker to remove the buffer so the packets don't have to be joined the next time */ httpGetPacket(q); } else { /* Compact the buffer to prevent memory growth. There is often residual data after the boundary for the next block. */ if (packet != rx->headerPacket) { mprCompactBuf(content); } } }