예제 #1
0
/*
    Get a character from the file. This will put the file into buffered mode.
 */
PUBLIC int mprGetFileChar(MprFile *file)
{
    MprBuf      *bp;
    ssize     len;

    assert(file);

    if (file == 0) {
        return MPR_ERR;
    }
    if (file->buf == 0) {
        file->buf = mprCreateBuf(ME_MAX_BUFFER, ME_MAX_BUFFER);
    }
    bp = file->buf;

    if (mprGetBufLength(bp) == 0) {
        len = fillBuf(file);
        if (len <= 0) {
            return -1;
        }
    }
    if (mprGetBufLength(bp) == 0) {
        return 0;
    }
    file->pos++;
    return mprGetCharFromBuf(bp);
}
예제 #2
0
/*
 *  Add a packet to the io vector. Return the number of bytes added to the vector.
 */
static void addPacketForNet(MaQueue *q, MaPacket *packet)
{
    MaResponse  *resp;
    MaConn      *conn;
    MprIOVec    *iovec;
    int         index, mask;

    conn = q->conn;
    resp = conn->response;
    iovec = q->iovec;
    index = q->ioIndex;

    mprAssert(q->count >= 0);
    mprAssert(q->ioIndex < (MA_MAX_IOVEC - 2));

    if (packet->prefix) {
        addToNetVector(q, mprGetBufStart(packet->prefix), mprGetBufLength(packet->prefix));
    }
    if (maGetPacketLength(packet) > 0) {
        addToNetVector(q, mprGetBufStart(packet->content), mprGetBufLength(packet->content));
    }
    mask = MA_TRACE_RESPONSE | ((packet->flags & MA_PACKET_HEADER) ? MA_TRACE_HEADERS : MA_TRACE_BODY);
    if (maShouldTrace(conn, mask)) {
        maTraceContent(conn, packet, 0, resp->bytesWritten, mask);
    }
}
예제 #3
0
파일: ejsHttp.c 프로젝트: soffmodd/ejs-2
/*  
    Read the required number of bytes into the response content buffer. Count < 0 means transfer the entire content.
    Returns the number of bytes read. Returns null on EOF.
 */ 
static ssize readHttpData(Ejs *ejs, EjsHttp *hp, ssize count)
{
    MprBuf      *buf;
    HttpConn    *conn;
    ssize       len, space, nbytes;

    conn = hp->conn;
    buf = hp->responseContent;
    mprResetBufIfEmpty(buf);
    while (count < 0 || mprGetBufLength(buf) < count) {
        len = (count < 0) ? BIT_MAX_BUFFER : (count - mprGetBufLength(buf));
        space = mprGetBufSpace(buf);
        if (space < len) {
            mprGrowBuf(buf, len - space);
        }
        if ((nbytes = httpRead(conn, mprGetBufEnd(buf), len)) < 0) {
            ejsThrowIOError(ejs, "Cannot read required data");
            return MPR_ERR_CANT_READ;
        }
        mprAdjustBufEnd(buf, nbytes);
        if (hp->conn->async || (nbytes == 0 && conn->state > HTTP_STATE_CONTENT)) {
            break;
        }
    }
    if (count < 0) {
        return mprGetBufLength(buf);
    }
    return min(count, mprGetBufLength(buf));
}
예제 #4
0
static void freeNetPackets(HttpQueue *q, ssize bytes)
{
    HttpPacket    *packet;
    ssize         len;

    mprAssert(q->count >= 0);
    mprAssert(bytes >= 0);

    while (bytes > 0 && (packet = q->first) != 0) {
        if (packet->prefix) {
            len = mprGetBufLength(packet->prefix);
            len = min(len, bytes);
            mprAdjustBufStart(packet->prefix, len);
            bytes -= len;
            /* Prefixes don't count in the q->count. No need to adjust */
            if (mprGetBufLength(packet->prefix) == 0) {
                packet->prefix = 0;
            }
        }
        if (packet->content) {
            len = mprGetBufLength(packet->content);
            len = min(len, bytes);
            mprAdjustBufStart(packet->content, len);
            bytes -= len;
            q->count -= len;
            mprAssert(q->count >= 0);
        }
        if (packet->content == 0 || mprGetBufLength(packet->content) == 0) {
            /*
                This will remove the packet from the queue and will re-enable upstream disabled queues.
             */
            httpGetPacket(q);
        }
    }
}
예제 #5
0
/*
 *  Add a packet to the io vector. Return the number of bytes added to the vector.
 */
