Пример #1
0
static void startFileHandler(HttpQueue *q)
{
    HttpConn    *conn;
    HttpRx      *rx;
    HttpTx      *tx;
    HttpPacket  *packet;

    conn = q->conn;
    rx = conn->rx;
    tx = conn->tx;
    
    if (tx->finalized || conn->error) {
        return;

    } else if (rx->flags & HTTP_PUT) {
        handlePutRequest(q);
        
    } else if (rx->flags & HTTP_DELETE) {
        handleDeleteRequest(q);
        
    } else if (rx->flags & HTTP_OPTIONS) {
        httpHandleOptions(q->conn);
        
    } else if (!(tx->flags & HTTP_TX_NO_BODY)) {
        /* Create a single data packet based on the entity length */
        packet = httpCreateEntityPacket(0, tx->entityLength, readFileData);
        if (!tx->outputRanges) {
            /* Can set a content length */
            tx->length = tx->entityLength;
        }
        /* Add to the output service queue */
        httpPutForService(q, packet, 0);
    }
}
Пример #2
0
/*
    Accept incoming body data from the client destined for the CGI gateway. This is typically POST or PUT data.
    Note: For POST "form" requests, this will be called before the command is actually started. 
 */
static void browserToCgiData(HttpQueue *q, HttpPacket *packet)
{
    HttpConn    *conn;
    Cgi         *cgi;

    assert(q);
    assert(packet);
    if ((cgi = q->queueData) == 0) {
        return;
    }
    conn = q->conn;
    assert(q == conn->readq);

    if (httpGetPacketLength(packet) == 0) {
        /* End of input */
        if (conn->rx->remainingContent > 0) {
            /* Short incoming body data. Just kill the CGI process */
            if (cgi->cmd) {
                mprDestroyCmd(cgi->cmd);
            }
            httpError(conn, HTTP_CODE_BAD_REQUEST, "Client supplied insufficient body data");
        }
    }
    httpPutForService(cgi->writeq, packet, HTTP_SCHEDULE_QUEUE);
}
Пример #3
0
PUBLIC void httpFinalizeOutput(HttpConn *conn)
{
    HttpTx      *tx;

    tx = conn->tx;
    if (!tx || tx->finalizedOutput) {
        return;
    }
    tx->responded = 1;
    tx->finalizedOutput = 1;
    assert(conn->writeq);
    if (conn->writeq == tx->queue[HTTP_QUEUE_TX]) {
        /* Tx Pipeline not yet created */
        tx->pendingFinalize = 1;
        return;
    }
    assert(conn->state >= HTTP_STATE_CONNECTED);
    /*
        This may be called from httpError when the connection fails.
     */
    if (conn->sock) {
        httpPutForService(conn->writeq, httpCreateEndPacket(), HTTP_SCHEDULE_QUEUE);
        httpServiceQueues(conn);
    }
}
Пример #4
0
/*
    Put packets on the service queue.
 */
static void outgoing(HttpQueue *q, HttpPacket *packet)
{
    int     enableService;

    /*
        Handlers service routines must only be auto-enabled if better than ready.
     */
    enableService = !(q->stage->flags & HTTP_STAGE_HANDLER) || (q->conn->state >= HTTP_STATE_READY) ? 1 : 0;
    httpPutForService(q, packet, enableService);
}
Пример #5
0
static ssize doOutput(HttpQueue *q, cchar *data, ssize len)
{
    HttpPacket  *packet;
    ssize       count;

    count = min(len, q->max - q->count);
    count = min(count, q->packetSize);
    packet = httpCreateDataPacket(count);
    mprPutBlockToBuf(packet->content, data, len);
    httpPutForService(q, packet, HTTP_SCHEDULE_QUEUE);
    return count;
}
Пример #6
0
/*
    Incoming data routine.  Simply transfer the data upstream to the next filter or handler.
 */
