Пример #1
0
static EjsString *joinArray(Ejs *ejs, EjsArray *ap, int argc, EjsObj **argv)
{
    EjsString       *sep, *sp;
    MprBuf          *buf;
    ssize           len;
    int             i, nonString;

    sep = (argc == 1) ? (EjsString*) argv[0] : NULL;
    if (sep == ESV(empty) && ap->length == 1 && ejsIs(ejs, ap->data[0], String)) {
        /* Optimized path for joining [string]. This happens frequently with fun(...args) */
        return (EjsString*) ap->data[0];
    }
    /*
        Get an estimate of the string length
     */
    len = 0;
    nonString = 0;
    for (i = 0; i < ap->length; i++) {
        sp = (EjsString*) ap->data[i];
        if (!ejsIs(ejs, sp, String)) {
            nonString = 1;
            continue;
        }
        len += sp->length;
    }
    if (sep) {
        len += (ap->length * sep->length);
    }
    if (nonString) {
        len += ME_MAX_BUFFER;
    }
    buf = mprCreateBuf(len + 1, -1);

    for (i = 0; i < ap->length; i++) {
        sp = (EjsString*) ap->data[i];
        if (!ejsIsDefined(ejs, sp)) {
            continue;
        }
        sp = ejsToString(ejs, sp);
        if (!ejsIsDefined(ejs, sp)) {
            continue;
        }
        if (i > 0 && sep) {
            mprPutBlockToBuf(buf, sep->value, sep->length);
        }
        mprPutBlockToBuf(buf, sp->value, sp->length);
    }
    mprAddNullToBuf(buf);
    return ejsCreateStringFromBytes(ejs, mprGetBufStart(buf), mprGetBufLength(buf));
}
Пример #2
0
int mprPutStringToBuf(MprBuf *bp, cchar *str)
{
    if (str) {
        return mprPutBlockToBuf(bp, str, (int) strlen(str));
    }
    return 0;
}
Пример #3
0
/*
 *  Split a packet at a given offset and return a new packet containing the data after the offset.
 *  The suffix data migrates to the new packet. 
 */
MaPacket *maSplitPacket(MprCtx ctx, MaPacket *orig, int offset)
{
    MaPacket    *packet;
    int         count, size;

    if (orig->esize) {
        if ((packet = maCreateEntityPacket(ctx, orig->epos + offset, orig->esize - offset, orig->fill)) == 0) {
            return 0;
        }
        orig->esize = offset;

    } else {
        if (offset >= maGetPacketLength(orig)) {
            mprAssert(offset < maGetPacketLength(orig));
            return 0;
        }
        count = maGetPacketLength(orig) - offset;
        size = max(count, MA_BUFSIZE);
        size = MA_PACKET_ALIGN(size);
        if ((packet = maCreateDataPacket(ctx, size)) == 0) {
            return 0;
        }
        mprAdjustBufEnd(orig->content, -count);
        if (mprPutBlockToBuf(packet->content, mprGetBufEnd(orig->content), count) != count) {
            return 0;
        }
#if BLD_DEBUG
        mprAddNullToBuf(orig->content);
#endif
    }
    packet->flags = orig->flags;
    return packet;
}
Пример #4
0
/*
 *  Write data to the client. Will buffer and flush as required. will create headers if required.
 */
static int writeBlock(void *handle, cchar *buf, int size)
{
    int     len, rc;

    len = mprGetBufLength(output);
    if ((len + size) < EJS_CGI_MAX_BUF) {
        rc = mprPutBlockToBuf(output, buf, size);
    } else {
        flushOutput(output);
        if (size < EJS_CGI_MAX_BUF) {
            rc = mprPutBlockToBuf(output, buf, size);
        } else {
            rc = write(1, (char*) buf, size);
        }
    }
    return rc;
}
Пример #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
/*
    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));
}
Пример #7
0
int mprPutSubStringToBuf(MprBuf *bp, cchar *str, int count)
{
    int     len;

    if (str) {
        len = (int) strlen(str);
        len = min(len, count);
        if (len > 0) {
            return mprPutBlockToBuf(bp, str, len);
        }
    }
    return 0;
}
Пример #8
0
/*
 *  Join two packets by pulling the content from the second into the first.
 */