static void addPacketForSend(MaQueue *q, MaPacket *packet)
{
    MaResponse  *resp;
    MaConn      *conn;
    MprIOVec    *iovec;
    int         mask;

    conn = q->conn;
    resp = conn->response;
    iovec = q->iovec;
    
    mprAssert(q->count >= 0);
    mprAssert(q->ioIndex < (MA_MAX_IOVEC - 2));

    if (packet->prefix) {
        addToSendVector(q, mprGetBufStart(packet->prefix), mprGetBufLength(packet->prefix));
    }
    if (packet->esize > 0) {
        mprAssert(q->ioFile == 0);
        q->ioFile = 1;
        q->ioCount += packet->esize;

    } else if (maGetPacketLength(packet) > 0) {
        /*
         *  Header packets have actual content. File data packets are virtual and only have a count.
         */
        addToSendVector(q, mprGetBufStart(packet->content), mprGetBufLength(packet->content));
        mask = (packet->flags & MA_PACKET_HEADER) ? MA_TRACE_HEADERS : MA_TRACE_BODY;
        if (maShouldTrace(conn, mask)) {
            maTraceContent(conn, packet, 0, resp->bytesWritten, mask);
        }
    }
}
예제 #6
0
파일: request.c 프로젝트: gamman/appweb-3
void maTraceContent(MaConn *conn, MaPacket *packet, int64 size, int64 offset, int mask)
{
    MaHost  *host;
    int     len;

    mprAssert(conn->trace);
    host = conn->host;

    if (offset >= host->traceMaxLength) {
        mprLog(conn, conn->host->traceLevel, "Abbreviating response trace for conn %d", conn->seqno);
        conn->trace = 0;
        return;
    }
    if (size <= 0) {
        size = INT_MAX;
    }
    if (packet->prefix) {
        len = mprGetBufLength(packet->prefix);
        len = (int) min(len, size);
        traceBuf(conn, mprGetBufStart(packet->prefix), len, mask);
    }
    if (packet->content) {
        len = mprGetBufLength(packet->content);
        len = (int) min(len, size);
        traceBuf(conn, mprGetBufStart(packet->content), len, mask);
    }
}
예제 #7
0
PUBLIC int mprFlushFile(MprFile *file)
{
    MprFileSystem   *fs;
    MprBuf          *bp;
    ssize           len, rc;

    assert(file);
    if (file == 0) {
        return MPR_ERR_BAD_HANDLE;
    }
    if (file->buf == 0) {
        return 0;
    }
    if (file->mode & (O_WRONLY | O_RDWR)) {
        fs = file->fileSystem;
        bp = file->buf;
        while (mprGetBufLength(bp) > 0) {
            len = mprGetBufLength(bp);
            rc = fs->writeFile(file, mprGetBufStart(bp), len);
            if (rc < 0) {
                return (int) rc;
            }
            mprAdjustBufStart(bp, rc);
        }
        mprFlushBuf(bp);
    }
    return 0;
}
예제 #8
0
/*
    Peek at a character from the file without disturbing the read position. This will put the file into buffered mode.
 */
PUBLIC int mprPeekFileChar(MprFile *file)
{
    MprBuf      *bp;
    ssize       len;

    assert(file);

    if (file == 0) {
        return MPR_ERR;
    }
    if (file->buf == 0) {
        file->buf = mprCreateBuf(ME_MAX_BUFFER, ME_MAX_BUFFER);
    }
    bp = file->buf;

    if (mprGetBufLength(bp) == 0) {
        len = fillBuf(file);
        if (len <= 0) {
            return -1;
        }
    }
    if (mprGetBufLength(bp) == 0) {
        return 0;
    }
    return ((uchar*) mprGetBufStart(bp))[0];
}
예제 #9
0
/*
    Read a line from the file. This will put the file into buffered mode.
    Return NULL on eof.
 */
