/* Prepare a data packet for sending downstream. This involves reading file data into a suitably sized packet. Return the 1 if the packet was sent entirely, return zero if the packet could not be completely sent. Return a negative error code for write errors. This may split the packet if it exceeds the downstreams maximum packet size. */ static int prepPacket(HttpQueue *q, HttpPacket *packet) { HttpQueue *nextQ; ssize size, nbytes; if (mprNeedYield()) { httpScheduleQueue(q); return 0; } nextQ = q->nextQ; if (packet->esize > nextQ->packetSize) { httpPutBackPacket(q, httpSplitPacket(packet, nextQ->packetSize)); size = nextQ->packetSize; } else { size = (ssize) packet->esize; } if ((size + nextQ->count) > nextQ->max) { /* The downstream queue is full, so disable the queue and service downstream queue. Will re-enable via a writable event on the connection. */ httpSuspendQueue(q); if (!(nextQ->flags & HTTP_QUEUE_SUSPENDED)) { httpScheduleQueue(nextQ); } return 0; } if ((nbytes = readFileData(q, packet, q->ioPos, size)) != size) { return MPR_ERR_CANT_READ; } q->ioPos += nbytes; return 1; }
PUBLIC bool httpWillQueueAcceptPacket(HttpQueue *q, HttpPacket *packet, bool split) { ssize size; size = httpGetPacketLength(packet); if (size <= q->packetSize && (size + q->count) <= q->max) { return 1; } if (split) { if (httpResizePacket(q, packet, 0) < 0) { return 0; } size = httpGetPacketLength(packet); assert(size <= q->packetSize); if ((size + q->count) <= q->max) { return 1; } } /* The downstream queue is full, so disable the queue and mark the downstream queue as full and service */ if (!(q->flags & HTTP_QUEUE_SUSPENDED)) { httpScheduleQueue(q); } return 0; }
/* Return true if the next queue will accept this packet. If not, then disable the queue's service procedure. This may split the packet if it exceeds the downstreams maximum packet size. */ PUBLIC bool httpWillNextQueueAcceptPacket(HttpQueue *q, HttpPacket *packet) { HttpQueue *nextQ; ssize size; nextQ = q->nextQ; size = httpGetPacketLength(packet); if (size <= nextQ->packetSize && (size + nextQ->count) <= nextQ->max) { return 1; } if (httpResizePacket(q, packet, 0) < 0) { return 0; } size = httpGetPacketLength(packet); assert(size <= nextQ->packetSize); /* Packet size is now acceptable. Accept the packet if the queue is mostly empty (< low) or if the packet will fit entirely under the max or if the queue. NOTE: queue maximums are advisory. We choose to potentially overflow the max here to optimize the case where the queue may have say one byte and a max size packet would overflow by 1. */ if (nextQ->count < nextQ->low || (size + nextQ->count) <= nextQ->max) { return 1; } /* The downstream queue cannot accept this packet, so disable queue and mark the downstream queue as full and service */ httpSuspendQueue(q); if (!(nextQ->flags & HTTP_QUEUE_SUSPENDED)) { httpScheduleQueue(nextQ); } return 0; }
PUBLIC void httpServiceQueue(HttpQueue *q) { q->conn->currentq = q; if (q->servicing) { q->flags |= HTTP_QUEUE_RESERVICE; } else { /* Since we are servicing this "q" now, we can remove from the schedule queue if it is already queued. */ if (q->conn->serviceq->scheduleNext == q) { httpGetNextQueueForService(q->conn->serviceq); } if (!(q->flags & HTTP_QUEUE_SUSPENDED)) { q->servicing = 1; q->service(q); if (q->flags & HTTP_QUEUE_RESERVICE) { q->flags &= ~HTTP_QUEUE_RESERVICE; httpScheduleQueue(q); } q->flags |= HTTP_QUEUE_SERVICED; q->servicing = 0; } } }
static void readyError(HttpQueue *q) { if (!q->stream->error) { httpError(q->stream, HTTP_CODE_NOT_FOUND, "The requested resource is not available"); } httpFinalize(q->stream); httpScheduleQueue(q); }
/* Flush queue data by scheduling the queue and servicing all scheduled queues. Return true if there is room for more data. If blocking is requested, the call will block until the queue count falls below the queue max. WARNING: Be very careful when using blocking == true. Should only be used by end applications and not by middleware. */ PUBLIC bool httpFlushQueue(HttpQueue *q, bool blocking) { HttpConn *conn; HttpQueue *next; conn = q->conn; assert(conn->sock); do { httpScheduleQueue(q); next = q->nextQ; if (next->count > 0) { httpScheduleQueue(next); } httpServiceQueues(conn); if (conn->sock == 0) { break; } } while (blocking && q->count > 0 && !conn->tx->finalizedConnector); return (q->count < q->max) ? 1 : 0; }
/* Return true if the next queue will accept a certain amount of data. If not, then disable the queue's service procedure. Will not split the packet. */ PUBLIC bool httpWillNextQueueAcceptSize(HttpQueue *q, ssize size) { HttpQueue *nextQ; nextQ = q->nextQ; if (size <= nextQ->packetSize && (size + nextQ->count) <= nextQ->max) { return 1; } httpSuspendQueue(q); if (!(nextQ->flags & HTTP_QUEUE_SUSPENDED)) { httpScheduleQueue(nextQ); } return 0; }
int httpProcessHandler(HttpConn *conn) { HttpQueue *q; q = conn->writeq; if (!q->stage->writable) { return 0; } if (!conn->finalized) { q->stage->writable(q); if (q->count > 0) { httpScheduleQueue(q); httpServiceQueues(conn); } } return 1; }
static void readyPass(HttpQueue *q) { httpFinalize(q->stream); httpScheduleQueue(q); }
PUBLIC void httpResumeQueue(HttpQueue *q) { mprTrace(7, "Resume q %s", q->name); q->flags &= ~HTTP_QUEUE_SUSPENDED; httpScheduleQueue(q); }