static void incoming(HttpQueue *q, HttpPacket *packet)
{
    assert(q);
    assert(packet);

    if (q->nextQ->put) {
        httpPutPacketToNext(q, packet);
    } else {
        /* This queue is the last queue in the pipeline */
        if (httpGetPacketLength(packet) > 0) {
            if (packet->flags & HTTP_PACKET_SOLO) {
                httpPutForService(q, packet, HTTP_DELAY_SERVICE);
            } else {
                httpJoinPacketForService(q, packet, 0);
            }
        } else {
            /* Zero length packet means eof */
            httpPutForService(q, packet, HTTP_DELAY_SERVICE);
        }
        HTTP_NOTIFY(q->conn, HTTP_EVENT_READABLE, 0);
    }
}
Пример #7
0
static void startFileHandler(HttpQueue *q)
{
    HttpConn    *conn;
    HttpRx      *rx;
    HttpTx      *tx;
    HttpPacket  *packet;

	int beint;
				
	printf("\n  startFileHandler  \n");

    conn = q->conn;
    rx = conn->rx;
    tx = conn->tx;
    assure(!tx->finalized);
    
    if (rx->flags & HTTP_PUT) {
        handlePutRequest(q);
        
    } else if (rx->flags & HTTP_DELETE) {
        handleDeleteRequest(q);
        
    } else if (!(tx->flags & HTTP_TX_NO_BODY)) {
        /* Create a single data packet based on the entity length */
        packet = httpCreateEntityPacket(0, tx->entityLength, readFileData);
        if (!tx->outputRanges) {
            /* Can set a content length */
			
			if(strcmp(tx->filename ,"C:\\Project\\appweb-4.2.0\\windows-x86-vsdebug\\web\\movie.mp4") == 0)
			{	
				tx->cacheBuffer = 0;
				tx->length = 400000;

			}
			else
			{
				tx->length = tx->entityLength;
			}	
	beint = tx->length;

	printf("\n--------------------\n");
	printf("beint,tx->filename : %d \t +%s+",beint,tx->filename);
	printf("\n--------------------\n");


        }
        /* Add to the output service queue */
        httpPutForService(q, packet, 0);
    }

}
Пример #8
0
/*
    Run the handler. This is called when all input data has been received.
 */