PUBLIC char *mprReadLine(MprFile *file, ssize maxline, ssize *lenp)
{
    MprBuf          *bp;
    MprFileSystem   *fs;
    ssize           size, len, nlen, consumed;
    cchar           *eol, *newline, *start;
    char            *result;

    assert(file);

    if (file == 0) {
        return NULL;
    }
    if (lenp) {
        *lenp = 0;
    }
    if (maxline <= 0) {
        maxline = ME_MAX_BUFFER;
    }
    fs = file->fileSystem;
    newline = fs->newline;
    if (file->buf == 0) {
        file->buf = mprCreateBuf(maxline, maxline);
    }
    bp = file->buf;

    result = NULL;
    size = 0;
    do {
        if (mprGetBufLength(bp) == 0) {
            if (fillBuf(file) <= 0) {
                return result;
            }
        }
        start = mprGetBufStart(bp);
        len = mprGetBufLength(bp);
        if ((eol = findNewline(start, newline, len, &nlen)) != 0) {
            len = eol - start;
            consumed = len + nlen;
        } else {
            consumed = len;
        }
        file->pos += (MprOff) consumed;
        if (lenp) {
            *lenp += len;
        }
        if ((result = mprRealloc(result, size + len + 1)) == 0) {
            return NULL;
        }
        memcpy(&result[size], start, len);
        size += len;
        result[size] = '\0';
        mprAdjustBufStart(bp, consumed);
    } while (!eol);

    return result;
}
예제 #10
0
static void browserToCgiService(HttpQueue *q)
{
    HttpConn    *conn;
    HttpPacket  *packet;
    Cgi         *cgi;
    MprCmd      *cmd;
    MprBuf      *buf;
    ssize       rc, len;
    int         err;

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

    for (packet = httpGetPacket(q); packet; packet = httpGetPacket(q)) {
        if ((buf = packet->content) == 0) {
            /* End packet */
            continue;
        }
        len = mprGetBufLength(buf);
        rc = mprWriteCmd(cmd, MPR_CMD_STDIN, mprGetBufStart(buf), len);
        if (rc < 0) {
            err = mprGetError();
            if (err == EINTR) {
                continue;
            } else if (err == EAGAIN || err == EWOULDBLOCK) {
                httpPutBackPacket(q, packet);
                break;
            }
            mprLog(2, "CGI: write to gateway failed for %d bytes, rc %d, errno %d", len, rc, mprGetOsError());
            mprCloseCmdFd(cmd, MPR_CMD_STDIN);
            httpDiscardQueueData(q, 1);
            httpError(conn, HTTP_CODE_BAD_GATEWAY, "Cannot write body data to CGI gateway");
            break;
        }
        mprTrace(6, "CGI: browserToCgiService %d/%d, qmax %d", rc, len, q->max);
        mprAdjustBufStart(buf, rc);
        if (mprGetBufLength(buf) > 0) {
            httpPutBackPacket(q, packet);
            break;
        }
    }
    if (q->count > 0) {
        /* Wait for writable event so cgiCallback can recall this routine */
        mprEnableCmdEvents(cmd, MPR_CMD_STDIN);
    } else if (conn->rx->eof) {
        mprCloseCmdFd(cmd, MPR_CMD_STDIN);
    } else {
        mprDisableCmdEvents(cmd, MPR_CMD_STDIN);
    }
}
예제 #11
0
static void freeSendPackets(HttpQueue *q, MprOff bytes)
{
    HttpPacket  *packet;
    ssize       len;

    assert(q->first);
    assert(q->count >= 0);
    assert(bytes >= 0);

    /*
        Loop while data to be accounted for and we have not hit the end of data packet
        There should be 2-3 packets on the queue. A header packet for the HTTP response headers, an optional
        data packet with packet->esize set to the size of the file, and an end packet with no content.
        Must leave this routine with the end packet still on the queue and all bytes accounted for.
     */
    while ((packet = q->first) != 0 && !(packet->flags & HTTP_PACKET_END) && bytes > 0) {
        if (packet->prefix) {
            len = mprGetBufLength(packet->prefix);
            len = (ssize) min(len, bytes);
            mprAdjustBufStart(packet->prefix, len);
            bytes -= len;
            /* Prefixes don't count in the q->count. No need to adjust */
            if (mprGetBufLength(packet->prefix) == 0) {
                packet->prefix = 0;
            }
        }
        if (packet->esize) {
            len = (ssize) min(packet->esize, bytes);
            packet->esize -= len;
            packet->epos += len;
            bytes -= len;
            assert(packet->esize >= 0);

        } else if ((len = httpGetPacketLength(packet)) > 0) {
            /* Header packets come here */
            len = (ssize) min(len, bytes);
            mprAdjustBufStart(packet->content, len);
            bytes -= len;
            q->count -= len;
            assert(q->count >= 0);
        }
        if (packet->esize == 0 && httpGetPacketLength(packet) == 0) {
            /* Done with this packet - consume it */
            assert(!(packet->flags & HTTP_PACKET_END));
            httpGetPacket(q);
        } else {
            break;
        }
    }
    assert(bytes == 0);
}
예제 #12
0
int mprPuts(MprFile *file, const char *writeBuf, uint count)
{
	MprBuf	*bp;
	char	*buf;
	int		total, bytes, len;

	mprAssert(file);

	/*
	 *	Buffer output and flush when full.
	 */
	if (file->buf == 0) {
		file->buf = mprCreateBuf(file, MPR_BUFSIZE, 0);
		if (file->buf == 0) {
			return MPR_ERR_CANT_ALLOCATE;
		}
	}
	bp = file->buf;

	if (mprGetBufLength(bp) > 0 && mprGetBufSpace(bp) < (int) count) {
		len = mprGetBufLength(bp);
		if (mprWrite(file, mprGetBufStart(bp), len) != len) {
			return MPR_ERR_CANT_WRITE;
		}
		mprFlushBuf(bp);
	}

	total = 0;
	buf = (char*) writeBuf;

	while (count > 0) {
		bytes = mprPutBlockToBuf(bp, buf, count);
		if (bytes <= 0) {
			return MPR_ERR_CANT_ALLOCATE;
		}
		count -= bytes;
		buf += bytes;
		total += bytes;
		mprAddNullToBuf(bp);

		if (count > 0) {
			len = mprGetBufLength(bp);
			if (mprWrite(file, mprGetBufStart(bp), len) != len) {
				return MPR_ERR_CANT_WRITE;
			}
			mprFlushBuf(bp);
		}
	}
	return total;
}
예제 #13
0
/*
 *  Clear entries from the IO vector that have actually been transmitted. This supports partial writes due to the socket
 *  being full. Don't come here if we've seen all the packets and all the data has been completely written. ie. small files
 *  don't come here.
 */