int maJoinPacket(MaPacket *packet, MaPacket *p)
{
    int     len;

    mprAssert(packet->esize == 0);
    mprAssert(p->esize == 0);

    len = maGetPacketLength(p);
    if (mprPutBlockToBuf(packet->content, mprGetBufStart(p->content), len) != len) {
        return MPR_ERR_NO_MEMORY;
    }
    return 0;
}
Пример #9
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;
}
Пример #10
0
/*
    Put a string to the file. This will put the file into buffered mode.
 */
PUBLIC ssize mprPutFileString(MprFile *file, cchar *str)
{
    MprBuf  *bp;
    ssize   total, bytes, count;
    char    *buf;

    assert(file);
    count = slen(str);

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

    if (mprGetBufLength(bp) > 0 && mprGetBufSpace(bp) < count) {
        mprFlushFile(file);
    }
    total = 0;
    buf = (char*) str;

    while (count > 0) {
        bytes = mprPutBlockToBuf(bp, buf, count);
        if (bytes < 0) {
            return MPR_ERR_CANT_ALLOCATE;

        } else if (bytes == 0) {
            if (mprFlushFile(file) < 0) {
                return MPR_ERR_CANT_WRITE;
            }
            continue;
        }
        count -= bytes;
        buf += bytes;
        total += bytes;
        file->pos += (MprOff) bytes;
    }
    return total;
}
Пример #11
0
/*
    compressString(data: String): String
 */
static EjsString *zlib_compressString(Ejs *ejs, EjsObj *unused, int argc, EjsObj **argv)
{
    EjsString       *in;
    MprBuf          *out;
    z_stream        zs;
    uchar           outbuf[ZBUFSIZE];
    ssize           size, nbytes;
    int             level, flush;

    in = (EjsString*) argv[0];
    if ((size = in->length) == 0) {
        return ESV(empty);
    }
    if ((out = mprCreateBuf(in->length, 0)) == 0) {
        return 0;
    }
    zs.zalloc = Z_NULL;
    zs.zfree = Z_NULL;
    zs.opaque = Z_NULL;
    level = Z_DEFAULT_COMPRESSION;
    deflateInit(&zs, level);
    zs.next_in = (uchar*) in->value;
    zs.avail_in = (int) size;
    do {
        flush = (zs.avail_in == 0) ? Z_FINISH : Z_NO_FLUSH;
        do {
            zs.avail_out = ZBUFSIZE;
            zs.next_out = outbuf;
            deflate(&zs, flush);
            nbytes = ZBUFSIZE - zs.avail_out;
            if (mprPutBlockToBuf(out, (char*) outbuf, nbytes) != nbytes) {
                ejsThrowIOError(ejs, "Cannot copy to output buffer");
                deflateEnd(&zs);
                return 0;
            }
        } while (zs.avail_out == 0);
        assure(zs.avail_in == 0);
    } while (flush != Z_FINISH);

    deflateEnd(&zs);
    return ejsCreateStringFromBytes(ejs, mprGetBufStart(out), mprGetBufLength(out));
}
Пример #12
0
/*
 *  Write a block of data. This is the lowest level write routine for dynamic data. If block is true, this routine will 
 *  block until all the block is written. If block is false, then it may return without having written all the data.
 */