static void processSimple(HttpQueue *q)
{
    HttpConn    *conn;

    conn = q->conn;
    httpSetHeader(conn, 0, "Last-Modified", conn->http->currentDate);

    /*
        Create the empty header packet. This will be filled in by the downstream network connector stage.
     */
    httpPutForService(q, httpCreateHeaderPacket(conn), 0);

    /*
        Generate some dynamic data. If you generate a lot, this will buffer up to a configured maximum. 
        If that limit is exceeded, the packet will be sent downstream and the response headers will be created.
     */
    httpWrite(q, "Hello World");

    /*
        Send an end of data packet
     */
    httpPutForService(q, httpCreateEndPacket(conn), 1);
}
Пример #9
0
static void incomingEjs(HttpQueue *q, HttpPacket *packet)
{
    HttpConn        *conn;
    HttpRx          *rx;

    conn = q->conn;
    rx = conn->rx;

    if (httpGetPacketLength(packet) == 0) {
        if (rx->remainingContent > 0) {
            httpError(conn, HTTP_CODE_BAD_REQUEST, "Client supplied insufficient body data");
        }
        httpPutForService(q, packet, 0);
    } else {
        httpJoinPacketForService(q, packet, 0);
    }
    HTTP_NOTIFY(q->conn, HTTP_EVENT_READABLE, 0);
}
Пример #10
0
void httpCreateTxPipeline(HttpConn *conn, HttpRoute *route)
{
    Http        *http;
    HttpTx      *tx;
    HttpRx      *rx;
    HttpQueue   *q;
    HttpStage   *stage, *filter;
    int         next, hasOutputFilters;

    mprAssert(conn);
    mprAssert(route);

    http = conn->http;
    rx = conn->rx;
    tx = conn->tx;

    tx->outputPipeline = mprCreateList(-1, 0);
    if (tx->handler == 0) {
        tx->handler = http->passHandler;
    }
    mprAddItem(tx->outputPipeline, tx->handler);

    hasOutputFilters = 0;
    if (route->outputStages) {
        for (next = 0; (filter = mprGetNextItem(route->outputStages, &next)) != 0; ) {
            if (matchFilter(conn, filter, route, HTTP_STAGE_TX) == HTTP_ROUTE_OK) {
                mprAddItem(tx->outputPipeline, filter);
                mprLog(4, "Select output filter: \"%s\"", filter->name);
                hasOutputFilters = 1;
            }
        }
    }
    if (tx->connector == 0) {
        if (tx->handler == http->fileHandler && (rx->flags & HTTP_GET) && !hasOutputFilters && 
                !conn->secure && httpShouldTrace(conn, HTTP_TRACE_TX, HTTP_TRACE_BODY, tx->ext) < 0) {
            tx->connector = http->sendConnector;
        } else if (route && route->connector) {
            tx->connector = route->connector;
        } else {
            tx->connector = http->netConnector;
        }
    }
    mprAddItem(tx->outputPipeline, tx->connector);
    mprLog(4, "Select connector: \"%s\"", tx->connector->name);

    /*  Create the outgoing queue heads and open the queues */
    q = tx->queue[HTTP_QUEUE_TX];
    for (next = 0; (stage = mprGetNextItem(tx->outputPipeline, &next)) != 0; ) {
        q = httpCreateQueue(conn, stage, HTTP_QUEUE_TX, q);
    }
    conn->writeq = tx->queue[HTTP_QUEUE_TX]->nextQ;
    conn->connectorq = tx->queue[HTTP_QUEUE_TX]->prevQ;
    pairQueues(conn);

    /*
        Put the header before opening the queues incase an open routine actually services and completes the request
        httpHandleOptionsTrace does this when called from openFile() in fileHandler.
     */
    httpPutForService(conn->writeq, httpCreateHeaderPacket(), HTTP_DELAY_SERVICE);
    openQueues(conn);

    /*
        Refinalize if httpFinalize was called before the Tx pipeline was created
     */
    if (conn->refinalize) {
        conn->finalized = 0;
        httpFinalize(conn);
    }
}
Пример #11
0
PUBLIC void httpCreateTxPipeline(HttpConn *conn, HttpRoute *route)
{
    Http        *http;
    HttpTx      *tx;
    HttpRx      *rx;
    HttpQueue   *q;
    HttpStage   *stage, *filter;
    int         next, hasOutputFilters;

    assert(conn);
    assert(route);

    http = conn->http;
    rx = conn->rx;
    tx = conn->tx;

    tx->outputPipeline = mprCreateList(-1, 0);
    if (conn->endpoint) {
        if (tx->handler == 0 || tx->finalized) {
            tx->handler = http->passHandler;
        }
        mprAddItem(tx->outputPipeline, tx->handler);
    }
    hasOutputFilters = 0;
    if (route->outputStages) {
        for (next = 0; (filter = mprGetNextItem(route->outputStages, &next)) != 0; ) {
            if (matchFilter(conn, filter, route, HTTP_STAGE_TX) == HTTP_ROUTE_OK) {
                mprAddItem(tx->outputPipeline, filter);
                if (rx->traceLevel >= 0) {
                    mprLog(rx->traceLevel, "Select output filter: \"%s\"", filter->name);
                }
                hasOutputFilters = 1;
            }
        }
    }
    if (tx->connector == 0) {
#if !BIT_ROM
        if (tx->handler == http->fileHandler && (rx->flags & HTTP_GET) && !hasOutputFilters && 
                !conn->secure && httpShouldTrace(conn, HTTP_TRACE_TX, HTTP_TRACE_BODY, tx->ext) < 0) {
            tx->connector = http->sendConnector;
        } else 
#endif
        if (route && route->connector) {
            tx->connector = route->connector;
        } else {
            tx->connector = http->netConnector;
        }
    }
    mprAddItem(tx->outputPipeline, tx->connector);
    if (rx->traceLevel >= 0) {
        mprLog(rx->traceLevel + 1, "Select connector: \"%s\"", tx->connector->name);
    }
    /*  Create the outgoing queue heads and open the queues */
    q = tx->queue[HTTP_QUEUE_TX];
    for (next = 0; (stage = mprGetNextItem(tx->outputPipeline, &next)) != 0; ) {
        q = httpCreateQueue(conn, stage, HTTP_QUEUE_TX, q);
    }
    conn->connectorq = tx->queue[HTTP_QUEUE_TX]->prevQ;

    /*
        Double the connector max hi-water mark. This optimization permits connectors to accept packets without 
        unnecesary flow control.
     */
    conn->connectorq->max *= 2;

    pairQueues(conn);

    /*
        Put the header before opening the queues incase an open routine actually services and completes the request
     */
    httpPutForService(conn->writeq, httpCreateHeaderPacket(), HTTP_DELAY_SERVICE);

    /*
        Open the pipelien stages. This calls the open entrypoints on all stages
     */
    openQueues(conn);
}
Пример #12
0
static void cgiToBrowserData(HttpQueue *q, HttpPacket *packet)
{
    httpPutForService(q->conn->writeq, packet, HTTP_SCHEDULE_QUEUE);
}
Пример #13
0
PUBLIC void httpCreateTxPipeline(HttpConn *conn, HttpRoute *route)
{
    Http        *http;
    HttpTx      *tx;
    HttpRx      *rx;
    HttpQueue   *q;
    HttpStage   *stage, *filter;
    int         next;

    assert(conn);
    assert(route);

    http = conn->http;
    rx = conn->rx;
    tx = conn->tx;

    tx->outputPipeline = mprCreateList(-1, MPR_LIST_STABLE);
    if (httpServerConn(conn)) {
        if (tx->handler == 0 || tx->finalized) {
            tx->handler = http->passHandler;
        }
        mprAddItem(tx->outputPipeline, tx->handler);
    }
    if (route->outputStages) {
        for (next = 0; (filter = mprGetNextItem(route->outputStages, &next)) != 0; ) {
            if (matchFilter(conn, filter, route, HTTP_STAGE_TX) == HTTP_ROUTE_OK) {
                mprAddItem(tx->outputPipeline, filter);
                tx->flags |= HTTP_TX_HAS_FILTERS;
            }
        }
    }
    if (tx->connector == 0) {
#if !ME_ROM
        if (tx->handler == http->fileHandler && (rx->flags & HTTP_GET) && !(tx->flags & HTTP_TX_HAS_FILTERS) && 
                !conn->secure && !httpTracing(conn)) {
            tx->connector = http->sendConnector;
        } else 
#endif
        tx->connector = (route && route->connector) ? route->connector : http->netConnector;
    }
    mprAddItem(tx->outputPipeline, tx->connector);

    /*  Create the outgoing queue heads and open the queues */
    q = tx->queue[HTTP_QUEUE_TX];
    for (next = 0; (stage = mprGetNextItem(tx->outputPipeline, &next)) != 0; ) {
        q = httpCreateQueue(conn, stage, HTTP_QUEUE_TX, q);
    }
    conn->connectorq = tx->queue[HTTP_QUEUE_TX]->prevQ;

    /*
        Double the connector max hi-water mark. This optimization permits connectors to accept packets without 
        unnecesary flow control.
     */
    conn->connectorq->max *= 2;

    pairQueues(conn);

    /*
        Put the header before opening the queues incase an open routine actually services and completes the request
     */
    httpPutForService(conn->writeq, httpCreateHeaderPacket(), HTTP_DELAY_SERVICE);

    /*
        Open the pipeline stages. This calls the open entrypoints on all stages.
     */
    openQueues(conn);

    if (conn->error) {
        if (tx->handler != http->passHandler) {
            tx->handler = http->passHandler;
            httpAssignQueue(conn->writeq, tx->handler, HTTP_QUEUE_TX);
        }
    }
    tx->flags |= HTTP_TX_PIPELINE;

    if (conn->endpoint) {
        httpTrace(conn, "request.pipeline", "context",  
            "route:'%s',handler:'%s',target:'%s',endpoint:'%s:%d',host:'%s',referrer:'%s',filename:'%s'",
            rx->route->pattern, tx->handler->name, rx->route->targetRule, conn->endpoint->ip, conn->endpoint->port,
            conn->host->name ? conn->host->name : "default", rx->referrer ? rx->referrer : "", 
            tx->filename ? tx->filename : "");
    }
}
Пример #14
0
PUBLIC void httpDefaultIncoming(HttpQueue *q, HttpPacket *packet)
{
    assert(q);
    assert(packet);
    httpPutForService(q, packet, HTTP_DELAY_SERVICE);
}
Пример #15
0
/*
    Write a block of data. This is the lowest level write routine for data. This will buffer the data and flush if
    the queue buffer is full. Flushing is done by calling httpFlushQueue which will service queues as required. This
    may call the queue outgoing service routine and disable downstream queues if they are overfull.
    This routine will always accept the data and never return "short". 
 */