static void freeSentPackets(MaQueue *q, int64 bytes)
{
    MaPacket    *packet;
    int64       len;

    mprAssert(q->first);
    mprAssert(q->count >= 0);
    mprAssert(bytes >= 0);

    while ((packet = q->first) != 0) {
        if (packet->prefix) {
            len = mprGetBufLength(packet->prefix);
            len = min(len, bytes);
            mprAdjustBufStart(packet->prefix, (int) len);
            bytes -= len;
            /* Prefixes don't count in the q->count. No need to adjust */
            if (mprGetBufLength(packet->prefix) == 0) {
                mprFree(packet->prefix);
                packet->prefix = 0;
            }
        }
        if (packet->esize) {
            len = min(packet->esize, bytes);
            packet->esize -= len;
            packet->epos += len;
            bytes -= len;
            mprAssert(packet->esize >= 0);
            mprAssert(bytes == 0);
            if (packet->esize > 0) {
                break;
            }
        } else if ((len = maGetPacketLength(packet)) > 0) {
            len = min(len, bytes);
            mprAdjustBufStart(packet->content, (int) len);
            bytes -= len;
            q->count -= (int) len;
            mprAssert(q->count >= 0);
        }
        if (maGetPacketLength(packet) == 0) {
            if ((packet = maGet(q)) != 0) {
                maFreePacket(q, packet);
            }
        }
        mprAssert(bytes >= 0);
        if (bytes == 0) {
            break;
        }
    }
}
예제 #14
0
파일: queue.c 프로젝트: gamman/appweb-3
/*
 *  Return true if the packet is too large to be accepted by the downstream queue.
 */
bool maPacketTooBig(MaQueue *q, MaPacket *packet)
{
    int     size;
    
    size = mprGetBufLength(packet->content);
    return size > q->max || size > q->packetSize;
}
예제 #15
0
static void printBodyData(MaQueue *q)
{
    MprBuf  *buf;
    char    **keys, *value;
    int     i, numKeys;
    
    if (q->pair == 0 || q->pair->first == 0) {
        return;
    }
    
    buf = q->pair->first->content;
    mprAddNullToBuf(buf);
    
    numKeys = getVars(q, &keys, mprGetBufStart(buf), mprGetBufLength(buf));

    if (numKeys == 0) {
        maWrite(q, "<H2>No Body Data Found</H2>\r\n");
    } else {
        maWrite(q, "<H2>Decoded Body Data</H2>\r\n");
        for (i = 0; i < (numKeys * 2); i += 2) {
            value = keys[i+1];
            maWrite(q, "<p>PVAR %s=%s</p>\r\n", keys[i], value ? value: "");
        }
    }
    maWrite(q, "\r\n");
    mprFree(keys);
    mprFree(buf);
}
예제 #16
0
/*
    Write data back to the client (browser). Must be locked when called.
 */
