/* * Grow the buffer. Return 0 if the buffer grows. Increase by the growBy size specified when creating the buffer. */ int mprGrowBuf(MprBuf *bp, int need) { char *newbuf; int growBy; if (bp->maxsize > 0 && bp->buflen >= bp->maxsize) { return MPR_ERR_TOO_MANY; } if (bp->start > bp->end) { mprCompactBuf(bp); } if (need > 0) { growBy = max(bp->growBy, need); } else { growBy = bp->growBy; } if ((newbuf = mprAlloc(bp, bp->buflen + growBy)) == 0) { mprAssert(!MPR_ERR_NO_MEMORY); return MPR_ERR_NO_MEMORY; } if (bp->data) { memcpy(newbuf, bp->data, bp->buflen); mprFree(bp->data); } bp->buflen += growBy; bp->end = newbuf + (bp->end - bp->data); bp->start = newbuf + (bp->start - bp->data); bp->data = newbuf; bp->endbuf = &bp->data[bp->buflen]; /* * Increase growBy to reduce overhead */ if (bp->maxsize > 0) { if ((bp->buflen + (bp->growBy * 2)) > bp->maxsize) { bp->growBy = min(bp->maxsize - bp->buflen, bp->growBy * 2); } } else { if ((bp->buflen + (bp->growBy * 2)) > bp->maxsize) { bp->growBy = min(bp->buflen, bp->growBy * 2); } } 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); } } }