PUBLIC ssize httpWriteBlock(HttpQueue *q, cchar *buf, ssize len, int flags)
{
    HttpPacket  *packet;
    HttpConn    *conn;
    HttpTx      *tx;
    ssize       totalWritten, packetSize, thisWrite;

    assert(q == q->conn->writeq);
    conn = q->conn;
    tx = conn->tx;
    if (flags == 0) {
        flags = HTTP_BUFFER;
    }
    if (tx == 0 || tx->finalizedOutput) {
        return MPR_ERR_CANT_WRITE;
    }
    tx->responded = 1;

    for (totalWritten = 0; len > 0; ) {
        mprTrace(7, "httpWriteBlock q_count %d, q_max %d", q->count, q->max);
        if (conn->state >= HTTP_STATE_FINALIZED) {
            return MPR_ERR_CANT_WRITE;
        }
        if (q->last && q->last != q->first && q->last->flags & HTTP_PACKET_DATA && mprGetBufSpace(q->last->content) > 0) {
            packet = q->last;
        } else {
            packetSize = (tx->chunkSize > 0) ? tx->chunkSize : q->packetSize;
            if ((packet = httpCreateDataPacket(packetSize)) == 0) {
                return MPR_ERR_MEMORY;
            }
            httpPutForService(q, packet, HTTP_DELAY_SERVICE);
        }
        assert(mprGetBufSpace(packet->content) > 0);
        thisWrite = min(len, mprGetBufSpace(packet->content));
        if (flags & (HTTP_BLOCK | HTTP_NON_BLOCK)) {
            thisWrite = min(thisWrite, q->max - q->count);
        }
        if (thisWrite > 0) {
            if ((thisWrite = mprPutBlockToBuf(packet->content, buf, thisWrite)) == 0) {
                return MPR_ERR_MEMORY;
            }
            buf += thisWrite;
            len -= thisWrite;
            q->count += thisWrite;
            totalWritten += thisWrite;
        }
        if (q->count >= q->max) {
            httpFlushQueue(q, 0);
            if (q->count >= q->max) {
                if (flags & HTTP_NON_BLOCK) {
                    break;
                } else if (flags & HTTP_BLOCK) {
                    while (q->count >= q->max && !tx->finalized) {
                        if (!mprWaitForSingleIO((int) conn->sock->fd, MPR_WRITABLE, conn->limits->inactivityTimeout)) {
                            return MPR_ERR_TIMEOUT;
                        }
                        httpResumeQueue(conn->connectorq);
                        httpServiceQueues(conn);
                    }
                }
            }
        }
    }
    if (conn->error) {
        return MPR_ERR_CANT_WRITE;
    }
    return totalWritten;
}
Пример #16
0
static void outgoingProxyData(HttpQueue *q)
{
#if UNUSED
    httpPutForService(q, packet, 1);
#endif
}
Пример #17
0
static void incomingProxyData(HttpQueue *q, HttpPacket *packet)
{
    httpPutForService(q, packet, 1);
}
Пример #18
0
static void processProxy(HttpQueue *q)
{
    int     count = 50000;
    
    q->max = 65536;
    
#if USE0
    /*
     May overflow q->max
     */
    while (sofar < count) {
        httpWrite(q, "%d aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n", sofar++);
    }
    httpFinalizeOutput(q->conn);
    sofar = 0;
#endif
    
    
#if USE1
    httpWrite(q, "%d aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n", sofar++);
    if (sofar == count) {
        httpFinalizeOutput(q->conn);
        sofar = 0;
    }
#endif
    
    
#if USE2
    while (sofar < count && q->count < (q->max * 3 / 4)) {
        /* NOTE: httpWrite may do internal flush if count > max */
        httpWrite(q, "%d aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n", sofar++);
    }
    if (sofar == count) {
        httpFinalizeOutput(q->conn);
        sofar = 0;
    }
#endif
    
    
#if USE3
    /*
        MANUAL FLOW CONTROL
     */
    HttpPacket  *packet;
    int         i, size;
    
    size = 1024;
    for (; sofar < count && q->count < q->max; sofar++) {
        packet = httpCreateDataPacket(size);
        for (i = 1; i < size - 1; i++) {
            mprPutCharToBuf(packet->content, 'a');
        }
        mprPutCharToBuf(packet->content, '\n');
        httpPutForService(q, packet, HTTP_DELAY_SERVICE);
    }
    if (sofar == count) {
        httpFinalizeOutput(q->conn);
        sofar = 0;
    }
#endif

#if USE4 || 1
    httpStealConn(q->conn);
#endif
}