static int writeToClient(MaQueue *q, MprCmd *cmd, MprBuf *buf, int channel)
{
    MaConn  *conn;
    int     rc, len;

    conn = q->conn;

    /*
        Write to the browser. We write as much as we can. Service queues to get the filters and connectors pumping.
     */
    while ((len = mprGetBufLength(buf)) > 0) {
        if (!conn->requestFailed) {
            rc = maWriteBlock(q, mprGetBufStart(buf), len, 1);
            mprLog(q, 5, "CGI: write %d bytes to client. Rc rc %d, errno %d", len, rc, mprGetOsError());
        } else {
            /* Request has failed so just eat the data */
            rc = len;
            mprAssert(len > 0);
        }
        if (rc < 0) {
            return MPR_ERR_CANT_WRITE;
        }
        mprAssert(rc == len);
        mprAdjustBufStart(buf, rc);
        mprResetBufIfEmpty(buf);
        maServiceQueues(conn);
    }
    return 0;
}
예제 #17
0
파일: request.c 프로젝트: gamman/appweb-3
/*
 *  Get the next input token. The content buffer is advanced to the next token. This routine always returns a 
 *  non-zero token. The empty string means the delimiter was not found.
 */
static char *getToken(MaConn *conn, cchar *delim)
{
    MprBuf  *buf;
    char    *token, *nextToken;
    int     len;

    mprAssert(mprGetParent(conn->input) == conn);

    buf = conn->input->content;
    len = mprGetBufLength(buf);
    if (len == 0) {
        return "";
    }

    token = mprGetBufStart(buf);
    nextToken = mprStrnstr(mprGetBufStart(buf), delim, len);
    if (nextToken) {
        *nextToken = '\0';
        len = (int) strlen(delim);
        nextToken += len;
        buf->start = nextToken;

    } else {
        buf->start = mprGetBufEnd(buf);
        mprAddNullToBuf(buf);
    }
    return token;
}
예제 #18
0
/*
    Add a packet to the io vector. Return the number of bytes added to the vector.
 */
static void addPacketForSend(HttpQueue *q, HttpPacket *packet)
{
    HttpConn     *conn;

    conn = q->conn;
    assert(q->count >= 0);
    assert(q->ioIndex < (ME_MAX_IOVEC - 2));

    if (packet->prefix) {
        addToSendVector(q, mprGetBufStart(packet->prefix), mprGetBufLength(packet->prefix));
    }
    if (packet->esize > 0) {
        assert(q->ioFile == 0);
        q->ioFile = 1;
        q->ioCount += packet->esize;

    } else if (httpGetPacketLength(packet) > 0) {
        /*
            Header packets have actual content. File data packets are virtual and only have a count.
         */
        addToSendVector(q, mprGetBufStart(packet->content), httpGetPacketLength(packet));
        if (httpTracing(conn) && packet->flags & HTTP_PACKET_DATA) {
            httpTraceBody(conn, 1, packet, -1);
        }
    }
}
예제 #19
0
파일: http.c 프로젝트: varphone/ejs-2
static int setContentLength(HttpConn *conn, MprList *files)
{
    MprPath     info;
    MprOff      len;
    char        *path, *pair;
    int         next;

    len = 0;
    if (app->upload) {
        httpEnableUpload(conn);
        return 0;
    }
    for (next = 0; (path = mprGetNextItem(files, &next)) != 0; ) {
        if (strcmp(path, "-") != 0) {
            if (mprGetPathInfo(path, &info) < 0) {
                mprError("Can't access file %s", path);
                return MPR_ERR_CANT_ACCESS;
            }
            len += info.size;
        }
    }
    if (app->formData) {
        for (next = 0; (pair = mprGetNextItem(app->formData, &next)) != 0; ) {
            len += slen(pair);
        }
        len += mprGetListLength(app->formData) - 1;
    }
    if (app->bodyData) {
        len += mprGetBufLength(app->bodyData);
    }
    if (len > 0) {
        httpSetContentLength(conn, len);
    }
    return 0;
}
예제 #20
0
파일: mprBuf.c 프로젝트: embedthis/mpr-3
int mprGetBlockFromBuf(MprBuf *bp, char *buf, int size)
{
    int     thisLen, bytesRead;

    mprAssert(buf);
    mprAssert(size >= 0);
    mprAssert(bp->buflen == (bp->endbuf - bp->data));

    /*
     *  Get the max bytes in a straight copy
     */
    bytesRead = 0;
    while (size > 0) {
        thisLen = mprGetBufLength(bp);
        thisLen = min(thisLen, size);
        if (thisLen <= 0) {
            break;
        }

        memcpy(buf, bp->start, thisLen);
        buf += thisLen;
        bp->start += thisLen;
        size -= thisLen;
        bytesRead += thisLen;
    }
    return bytesRead;
}
예제 #21
0
파일: trace.c 프로젝트: DavidQuan/http
/*
    Trace any packet
 */
