/* * Split a packet if required so it fits in the downstream queue. Put back the 2nd portion of the split packet on the queue. * Ensure that the packet is not larger than "size" if it is greater than zero. */ int maResizePacket(MaQueue *q, MaPacket *packet, int size) { MaPacket *tail; MaConn *conn; MprCtx ctx; int len; conn = q->conn; if (size <= 0) { size = MAXINT; } ctx = conn->request ? (MprCtx) conn->request : (MprCtx) conn; if (packet->esize > size) { if ((tail = maSplitPacket(ctx, packet, size)) == 0) { return MPR_ERR_NO_MEMORY; } } else { /* * Calculate the size that will fit */ len = packet->content ? maGetPacketLength(packet) : 0; size = min(size, len); size = min(size, q->nextQ->max); size = min(size, q->nextQ->packetSize); if (size == 0 || size == len) { return 0; } if ((tail = maSplitPacket(ctx, packet, size)) == 0) { return MPR_ERR_NO_MEMORY; } } maPutBack(q, tail); return 0; }
/* * Apply chunks to dynamic outgoing data. */ static void outgoingChunkService(MaQueue *q) { MaConn *conn; MaPacket *packet; MaResponse *resp; conn = q->conn; resp = conn->response; if (!(q->flags & MA_QUEUE_SERVICED)) { /* * If the last packet is the end packet, we have all the data. Thus we know the actual content length * and can bypass the chunk handler. */ if (q->last->flags & MA_PACKET_END) { if (resp->chunkSize < 0 && resp->length <= 0) { /* * Set the response content length and thus disable chunking -- not needed as we know the entity length. */ resp->length = q->count; } } else { if (resp->chunkSize < 0 && resp->entityLength < 0) { resp->chunkSize = (int) min(conn->http->limits.maxChunkSize, q->max); } } } if (resp->chunkSize <= 0) { maDefaultOutgoingServiceStage(q); } else { for (packet = maGet(q); packet; packet = maGet(q)) { if (!(packet->flags & MA_PACKET_HEADER)) { if (maGetPacketLength(packet) > resp->chunkSize) { maResizePacket(q, packet, resp->chunkSize); } } if (!maWillNextQueueAccept(q, packet)) { maPutBack(q, packet); return; } if (!(packet->flags & MA_PACKET_HEADER)) { setChunkPrefix(q, packet); } maPutNext(q, packet); } } }
static void writeToCGI(MaQueue *q) { MaConn *conn; MaPacket *packet; MprCmd *cmd; MprBuf *buf; int len, rc, err; cmd = (MprCmd*) q->pair->queueData; mprAssert(cmd); conn = q->conn; for (packet = maGet(q); packet && !conn->requestFailed; packet = maGet(q)) { buf = packet->content; len = mprGetBufLength(buf); mprAssert(len > 0); rc = mprWriteCmdPipe(cmd, MPR_CMD_STDIN, mprGetBufStart(buf), len); mprLog(q, 5, "CGI: write %d bytes to gateway. Rc rc %d, errno %d", len, rc, mprGetOsError()); if (rc < 0) { err = mprGetError(); if (err == EINTR) { continue; } else if (err == EAGAIN || err == EWOULDBLOCK) { break; } mprLog(q, 2, "CGI: write to gateway failed for %d bytes, rc %d, errno %d", len, rc, mprGetOsError()); mprCloseCmdFd(cmd, MPR_CMD_STDIN); maFailRequest(conn, MPR_HTTP_CODE_BAD_GATEWAY, "Can't write body data to CGI gateway"); break; } else { mprLog(q, 5, "CGI: write to gateway %d bytes asked to write %d", rc, len); mprAdjustBufStart(buf, rc); if (mprGetBufLength(buf) > 0) { maPutBack(q, packet); } else { maFreePacket(q, packet); } } } }