int maWriteBlock(MaQueue *q, cchar *buf, int size, bool block)
{
    MaPacket    *packet;
    MaConn      *conn;
    MaResponse  *resp;
    int         bytes, written, packetSize;

    mprAssert(q->stage->flags & MA_STAGE_HANDLER);
               
    conn = q->conn;
    resp = conn->response;
    packetSize = (resp->chunkSize > 0) ? resp->chunkSize : q->max;
    packetSize = min(packetSize, size);
    
    if ((q->flags & MA_QUEUE_DISABLED) || (q->count > 0 && (q->count + size) >= q->max)) {
        if (!drain(q, block)) {
            return 0;
        }
    }
    for (written = 0; size > 0; ) {
        if (q->count >= q->max && !drain(q, block)) {
            maCheckQueueCount(q);
            break;
        }
        if (conn->disconnected) {
            return MPR_ERR_CANT_WRITE;
        }
        if ((packet = maCreateDataPacket(q, packetSize)) == 0) {
            return MPR_ERR_NO_MEMORY;
        }
        if ((bytes = mprPutBlockToBuf(packet->content, buf, size)) == 0) {
            return MPR_ERR_NO_MEMORY;
        }
        buf += bytes;
        size -= bytes;
        written += bytes;
        maPutForService(q, packet, 1);
        maCheckQueueCount(q);
    }
    maCheckQueueCount(q);
    return written;
}
Пример #13
0
PUBLIC ssize mprWriteFile(MprFile *file, cvoid *buf, ssize count)
{
    MprFileSystem   *fs;
    MprBuf          *bp;
    ssize           bytes, written;

    assert(file);
    if (file == 0) {
        return MPR_ERR_BAD_HANDLE;
    }

    fs = file->fileSystem;
    bp = file->buf;
    written = 0;
    while (count > 0) {
        if (bp == 0) {
            if ((bytes = fs->writeFile(file, buf, count)) < 0) {
                return bytes;
            }
        } else {
            if ((bytes = mprPutBlockToBuf(bp, buf, count)) < 0) {
                return bytes;
            }
            if (bytes != count) {
                mprFlushFile(file);
            }
        }
        count -= bytes;
        written += bytes;
        buf = (char*) buf + bytes;
    }
    file->pos += (MprOff) written;
    if (file->pos > file->size) {
        file->size = file->pos;
    }
    return written;
}
Пример #14
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;
}
Пример #15
0
/*
    This will be enabled when caching is enabled for the route and there is no acceptable cache data to use.
    OR - manual caching has been enabled.
 */