PUBLIC bool httpTracePacket(HttpConn *conn, cchar *event, cchar *type, HttpPacket *packet, cchar *values, ...)
{
    va_list     ap;
    int         level;

    assert(conn);
    assert(packet);

    if (!conn || conn->http->traceLevel == 0 || conn->rx->skipTrace) {
        return 0;
    }
    level = PTOI(mprLookupKey(conn->trace->events, type));
    if (level == 0 || level > conn->http->traceLevel) { \
        return 0;
    }
    if (packet->prefix) {
        httpTraceContent(conn, event, type, mprGetBufStart(packet->prefix), mprGetBufLength(packet->prefix), 0);
    }
    if (values) {
        va_start(ap, values);
        values = sfmtv(values, ap);
        va_end(ap);
    }
    if (packet->content) {
        if (values) {
            httpTraceContent(conn, event, type, mprGetBufStart(packet->content), httpGetPacketLength(packet), "%s", values);
        } else {
            httpTraceContent(conn, event, type, mprGetBufStart(packet->content), httpGetPacketLength(packet), 0);
        }
    }
    return 1;
}
예제 #22
0
파일: request.c 프로젝트: gamman/appweb-3
/*
 *  Complete the request and return true if there is a pipelined request following.
 */
bool maProcessCompletion(MaConn *conn)
{
    MaRequest   *req;
    MaPacket    *packet;
    bool        more;

    mprAssert(conn->state == MPR_HTTP_STATE_COMPLETE);

    req = conn->request;
    maLogRequest(conn);

#if BLD_DEBUG
    mprLog(req, 4, "Request complete used %,d K, conn usage %,d K, mpr usage %,d K, page usage %,d K", 
        req->arena->allocBytes / 1024, conn->arena->allocBytes / 1024, mprGetMpr(conn)->heap.allocBytes / 1024, 
        mprGetMpr(conn)->pageHeap.allocBytes / 1024);
    /* mprPrintAllocReport(mprGetMpr(conn), "Before completing request"); */
#endif

    packet = conn->input;
    more = packet && (mprGetBufLength(packet->content) > 0);
    if (mprGetParent(packet) != conn) {
        if (more) {
            conn->input = maSplitPacket(conn, packet, 0);
            mprAssert(mprGetParent(conn->input) == conn);
        } else {
            conn->input = 0;
        }
    }

    /*
     *  This will free the request, response, pipeline and call maPrepConnection to reset the state.
     */
    mprFree(req->arena);
    return (conn->disconnected || conn->connectionFailed) ? 0 : more;
}
예제 #23
0
파일: queue.c 프로젝트: adammendoza/http
/*
    Read data. If sync mode, this will block. If async, will never block.
    Will return what data is available up to the requested size. 
    Returns a count of bytes read. Returns zero if not data. EOF if returns zero and conn->state is > HTTP_STATE_CONTENT.
 */
PUBLIC ssize httpRead(HttpConn *conn, char *buf, ssize size)
{
    HttpPacket  *packet;
    HttpQueue   *q;
    MprBuf      *content;
    ssize       nbytes, len;

    q = conn->readq;
    assert(q->count >= 0);
    assert(size >= 0);
    VERIFY_QUEUE(q);

    while (q->count <= 0 && !conn->async && !conn->error && conn->sock && (conn->state <= HTTP_STATE_CONTENT)) {
        httpServiceQueues(conn);
        if (conn->sock) {
            httpWait(conn, 0, MPR_TIMEOUT_NO_BUSY);
        }
    }
    conn->lastActivity = conn->http->now;

    for (nbytes = 0; size > 0 && q->count > 0; ) {
        if ((packet = q->first) == 0) {
            break;
        }
        content = packet->content;
        len = mprGetBufLength(content);
        len = min(len, size);
        assert(len <= q->count);
        if (len > 0) {
            len = mprGetBlockFromBuf(content, buf, len);
            assert(len <= q->count);
        }
        buf += len;
        size -= len;
        q->count -= len;
        assert(q->count >= 0);
        nbytes += len;
        if (mprGetBufLength(content) == 0) {
            httpGetPacket(q);
        }
    }
    assert(q->count >= 0);
    if (nbytes < size) {
        buf[nbytes] = '\0';
    }
    return nbytes;
}
예제 #24
0
파일: conn.c 프로젝트: embedthis/appweb-3
/*
 *  Get the packet into which to read data. This may be owned by the connection or if mid-request, may be owned by the
 *  request. Also return in *bytesToRead the length of data to attempt to read.
 */