static void outgoingCacheFilterService(HttpQueue *q)
{
    HttpPacket  *packet, *data;
    HttpConn    *conn;
    HttpTx      *tx;
    MprKey      *kp;
    cchar       *cachedData;
    ssize       size;
    int         foundDataPacket;

    conn = q->conn;
    tx = conn->tx;
    foundDataPacket = 0;
    cachedData = 0;

    if (tx->status < 200 || tx->status > 299) {
        tx->cacheBuffer = 0;
    }

    /*
        This routine will save cached responses to tx->cacheBuffer.
        It will also send cached data if the X-SendCache header is present. Normal caching is done by cacheHandler
     */
    if (mprLookupKey(conn->tx->headers, "X-SendCache") != 0) {
        if (fetchCachedResponse(conn)) {
            mprLog(3, "cacheFilter: write cached content for '%s'", conn->rx->uri);
            cachedData = setHeadersFromCache(conn, tx->cachedContent);
            tx->length = slen(cachedData);
        }
    }
    for (packet = httpGetPacket(q); packet; packet = httpGetPacket(q)) {
        if (!httpWillNextQueueAcceptPacket(q, packet)) {
            httpPutBackPacket(q, packet);
            return;
        }
        if (packet->flags & HTTP_PACKET_HEADER) {
            if (!cachedData && tx->cacheBuffer) {
                /*
                    Add defined headers to the start of the cache buffer. Separate with a double newline.
                 */
                mprPutFmtToBuf(tx->cacheBuffer, "X-Status: %d\n", tx->status);
                for (kp = 0; (kp = mprGetNextKey(tx->headers, kp)) != 0; ) {
                    mprPutFmtToBuf(tx->cacheBuffer, "%s: %s\n", kp->key, kp->data);
                }
                mprPutCharToBuf(tx->cacheBuffer, '\n');
            }

        } else if (packet->flags & HTTP_PACKET_DATA) {
            if (cachedData) {
                /*
                    Using X-SendCache. Replace the data with the cached response.
                 */
                mprFlushBuf(packet->content);
                mprPutBlockToBuf(packet->content, cachedData, (ssize) tx->length);

            } else if (tx->cacheBuffer) {
                /*
                    Save the response packet to the cache buffer. Will write below in saveCachedResponse.
                 */
                size = mprGetBufLength(packet->content);
                if ((tx->cacheBufferLength + size) < conn->limits->cacheItemSize) {
                    mprPutBlockToBuf(tx->cacheBuffer, mprGetBufStart(packet->content), mprGetBufLength(packet->content));
                    tx->cacheBufferLength += size;
                } else {
                    tx->cacheBuffer = 0;
                    mprLog(3, "cacheFilter: Item too big to cache %d bytes, limit %d", tx->cacheBufferLength + size,
                        conn->limits->cacheItemSize);
                }
            }
            foundDataPacket = 1;

        } else if (packet->flags & HTTP_PACKET_END) {
            if (cachedData && !foundDataPacket) {
                /*
                    Using X-SendCache but there was no data packet to replace. So do the write here
                 */
                data = httpCreateDataPacket((ssize) tx->length);
                mprPutBlockToBuf(data->content, cachedData, (ssize) tx->length);
                httpPutPacketToNext(q, data);

            } else if (tx->cacheBuffer) {
                /*
                    Save the cache buffer to the cache store
                 */
                saveCachedResponse(conn);
            }
        }
        httpPutPacketToNext(q, packet);
    }
}
Пример #16
0
static EjsString *serialize(Ejs *ejs, EjsAny *vp, Json *json)
{
    EjsName     qname;
    EjsFunction *fn;
    EjsString   *result, *sv;
    EjsTrait    *trait;
    EjsObj      *pp, *obj, *replacerArgs[2];
    wchar       *cp;
    cchar       *key;
    int         c, isArray, i, count, slotNum, quotes;

    /*
        The main code below can handle Arrays, Objects, objects derrived from Object and also native classes with properties.
        All others just use toString.
     */
    count = ejsIsPot(ejs, vp) ? ejsGetLength(ejs, vp) : 0;
    if (count == 0 && TYPE(vp) != ESV(Object) && TYPE(vp) != ESV(Array)) {
        //  OPT - need some flag for this test.
        if (!ejsIsDefined(ejs, vp) || ejsIs(ejs, vp, Boolean) || ejsIs(ejs, vp, Number)) {
            return ejsToString(ejs, vp);
        } else if (json->regexp) {
            return ejsToString(ejs, vp);
        } else {
            return ejsToLiteralString(ejs, vp);
        }
    }
    obj = vp;
    json->nest++;
    if (json->buf == 0) {
        json->buf = mprCreateBuf(0, 0);
        mprAddRoot(json->buf);
    }
    isArray = ejsIs(ejs, vp, Array);
    mprPutCharToWideBuf(json->buf, isArray ? '[' : '{');
    if (json->pretty) {
        mprPutCharToWideBuf(json->buf, '\n');
    }
    if (++ejs->serializeDepth <= json->depth && !VISITED(obj)) {
        SET_VISITED(obj, 1);
        for (slotNum = 0; slotNum < count && !ejs->exception; slotNum++) {
            trait = ejsGetPropertyTraits(ejs, obj, slotNum);
            if (trait && (trait->attributes & (EJS_TRAIT_HIDDEN | EJS_TRAIT_DELETED | EJS_FUN_INITIALIZER | 
                    EJS_FUN_MODULE_INITIALIZER)) && !json->hidden) {
                continue;
            }
            pp = ejsGetProperty(ejs, obj, slotNum);
            if (ejs->exception) {
                SET_VISITED(obj, 0);
                json->nest--;
                return 0;
            }
            if (pp == 0) {
                continue;
            }
            if (isArray) {
                key = itos(slotNum);
                qname.name = ejsCreateStringFromAsc(ejs, key);
                qname.space = ESV(empty);
            } else {
                qname = ejsGetPropertyName(ejs, vp, slotNum);
            }

            quotes = json->quotes;
            if (!quotes) {
                //  UNICODE
                for (cp = qname.name->value; cp < &qname.name->value[qname.name->length]; cp++) {
                    if (!isalnum((uchar) *cp) && *cp != '_') {
                        quotes = 1;
                        break;
                    }
                }
            }
            if (json->pretty) {
                for (i = 0; i < ejs->serializeDepth; i++) {
                    mprPutStringToWideBuf(json->buf, json->indent);
                }
            }
            if (!isArray) {
                if (json->namespaces) {
                    if (qname.space != ESV(empty)) {
                        mprPutToBuf(json->buf, "\"%@\"::", qname.space);
                    }
                }
                if (quotes) {
                    mprPutCharToWideBuf(json->buf, '"');
                }
                for (cp = qname.name->value; cp && *cp; cp++) {
                    c = *cp;
                    if (c == '"' || c == '\\') {
                        mprPutCharToWideBuf(json->buf, '\\');
                        mprPutCharToWideBuf(json->buf, c);
                    } else {
                        mprPutCharToWideBuf(json->buf, c);
                    }
                }
                if (quotes) {
                    mprPutCharToWideBuf(json->buf, '"');
                }
                mprPutCharToWideBuf(json->buf, ':');
                if (json->pretty) {
                    mprPutCharToWideBuf(json->buf, ' ');
                }
            }
            fn = (EjsFunction*) ejsGetPropertyByName(ejs, TYPE(pp)->prototype, N(NULL, "toJSON"));
            // OPT - check that this is going directly to serialize most of the time
            if (!ejsIsFunction(ejs, fn) || (fn->isNativeProc && fn->body.proc == (EjsProc) ejsObjToJSON)) {
                sv = serialize(ejs, pp, json);
            } else {
                sv = (EjsString*) ejsRunFunction(ejs, fn, pp, 1, &json->options);
            }
            if (sv == 0 || !ejsIs(ejs, sv, String)) {
                if (ejs->exception) {
                    ejsThrowTypeError(ejs, "Cannot serialize property %@", qname.name);
                    SET_VISITED(obj, 0);
                    return 0;
                }
            } else {
                if (json->replacer) {
                    replacerArgs[0] = (EjsObj*) qname.name; 
                    replacerArgs[1] = (EjsObj*) sv; 

                    /* function replacer(key: String, value: String): String */
                    sv = ejsRunFunction(ejs, json->replacer, obj, 2, (EjsObj**) replacerArgs);
                }
                mprPutBlockToBuf(json->buf, sv->value, sv->length * sizeof(wchar));
            }
            if ((slotNum + 1) < count || json->commas) {
                mprPutCharToWideBuf(json->buf, ',');
            }
            if (json->pretty) {
                mprPutCharToWideBuf(json->buf, '\n');
            }
        }
        SET_VISITED(obj, 0);
    }
    --ejs->serializeDepth; 
    if (json->pretty) {
        for (i = ejs->serializeDepth; i > 0; i--) {
            mprPutStringToWideBuf(json->buf, json->indent);
        }
    }
    mprPutCharToWideBuf(json->buf, isArray ? ']' : '}');
    mprAddNullToWideBuf(json->buf);

    if (--json->nest == 0) {
        result = ejsCreateString(ejs, mprGetBufStart(json->buf), mprGetBufLength(json->buf) / sizeof(wchar));
        mprRemoveRoot(json->buf);
    } else {
        result = 0;
    }
    return result;
}
Пример #17
0
Token getNextJsonToken(MprBuf *buf, wchar **token, JsonState *js)
{
    wchar       *start, *cp, *end, *next;
    wchar       *src, *dest;
    int         quote, tid, c, isReg;

    if (buf) {
        mprFlushBuf(buf);
    }
    cp = js->next;
    end = js->end;
    cp = skipComments(cp, end);
    next = cp + 1;
    quote = -1;
    isReg = 0;

    if (*cp == '\0') {
        tid = TOK_EOF;

    } else  if (*cp == '{') {
        tid = TOK_LBRACE;

    } else if (*cp == '[') {
        tid = TOK_LBRACKET;

    } else if (*cp == '}' || *cp == ']') {
        tid = *cp == '}' ? TOK_RBRACE: TOK_RBRACKET;
        while (*++cp && isspace((uchar) *cp)) ;
#if NEW || 1
        /*
            Detect missing comma after closing brace/bracket
         */
        if (*cp && *cp != ',' && *cp != '}' && *cp != ']' && *cp != '/') {
            js->error = cp;
            return TOK_ERR;
        }
#endif
        if (*cp == ',' || *cp == ':') {
            cp++;
        }
        next = cp;

    } else {
        if (*cp == '"' || *cp == '\'') {
            tid = TOK_QID;
            quote = *cp++;
            for (start = cp; cp < end; cp++) {
                if (*cp == '\\' && &cp[1] < end) {
                    cp++;
                } else if (*cp == quote) {
                    break;
                }
            }
            if (*cp != quote) {
                js->error = cp;
                return TOK_ERR;
            }
            if (buf) {
                mprPutBlockToBuf(buf, (char*) start, (cp - start));
            }
            cp++;

        } else if (*cp == '/') {
            tid = TOK_ID;
            isReg = 1;
            for (start = cp++; cp < end; cp++) {
                if (*cp == '\\') {
                    if (cp[1] == '/') {
                        cp++;
                    }
                    continue;
                }
                if (*cp == '/') {
                    break;
                }
            }
            if (*cp != '/') {
                js->error = cp;
                return TOK_ERR;
            }
            if (buf) {
                mprPutBlockToBuf(buf, (char*) start, (cp - start + 1));
            }
            cp++;

        } else {
            /*
                Note: this is for keys and values
             */
            tid = TOK_ID;
            for (start = cp; cp < end; cp++) {
                if (*cp == '\\') {
                    continue;
                }
                /* 
                    Not an allowable character outside quotes (TODO - removed space 
                    Should really keep state for parsing keys or values and not allow -,+,. in keys
                 */
                if (!(isalnum((uchar) *cp) || *cp == '_' || *cp == '-' || *cp == '+' || *cp == '.')) {
                    break;
                }
            }
            if (buf) {
                mprPutBlockToBuf(buf, (char*) start, (int) (cp - start));
            }
        }
        if (buf) {
            mprAddNullToBuf(buf);
        }
        while (*cp && isspace((int) *cp)) cp++;
        if (*cp == ',' || *cp == ':') {
            cp++;
        } else if (*cp != '}' && *cp != ']' && *cp != '\0' && *cp != '\n' && *cp != '\r' && *cp != ' ') {
            js->error = cp;
            return TOK_ERR;
        }
        next = cp;

        if (buf) {
            for (dest = src = (wchar*) buf->start; src < (wchar*) buf->end; ) {
                c = *src++;
                if (c == '\\' && !isReg) {
                    c = *src++;
                    if (c == 'r') {
                        c = '\r';
                    } else if (c == 'n') {
                        c = '\n';
                    } else if (c == 'b') {
                        c = '\b';
                    }
                }
                *dest++ = c;
            }
            *dest = '\0';
            *token = (wchar*) mprGetBufStart(buf);
        }
    }
    js->next = next;
    return tid;
}
Пример #18
0
Token getNextJsonToken(MprBuf *buf, MprChar **token, JsonState *js)
{
    MprChar     *start, *cp, *end, *next;
    MprChar     *src, *dest;
    int         quote, tid, c;

    if (buf) {
        mprFlushBuf(buf);
    }
    cp = js->next;
    end = js->end;
    cp = skipComments(cp, end);
    next = cp + 1;
    quote = -1;

    if (*cp == '\0') {
        tid = TOK_EOF;

    } else  if (*cp == '{') {
        tid = TOK_LBRACE;

    } else if (*cp == '[') {
        tid = TOK_LBRACKET;

    } else if (*cp == '}' || *cp == ']') {
        tid = *cp == '}' ? TOK_RBRACE: TOK_RBRACKET;
        while (*++cp && isspace((uchar) *cp)) ;
        if (*cp == ',' || *cp == ':') {
            cp++;
        }
        next = cp;

    } else {
        if (*cp == '"' || *cp == '\'') {
            tid = TOK_QID;
            quote = *cp++;
            for (start = cp; cp < end; cp++) {
                if (*cp == '\\') {
                    if (cp[1] == quote) {
                        cp++;
                    }
                    continue;
                }
                if (*cp == quote) {
                    break;
                }
            }
            if (*cp != quote) {
                js->error = cp;
                return TOK_ERR;
            }
            if (buf) {
                mprPutBlockToBuf(buf, (char*) start, (cp - start));
            }
            cp++;

        } else if (*cp == '/') {
            tid = TOK_ID;
            for (start = cp++; cp < end; cp++) {
                if (*cp == '\\') {
                    if (cp[1] == '/') {
                        cp++;
                    }
                    continue;
                }
                if (*cp == '/') {
                    break;
                }
            }
            if (*cp != '/') {
                js->error = cp;
                return TOK_ERR;
            }
            if (buf) {
                mprPutBlockToBuf(buf, (char*) start, (cp - start));
            }
            cp++;

        } else {
            tid = TOK_ID;
            for (start = cp; cp < end; cp++) {
                if (*cp == '\\') {
                    continue;
                }
                /* Not an allowable character outside quotes */
                if (!(isalnum((uchar) *cp) || *cp == '_' || *cp == ' ' || *cp == '-' || *cp == '+' || *cp == '.')) {
                    break;
                }
            }
            if (buf) {
                mprPutBlockToBuf(buf, (char*) start, (int) (cp - start));
            }
        }
        if (buf) {
            mprAddNullToBuf(buf);
        }
        if (*cp == ',' || *cp == ':') {
            cp++;
        } else if (*cp != '}' && *cp != ']' && *cp != '\0' && *cp != '\n' && *cp != '\r' && *cp != ' ') {
            js->error = cp;
            return TOK_ERR;
        }
        next = cp;

        if (buf) {
            for (dest = src = (MprChar*) buf->start; src < (MprChar*) buf->end; ) {
                c = *src++;
                if (c == '\\') {
                    c = *src++;
                    if (c == 'r') {
                        c = '\r';
                    } else if (c == 'n') {
                        c = '\n';
                    } else if (c == 'b') {
                        c = '\b';
                    }
                }
                *dest++ = c;
            }
            *dest = '\0';
            *token = (MprChar*) mprGetBufStart(buf);
        }
    }
    js->next = next;
    return tid;
}
Пример #19
0
/*
    function [get|put|delete|post...](uri = null, ...data): Http
 */