static inline MaPacket *getPacket(MaConn *conn, int *bytesToRead)
{
    MaPacket    *packet;
    MaRequest   *req;
    MprBuf      *content;
    MprOff      remaining;
    int         len;

    req = conn->request;
    len = MA_BUFSIZE;

    /*
     *  The input packet may have pipelined headers and data left from the prior request. It may also have incomplete
     *  chunk boundary data.
     */
    if ((packet = conn->input) == NULL) {
        conn->input = packet = maCreateConnPacket(conn, len);

    } else {
        content = packet->content;
        mprResetBufIfEmpty(content);
        if (req) {
            /*
             *  Don't read more than the remainingContent unless chunked. We do this to minimize requests split 
             *  across packets.
             */
            if (req->remainingContent) {
                remaining = req->remainingContent;
                if (req->flags & MA_REQ_CHUNKED) {
                    remaining = max(remaining, MA_BUFSIZE);
                }
                len = (int) min(remaining, MAXINT);
            }
            len = min(len, MA_BUFSIZE);
            mprAssert(len > 0);
            if (mprGetBufSpace(content) < len) {
                mprGrowBuf(content, len);
            }

        } else {
            /*
             *  Still reading the request headers
             */
            if (mprGetBufLength(content) >= conn->http->limits.maxHeader) {
                maFailConnection(conn, MPR_HTTP_CODE_REQUEST_TOO_LARGE, "Header too big");
                return 0;
            }
            if (mprGetBufSpace(content) < MA_BUFSIZE) {
                mprGrowBuf(content, MA_BUFSIZE);
            }
            len = mprGetBufSpace(content);
        }
    }
    mprAssert(len > 0);
    *bytesToRead = len;
    return packet;
}
예제 #25
0
static void freeNetPackets(MaQueue *q, int64 bytes)
{
    MaPacket    *packet;
    int         len;

    mprAssert(q->first);
    mprAssert(q->count >= 0);
    mprAssert(bytes >= 0);

    while ((packet = q->first) != 0) {
        if (packet->prefix) {
            len = mprGetBufLength(packet->prefix);
            len = (int) min(len, bytes);
            mprAdjustBufStart(packet->prefix, len);
            bytes -= len;
            /* Prefixes don't count in the q->count. No need to adjust */
            if (mprGetBufLength(packet->prefix) == 0) {
                mprFree(packet->prefix);
                packet->prefix = 0;
            }
        }

        if (packet->content) {
            len = mprGetBufLength(packet->content);
            len = (int) min(len, bytes);
            mprAdjustBufStart(packet->content, len);
            bytes -= len;
            q->count -= len;
            mprAssert(q->count >= 0);
        }
        if (packet->content == 0 || mprGetBufLength(packet->content) == 0) {
            /*
             *  This will remove the packet from the queue and will re-enable upstream disabled queues.
             */
            if ((packet = maGet(q)) != 0) {
                maFreePacket(q, packet);
            }
        }
        mprAssert(bytes >= 0);
        if (bytes == 0) {
            break;
        }
    }
}
예제 #26
0
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);
            }
        }
    }
}
예제 #27
0
파일: mprBuf.c 프로젝트: embedthis/mpr-3
void mprCompactBuf(MprBuf *bp)
{
    if (mprGetBufLength(bp) == 0) {
        mprFlushBuf(bp);
        return;
    }
    if (bp->start > bp->data) {
        memmove(bp->data, bp->start, (bp->end - bp->start));
        bp->end -= (bp->start - bp->data);
        bp->start = bp->data;
    }
}
예제 #28
0
파일: ejsZlib.c 프로젝트: monmarzia/ejs-2
/*
    uncompressString(data: String): String
 */