static EjsHttp *startHttpRequest(Ejs *ejs, EjsHttp *hp, char *method, int argc, EjsObj **argv)
{
    EjsArray        *args;
    EjsByteArray    *data;
    EjsNumber       *written;
    EjsUri          *uriObj;
    HttpConn        *conn;
    ssize           nbytes;

    conn = hp->conn;
    hp->responseCache = 0;
    hp->requestContentCount = 0;
    mprFlushBuf(hp->responseContent);

    if (argc >= 1 && !ejsIs(ejs, argv[0], Null)) {
        uriObj = (EjsUri*) argv[0];
        hp->uri = httpUriToString(uriObj->uri, HTTP_COMPLETE_URI);
    }
    if (argc == 2 && ejsIs(ejs, argv[1], Array)) {
        args = (EjsArray*) argv[1];
        if (args->length > 0) {
            data = ejsCreateByteArray(ejs, -1);
            written = ejsWriteToByteArray(ejs, data, 1, &argv[1]);
            mprPutBlockToBuf(hp->requestContent, (char*) data->value, (int) written->value);
            mprAddNullToBuf(hp->requestContent);
            assert(written > 0);
        }
    }
    if (hp->uri == 0) {
        ejsThrowArgError(ejs, "URL is not defined");
        return 0;
    }
    if (method && strcmp(hp->method, method) != 0) {
        hp->method = sclone(method);
    }
    if (hp->method == 0) {
        ejsThrowArgError(ejs, "HTTP Method is not defined");
        return 0;
    }
    if (hp->certFile) {
        if (!hp->ssl) {
            hp->ssl = mprCreateSsl(0);
        }
        mprSetSslCertFile(hp->ssl, hp->certFile);
        if (!hp->keyFile) {
            ejsThrowStateError(ejs, "Must define a Http.key to use with a certificate");
        }
        mprSetSslKeyFile(hp->ssl, hp->keyFile);
    }
    if (hp->caFile) {
        if (!hp->ssl) {
            hp->ssl = mprCreateSsl(0);
        }
        mprSetSslCaFile(hp->ssl, hp->caFile);
    }
    if (httpConnect(conn, hp->method, hp->uri, hp->ssl) < 0) {
        ejsThrowIOError(ejs, "Cannot issue request for \"%s\"", hp->uri);
        return 0;
    }
    if (mprGetBufLength(hp->requestContent) > 0) {
        nbytes = httpWriteBlock(conn->writeq, mprGetBufStart(hp->requestContent), mprGetBufLength(hp->requestContent),
            HTTP_BLOCK);
        if (nbytes < 0) {
            ejsThrowIOError(ejs, "Cannot write request data for \"%s\"", hp->uri);
            return 0;
        } else if (nbytes > 0) {
            assert(nbytes == mprGetBufLength(hp->requestContent));
            mprAdjustBufStart(hp->requestContent, nbytes);
            hp->requestContentCount += nbytes;
        }
        httpFinalize(conn);
    }
    httpNotify(conn, HTTP_EVENT_WRITABLE, 0);
    if (conn->async) {
        httpEnableConnEvents(hp->conn);
    }
    return hp;
}