static EjsString *zlib_uncompressString(Ejs *ejs, EjsObj *unused, int argc, EjsObj **argv)
{
    EjsString       *in;
    MprBuf          *out;
    z_stream        zs;
    uchar           outbuf[ZBUFSIZE];
    ssize           nbytes, size;
    int             rc;

    in = (EjsString*) argv[0];
    if ((out = mprCreateBuf(ZBUFSIZE, -1)) == 0) {
        return 0;
    }
    if ((size = in->length) == 0) {
        return ESV(empty);
    }
    zs.zalloc = Z_NULL;
    zs.zfree = Z_NULL;
    zs.opaque = Z_NULL;
    zs.avail_in = 0;
    rc = inflateInit(&zs);
    zs.next_in = (uchar*) in->value;
    zs.avail_in = (int) size;

    do {
        if (zs.avail_in == 0) {
            break;
        }
        do {
            zs.avail_out = ZBUFSIZE;
            zs.next_out = outbuf;
            if ((rc = inflate(&zs, Z_NO_FLUSH)) == Z_NEED_DICT) {
                inflateEnd(&zs);
                return 0;
            } else if (rc == Z_DATA_ERROR || rc == Z_MEM_ERROR) {
                inflateEnd(&zs);
                return 0;
            } else {
                nbytes = ZBUFSIZE - zs.avail_out;
            }
            if (mprPutBlockToBuf(out, (char*) outbuf, nbytes) != nbytes) {
                ejsThrowIOError(ejs, "Cannot copy to byte array");
                inflateEnd(&zs);
                return 0;
            }
        } while (zs.avail_out == 0);
        assure(zs.avail_in == 0);
    } while (rc != Z_STREAM_END);

    deflateEnd(&zs);
    return ejsCreateStringFromBytes(ejs, mprGetBufStart(out), mprGetBufLength(out));
}
예제 #29
0
파일: request.c 프로젝트: gamman/appweb-3
/*
 *  Parse a new request. Return true to keep going with this or subsequent request, zero means insufficient data to proceed.
 */
static bool parseRequest(MaConn *conn, MaPacket *packet) 
{
    MaRequest   *req;
    char        *start, *end;
    int         len;

    /*
     *  Must wait until we have the complete set of headers.
     */
    if ((len = mprGetBufLength(packet->content)) == 0) {
        return 0;
    }
    start = mprGetBufStart(packet->content);
    if ((end = mprStrnstr(start, "\r\n\r\n", len)) == 0) {
        return 0;
    }
    len = (int) (end - start);
    if (len >= conn->host->limits->maxHeader) {
        maFailConnection(conn, MPR_HTTP_CODE_REQUEST_TOO_LARGE, "Header too big");
        return 0;
    }
    if (parseFirstLine(conn, packet)) {
        parseHeaders(conn, packet);
    } else {
        return 0;
    }
    maMatchHandler(conn);
    
    /*
     *  Have read the headers. Create the request pipeline. This calls the open() stage entry routines.
     */
    maCreatePipeline(conn);

    req = conn->request;
    if (conn->connectionFailed) {
        /* Discard input data */
        mprAssert(conn->keepAliveCount <= 0);
        conn->state = MPR_HTTP_STATE_PROCESSING;
        maRunPipeline(conn);
    } else if (req->remainingContent > 0) {
        conn->state = MPR_HTTP_STATE_CONTENT;
    } else if (req->length == -1 && (req->method == MA_REQ_POST || req->method == MA_REQ_PUT)) {
        conn->state = MPR_HTTP_STATE_CONTENT;
    } else {
        /*
         *  Can run the request now if there is no incoming data.
         */
        conn->state = MPR_HTTP_STATE_PROCESSING;
        maRunPipeline(conn);
    }
    return !conn->disconnected;
}
예제 #30
0
/*
    Add a packet to the io vector. Return the number of bytes added to the vector.
 */
static void addPacketForNet(HttpQueue *q, HttpPacket *packet)
{
    HttpTx      *tx;
    HttpConn    *conn;
    int         item;

    conn = q->conn;
    tx = conn->tx;

    mprAssert(q->count >= 0);
    mprAssert(q->ioIndex < (HTTP_MAX_IOVEC - 2));

    if (packet->prefix) {
        addToNetVector(q, mprGetBufStart(packet->prefix), mprGetBufLength(packet->prefix));
    }
    if (httpGetPacketLength(packet) > 0) {
        addToNetVector(q, mprGetBufStart(packet->content), mprGetBufLength(packet->content));
    }
    item = (packet->flags & HTTP_PACKET_HEADER) ? HTTP_TRACE_HEADER : HTTP_TRACE_BODY;
    if (httpShouldTrace(conn, HTTP_TRACE_TX, item, tx->ext) >= 0) {
        httpTraceContent(conn, HTTP_TRACE_TX, item, packet, 0, (ssize) tx->bytesWritten);
    }
}