Beispiel #1
0
/*
    This replace will replace the given pattern and the next word on the same line with the given replacement.
 */
static char *replace(cchar *str, cchar *pattern, cchar *fmt, ...)
{
    va_list     args;
    MprBuf      *buf;
    cchar       *s, *replacement;
    ssize       plen;

    va_start(args, fmt);
    replacement = sfmtv(fmt, args);
    buf = mprCreateBuf(-1, -1);
    plen = slen(pattern);
    for (s = str; *s; s++) {
        if (*s == *pattern && sncmp(s, pattern, plen) == 0) {
            mprPutStringToBuf(buf, replacement);
            for (s += plen; *s && isspace((uchar) *s) && *s != '\n'; s++) ;
            for (; *s && !isspace((uchar) *s) && *s != '\n' && *s != '>'; s++) ;
         
        }
#if BIT_WIN_LIKE
        if (*s == '\n' && s[-1] != '\r') {
            mprPutCharToBuf(buf, '\r');
        }
#endif
        mprPutCharToBuf(buf, *s);
    }
    va_end(args);
    mprAddNullToBuf(buf);
    return sclone(mprGetBufStart(buf));
}
Beispiel #2
0
/*
    Remove trailing whitespace in a token and ensure it is terminated with a NULL for easy parsing
 */
static void trimToken(MprXml *xp)
{
    while (isspace(mprLookAtLastCharInBuf(xp->tokBuf))) {
        mprAdjustBufEnd(xp->tokBuf, -1);
    }
    mprAddNullToBuf(xp->tokBuf);
}
Beispiel #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;
}
Beispiel #4
0
/*  
    Expand a template with {word} tokens from the given options objects

    function template(pattern: String, ...options): Uri
 */
static EjsUri *uri_template(Ejs *ejs, EjsUri *up, int argc, EjsObj **argv)
{
    EjsArray    *options;
    EjsObj      *obj, *value;
    MprBuf      *buf;
    cchar       *pattern, *cp, *ep, *str;
    char        *token;
    int         i, len;

    pattern = ejsToMulti(ejs, argv[0]);
    options = (EjsArray*) argv[1];

    buf = mprCreateBuf(-1, -1);
    for (cp = pattern; *cp; cp++) {
        if (*cp == '~' && (cp == pattern || cp[-1] != '\\')) {
            for (i = 0; i < options->length; i++) {
                obj = options->data[i];
                if ((value = ejsGetPropertyByName(ejs, obj, N(NULL, "scriptName"))) != 0 && ejsIsDefined(ejs, value)) {
                    str = ejsToMulti(ejs, value);
                    if (str && *str) {
                        mprPutStringToBuf(buf, str);
                        break;
                    } else {
                        value = 0;
                    }
                }
            }
        } else if (*cp == '{' && (cp == pattern || cp[-1] != '\\')) {
            if ((ep = strchr(++cp, '}')) != 0) {
                len = (int) (ep - cp);
                token = mprMemdup(cp, len + 1);
                token[len] = '\0';
                value = 0;
                for (i = 0; i < options->length; i++) {
                    obj = options->data[i];
                    if ((value = ejsGetPropertyByName(ejs, obj, N(NULL, token))) != 0 && ejsIsDefined(ejs, value)) {
                        str = ejsToMulti(ejs, value);
                        if (str && *str) {
                            mprPutStringToBuf(buf, str);
                            break;
                        } else {
                            value = 0;
                        }
                    }
                }
                if (!ejsIsDefined(ejs, value)) {
                    //  MOB - remove this. Should not be erasing the prior "/"
                    if (cp >= &pattern[2] && cp[-2] == '/') {
                        mprAdjustBufEnd(buf, -1);
                    }
                }
                cp = ep;
            }
        } else {
            mprPutCharToBuf(buf, *cp);
        }
    }
    mprAddNullToBuf(buf);
    return ejsCreateUriFromAsc(ejs, mprGetBufStart(buf));
}
Beispiel #5
0
/*
 *  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;
}
Beispiel #6
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);
}
Beispiel #7
0
/*  
    function form(uri: String = null, formData: Object = null): Http
    Issue a POST method with form data
 */
static EjsHttp *http_form(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv)
{
    EjsObj  *data;

    if (argc == 2 && !ejsIs(ejs, argv[1], Null)) {
        /*
            Prep here to reset the state. The ensures the current headers will be preserved.
            Users may have called setHeader to define custom headers. Users must call reset if they want to clear 
            prior headers.
         */
        httpPrepClientConn(hp->conn, 1);
        mprFlushBuf(hp->requestContent);
        data = argv[1];
        if (ejsGetLength(ejs, data) > 0) {
            prepForm(ejs, hp, NULL, data);
        } else {
            mprPutStringToBuf(hp->requestContent, ejsToMulti(ejs, data));
        }
        mprAddNullToBuf(hp->requestContent);
        httpSetHeader(hp->conn, "Content-Type", "application/x-www-form-urlencoded");
        /* Ensure this gets recomputed */
        httpRemoveHeader(hp->conn, "Content-Length");
    }
    return startHttpRequest(ejs, hp, "POST", argc, argv);
}
Beispiel #8
0
static bool addChar(EspParse *parse, int c)
{
    if (mprPutCharToBuf(parse->token, c) < 0) {
        return 0;
    }
    mprAddNullToBuf(parse->token);
    return 1;
}
Beispiel #9
0
PUBLIC char *httpStatsReport(int flags)
{
    MprTime             now;
    MprBuf              *buf;
    HttpStats           s;
    double              elapsed;
    static MprTime      lastTime;
    static HttpStats    last;
    double              mb;

    mb = 1024.0 * 1024;
    now = mprGetTime();
    elapsed = (now - lastTime) / 1000.0;
    httpGetStats(&s);
    buf = mprCreateBuf(0, 0);

    mprPutToBuf(buf, "\nHttp Report: at %s\n\n", mprGetDate("%D %T"));
    if (flags & HTTP_STATS_MEMORY) {
        mprPutToBuf(buf, "Memory       %8.1f MB, %5.1f%% max\n", s.mem / mb, s.mem / (double) s.memMax * 100.0);
        mprPutToBuf(buf, "Heap         %8.1f MB, %5.1f%% mem\n", s.heap / mb, s.heap / (double) s.mem * 100.0);
        mprPutToBuf(buf, "Heap-peak    %8.1f MB\n", s.heapPeak / mb);
        mprPutToBuf(buf, "Heap-used    %8.1f MB, %5.1f%% used\n", s.heapUsed / mb, s.heapUsed / (double) s.heap * 100.0);
        mprPutToBuf(buf, "Heap-free    %8.1f MB, %5.1f%% free\n", s.heapFree / mb, s.heapFree / (double) s.heap * 100.0);

        if (s.memMax == (size_t) -1) {
            mprPutToBuf(buf, "Heap limit          -\n");
            mprPutToBuf(buf, "Heap readline       -\n");
        } else {
            mprPutToBuf(buf, "Heap limit   %8.1f MB\n", s.memMax / mb);
            mprPutToBuf(buf, "Heap redline %8.1f MB\n", s.memRedline / mb);
        }
    }

    mprPutToBuf(buf, "Connections  %8.1f per/sec\n", (s.totalConnections - last.totalConnections) / elapsed);
    mprPutToBuf(buf, "Requests     %8.1f per/sec\n", (s.totalRequests - last.totalRequests) / elapsed);
    mprPutToBuf(buf, "Sweeps       %8.1f per/sec\n", (s.totalSweeps - last.totalSweeps) / elapsed);
    mprPutCharToBuf(buf, '\n');

    mprPutToBuf(buf, "Clients      %8d active\n", s.activeClients);
    mprPutToBuf(buf, "Connections  %8d active\n", s.activeConnections);
    mprPutToBuf(buf, "Processes    %8d active\n", s.activeProcesses);
    mprPutToBuf(buf, "Requests     %8d active\n", s.activeRequests);
    mprPutToBuf(buf, "Sessions     %8d active\n", s.activeSessions);
    mprPutToBuf(buf, "Workers      %8d busy - %d yielded, %d idle, %d max\n", 
        s.workersBusy, s.workersYielded, s.workersIdle, s.workersMax);
    mprPutToBuf(buf, "Sessions     %8.1f MB\n", s.memSessions / mb);
    mprPutCharToBuf(buf, '\n');

    last = s;
    lastTime = now;
    mprAddNullToBuf(buf);
    return sclone(mprGetBufStart(buf));
}
Beispiel #10
0
bool httpPamVerifyUser(HttpConn *conn)
{
    MprBuf              *abilities;
    pam_handle_t        *pamh;
    UserInfo            info;
    struct pam_conv     conv = { pamChat, &info };
    struct group        *gp;
    int                 res, i;
   
    mprAssert(conn->username);
    mprAssert(conn->password);
    mprAssert(!conn->encoded);

    info.name = (char*) conn->username;
    info.password = (char*) conn->password;
    pamh = NULL;
    if ((res = pam_start("login", info.name, &conv, &pamh)) != PAM_SUCCESS) {
        return 0;
    }
    if ((res = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS) {
        pam_end(pamh, PAM_SUCCESS);
        mprLog(5, "httpPamVerifyUser failed to verify %s", conn->username);
        return 0;
    }
    pam_end(pamh, PAM_SUCCESS);
    mprLog(5, "httpPamVerifyUser verified %s", conn->username);

    if (!conn->user) {
        conn->user = mprLookupKey(conn->rx->route->auth->users, conn->username);
    }
    if (!conn->user) {
        Gid     groups[32];
        int     ngroups;
        /* 
            Create a temporary user with a abilities set to the groups 
         */
        ngroups = sizeof(groups) / sizeof(Gid);
        if ((i = getgrouplist(conn->username, 99999, groups, &ngroups)) >= 0) {
            abilities = mprCreateBuf(0, 0);
            for (i = 0; i < ngroups; i++) {
                if ((gp = getgrgid(groups[i])) != 0) {
                    mprPutFmtToBuf(abilities, "%s ", gp->gr_name);
                }
            }
            mprAddNullToBuf(abilities);
            mprLog(5, "Create temp user \"%s\" with abilities: %s", conn->username, mprGetBufStart(abilities));
            conn->user = httpCreateUser(conn->rx->route->auth, conn->username, 0, mprGetBufStart(abilities));
        }
    }
    return 1;
}
Beispiel #11
0
/*
    Map options to an attribute string. Remove all internal control specific options and transparently handle URI link options.
    WARNING: this returns a non-cloned reference and relies on no GC yield until the returned value is used or cloned.
    This is done as an optimization to reduce memeory allocations.
 */
static cchar *map(HttpConn *conn, MprHash *options)
{
    Esp         *esp;
    EspReq      *req;
    MprHash     *params;
    MprKey      *kp;
    MprBuf      *buf;
    cchar       *value;
    char        *pstr;

    if (options == 0 || mprGetHashLength(options) == 0) {
        return MPR->emptyString;
    }
    req = conn->data;
    if (httpGetOption(options, EDATA("refresh"), 0) && !httpGetOption(options, "id", 0)) {
        httpAddOption(options, "id", sfmt("id_%d", req->lastDomID++));
    }
    esp = MPR->espService;
    buf = mprCreateBuf(-1, -1);
    for (kp = 0; (kp = mprGetNextKey(options, kp)) != 0; ) {
        if (kp->type != MPR_JSON_OBJ && kp->type != MPR_JSON_ARRAY && !mprLookupKey(esp->internalOptions, kp->key)) {
            mprPutCharToBuf(buf, ' ');
            value = kp->data;
            /*
                Support link template resolution for these options
             */
            if (smatch(kp->key, EDATA("click")) || smatch(kp->key, EDATA("remote")) || smatch(kp->key, EDATA("refresh"))) {
                value = httpUriEx(conn, value, options);
                if ((params = httpGetOptionHash(options, "params")) != 0) {
                    pstr = (char*) "";
                    for (kp = 0; (kp = mprGetNextKey(params, kp)) != 0; ) {
                        pstr = sjoin(pstr, mprUriEncode(kp->key, MPR_ENCODE_URI_COMPONENT), "=", 
                            mprUriEncode(kp->data, MPR_ENCODE_URI_COMPONENT), "&", NULL);
                    }
                    if (pstr[0]) {
                        /* Trim last "&" */
                        pstr[strlen(pstr) - 1] = '\0';
                    }
                    mprPutToBuf(buf, "%s-params='%s", params);
                }
            }
            mprPutStringToBuf(buf, kp->key);
            mprPutStringToBuf(buf, "='");
            mprPutStringToBuf(buf, value);
            mprPutCharToBuf(buf, '\'');
        }
    }
    mprAddNullToBuf(buf);
    return mprGetBufStart(buf);
}
Beispiel #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;
}
Beispiel #13
0
/*
    Expand ${token} references in a path or string.
 */
static char *stemplateInner(cchar *str, void *keys, int json)
{
    MprBuf      *buf;
    cchar       *value;
    char        *src, *result, *cp, *tok;

    if (str) {
        if (schr(str, '$') == 0) {
            return sclone(str);
        }
        buf = mprCreateBuf(0, 0);
        for (src = (char*) str; *src; ) {
            if (*src == '$') {
                if (*++src == '{') {
                    for (cp = ++src; *cp && *cp != '}'; cp++) ;
                    tok = snclone(src, cp - src);
                } else {
                    for (cp = src; *cp && (isalnum((uchar) *cp) || *cp == '_'); cp++) ;
                    tok = snclone(src, cp - src);
                }
                if (json) {
                    value = mprGetJson(keys, tok);
                } else {
                    value = mprLookupKey(keys, tok);
                }
                if (value != 0) {
                    mprPutStringToBuf(buf, value);
                    if (src > str && src[-1] == '{') {
                        src = cp + 1;
                    } else {
                        src = cp;
                    }
                } else {
                    mprPutCharToBuf(buf, '$');
                    if (src > str && src[-1] == '{') {
                        mprPutCharToBuf(buf, '{');
                    }
                    mprPutCharToBuf(buf, *src++);
                }
            } else {
                mprPutCharToBuf(buf, *src++);
            }
        }
        mprAddNullToBuf(buf);
        result = sclone(mprGetBufStart(buf));
    } else {
        result = MPR->emptyString;
    }
    return result;
}
Beispiel #14
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));
}
Beispiel #15
0
/*
    Default callback routine for the mprRunCmd routines. Uses may supply their own callback instead of this routine.
    The callback is run whenever there is I/O to read/write to the CGI gateway.
 */
static void defaultCmdCallback(MprCmd *cmd, int channel, void *data)
{
    MprBuf      *buf;
    ssize       len, space;
    int         errCode;

    /*
        Note: stdin, stdout and stderr are named from the client's perspective
     */
    buf = 0;
    switch (channel) {
    case MPR_CMD_STDIN:
        return;
    case MPR_CMD_STDOUT:
        buf = cmd->stdoutBuf;
        break;
    case MPR_CMD_STDERR:
        buf = cmd->stderrBuf;
        break;
    default:
        /* Child death notification */
        return;
    }
    /*
        Read and aggregate the result into a single string
     */
    space = mprGetBufSpace(buf);
    if (space < (ME_BUFSIZE / 4)) {
        if (mprGrowBuf(buf, ME_BUFSIZE) < 0) {
            mprCloseCmdFd(cmd, channel);
            return;
        }
        space = mprGetBufSpace(buf);
    }
    len = mprReadCmd(cmd, channel, mprGetBufEnd(buf), space);
    errCode = mprGetError();
    if (len <= 0) {
        if (len == 0 || (len < 0 && !(errCode == EAGAIN || errCode == EWOULDBLOCK))) {
            mprCloseCmdFd(cmd, channel);
            return;
        }
    } else {
        mprAdjustBufEnd(buf, len);
    }
    mprAddNullToBuf(buf);
    mprEnableCmdEvents(cmd, channel);
}
Beispiel #16
0
static int toStringMethod(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
{
	MprBuf	*bp;
	int		saveMaxDepth, saveDepth, saveFlags;

	saveMaxDepth = ep->maxDepth;

	if (argc >= 1) {
		ep->maxDepth = ejsVarToInteger(argv[0]);
	} else if (ep->maxDepth == 0) {
		ep->maxDepth = MAXINT;
	}

	saveFlags = ep->flags;
	if (argc >= 2) {
		if (ejsVarToBoolean(argv[1])) {
			ep->flags |= EJS_FLAGS_ENUM_HIDDEN;
		}
	}
	if (argc == 3) {
		if (ejsVarToBoolean(argv[2])) {
			ep->flags |= EJS_FLAGS_ENUM_BASE;
		}
	}

	bp = mprCreateBuf(ep, 0, 0);

	saveDepth = ep->depth;

	formatVar(ep, bp, thisObj);

	ep->depth = saveDepth;
	ep->maxDepth = saveMaxDepth;

	mprAddNullToBuf(bp);

	ejsWriteVarAsString(ep, ep->result, mprGetBufStart(bp));
	mprFree(bp);

	ep->flags = saveFlags;

	return 0;
}
Beispiel #17
0
static void saveCachedResponse(HttpConn *conn)
{
    HttpTx      *tx;
    MprBuf      *buf;
    MprTime     modified;

    tx = conn->tx;

    mprAssert(conn->finalized && tx->cacheBuffer);
    buf = tx->cacheBuffer;
    mprAddNullToBuf(buf);
    tx->cacheBuffer = 0;
    /* 
        Truncate modified time to get a 1 sec resolution. This is the resolution for If-Modified headers.  
     */
    modified = mprGetTime() / MPR_TICKS_PER_SEC * MPR_TICKS_PER_SEC;
    mprWriteCache(conn->host->responseCache, makeCacheKey(conn), mprGetBufStart(buf), modified, 
        tx->cache->serverLifespan, 0, 0);
}
Beispiel #18
0
PUBLIC cchar *httpGetBodyInput(HttpConn *conn)
{
    HttpQueue   *q;
    HttpRx      *rx;
    MprBuf      *content;

    rx = conn->rx;
    if (!rx->eof) {
        return 0;
    }
    q = conn->readq;
    if (q->first) {
        httpJoinPackets(q, -1);
        if ((content = q->first->content) != 0) {
            mprAddNullToBuf(content); 
            return mprGetBufStart(content);
        }
    }
    return 0;
}
Beispiel #19
0
char *sreplace(cchar *str, cchar *pattern, cchar *replacement)
{
    MprBuf      *buf;
    cchar       *s;
    ssize       plen;

    buf = mprCreateBuf(-1, -1);
    if (pattern && *pattern && replacement) {
        plen = slen(pattern);
        for (s = str; *s; s++) {
            if (sncmp(s, pattern, plen) == 0) {
                mprPutStringToBuf(buf, replacement);
                s += plen - 1;
            } else {
                mprPutCharToBuf(buf, *s);
            }
        }
    }
    mprAddNullToBuf(buf);
    return sclone(mprGetBufStart(buf));
}
Beispiel #20
0
static char *hashToString(MprHash *hash, cchar *sep)
{
    MprBuf  *buf;
    cchar   *data;
    char    key[8];
    int     i, len;

    len = mprGetHashLength(hash);
    buf = mprCreateBuf(0, 0);
    mprPutCharToBuf(buf, '{');
    for (i = 0; i < len; ) {
        data = mprLookupKey(hash, itosbuf(key, sizeof(key), i, 10));
        mprPutStringToBuf(buf, data);
        if (++i < len) {
            mprPutStringToBuf(buf, sep ? sep : ",");
        }
    }
    mprPutCharToBuf(buf, '}');
    mprAddNullToBuf(buf);
    return mprGetBufStart(buf);
}
Beispiel #21
0
char *mprGets(MprFile *file, char *buf, uint size)
{
	MprBuf	*bp;
	int		count, len, c;

	mprAssert(file);

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

	if (file->buf == 0) {
		file->buf = mprCreateBuf(file, MPR_DEFAULT_ALLOC, MPR_MAX_STRING);
	}
	bp = file->buf;

	/*
	 *	Must leave room for null
	 */
	count = 0;
	while (--size > 0) {
		if (mprGetBufLength(bp) == 0) {
			mprFlushBuf(bp);
			len = mprRead(file, mprGetBufEnd(bp), 
				mprGetBufLinearSpace(bp));
			if (len <= 0) {
				return 0;
			}
			mprAdjustBufEnd(bp, len);
			mprAddNullToBuf(bp);
		}
		if ((c = mprGetCharFromBuf(bp)) == '\n') {
			buf[count] = '\0';
			return buf;
		}
		buf[count++] = c;
	}
	buf[count] = '\0';
	return buf;
}
Beispiel #22
0
/*
    Convert to a JSON string

    override function toJSON(): String
 */
static EjsString *xmlToJson(Ejs *ejs, EjsObj *vp, int argc, EjsObj **argv)
{
    EjsString       *sp;
    MprBuf          *buf;
    cchar           *cp;

    /*
        Quote all quotes
     */
    sp = ejsToString(ejs, vp);
    buf = mprCreateBuf(-1, -1);
    mprPutCharToBuf(buf, '"');
    for (cp = ejsToMulti(ejs, sp); *cp; cp++) {
        if (*cp == '"') {
            mprPutCharToBuf(buf, '\\');
        }
        mprPutCharToBuf(buf, (uchar) *cp);
    }
    mprPutCharToBuf(buf, '"');
    mprAddNullToBuf(buf);
    return ejsCreateStringFromAsc(ejs, mprGetBufStart(buf));
}
Beispiel #23
0
static int getPostData(MprCtx ctx, MprBuf *buf)
{
    char    *contentLength;
    int     bytes, len, space;

    if ((contentLength = getenv("CONTENT_LENGTH")) != 0) {
        len = atoi(contentLength);
    } else {
        len = MAXINT;
    }
    while (len > 0) {
        space = mprGetBufSpace(buf);
        if (space < MPR_BUFSIZE) {
            if (mprGrowBuf(buf, MPR_BUFSIZE) < 0) {
                error(mpr, "Couldn't allocate memory to read post data");
                return -1;
            }
        }
        space = mprGetBufSpace(buf);
        bytes = (int) read(0, mprGetBufEnd(buf), space);
        if (bytes < 0) {
            error(mpr, "Couldn't read CGI input %d", errno);
            return -1;

        } else if (bytes == 0) {
            /* EOF */
            if (len > 0) {
                error(mpr, "Missing content (length %s)", contentLength);
            }
            break;
        }
        mprAdjustBufEnd(buf, bytes);
        len -= bytes;
    }
    mprAddNullToBuf(buf);
    return 0;
}
Beispiel #24
0
PUBLIC void maLogRequest(HttpConn *conn)
{
    HttpHost    *host;
    HttpRx      *rx;
    HttpTx      *tx;
    HttpRoute   *route;
    MprBuf      *buf;
    char        keyBuf[80], *timeText, *fmt, *cp, *qualifier, *value, c;
    int         len;

    rx = conn->rx;
    tx = conn->tx;
    route = rx->route;
    host = httpGetConnContext(conn);
    if (host == 0) {
        return;
    }
    fmt = route->logFormat;
    if (fmt == 0) {
        return;
    }
    if (rx->method == 0) {
        return;
    }
    len = BIT_MAX_URI + 256;
    buf = mprCreateBuf(len, len);

    while ((c = *fmt++) != '\0') {
        if (c != '%' || (c = *fmt++) == '%') {
            mprPutCharToBuf(buf, c);
            continue;
        }
        switch (c) {
        case 'a':                           /* Remote IP */
            mprPutStringToBuf(buf, conn->ip);
            break;

        case 'A':                           /* Local IP */
            mprPutStringToBuf(buf, conn->sock->listenSock->ip);
            break;

        case 'b':
            if (tx->bytesWritten == 0) {
                mprPutCharToBuf(buf, '-');
            } else {
                mprPutIntToBuf(buf, tx->bytesWritten);
            } 
            break;

        case 'B':                           /* Bytes written (minus headers) */
            mprPutIntToBuf(buf, (tx->bytesWritten - tx->headerSize));
            break;

        case 'h':                           /* Remote host */
            mprPutStringToBuf(buf, conn->ip);
            break;

        case 'n':                           /* Local host */
            mprPutStringToBuf(buf, rx->parsedUri->host);
            break;

        case 'O':                           /* Bytes written (including headers) */
            mprPutIntToBuf(buf, tx->bytesWritten);
            break;

        case 'r':                           /* First line of request */
            mprPutToBuf(buf, "%s %s %s", rx->method, rx->uri, conn->protocol);
            break;

        case 's':                           /* Response code */
            mprPutIntToBuf(buf, tx->status);
            break;

        case 't':                           /* Time */
            mprPutCharToBuf(buf, '[');
            timeText = mprFormatLocalTime(MPR_DEFAULT_DATE, mprGetTime());
            mprPutStringToBuf(buf, timeText);
            mprPutCharToBuf(buf, ']');
            break;

        case 'u':                           /* Remote username */
            mprPutStringToBuf(buf, conn->username ? conn->username : "******");
            break;

        case '{':                           /* Header line */
            qualifier = fmt;
            if ((cp = strchr(qualifier, '}')) != 0) {
                fmt = &cp[1];
                *cp = '\0';
                c = *fmt++;
                scopy(keyBuf, sizeof(keyBuf), "HTTP_");
                scopy(&keyBuf[5], sizeof(keyBuf) - 5, qualifier);
                switch (c) {
                case 'i':
                    value = (char*) mprLookupKey(rx->headers, supper(keyBuf));
                    mprPutStringToBuf(buf, value ? value : "-");
                    break;
                default:
                    mprPutStringToBuf(buf, qualifier);
                }
                *cp = '}';

            } else {
                mprPutCharToBuf(buf, c);
            }
            break;

        case '>':
            if (*fmt == 's') {
                fmt++;
                mprPutIntToBuf(buf, tx->status);
            }
            break;

        default:
            mprPutCharToBuf(buf, c);
            break;
        }
    }
    mprPutCharToBuf(buf, '\n');
    mprAddNullToBuf(buf);
    mprWriteFile(route->log, mprGetBufStart(buf), mprGetBufLength(buf));
}
Beispiel #25
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;
}
Beispiel #26
0
void maLogRequest(MaConn *conn)
{
    MaHost      *logHost, *host;
    MaResponse  *resp;
    MaRequest   *req;
    MprBuf      *buf;
    char        keyBuf[80], *timeText, *fmt, *cp, *qualifier, *value, c;
    int         len;

    resp = conn->response;
    req = conn->request;
    host = req->host;

    logHost = host->logHost;
    if (logHost == 0) {
        return;
    }
    fmt = logHost->logFormat;
    if (fmt == 0) {
        return;
    }
    if (req->method == 0) {
        return;
    }

    len = MPR_MAX_URL + 256;
    buf = mprCreateBuf(resp, len, len);

    while ((c = *fmt++) != '\0') {
        if (c != '%' || (c = *fmt++) == '%') {
            mprPutCharToBuf(buf, c);
            continue;
        }

        switch (c) {
        case 'a':                           /* Remote IP */
            mprPutStringToBuf(buf, conn->remoteIpAddr);
            break;

        case 'A':                           /* Local IP */
            mprPutStringToBuf(buf, conn->sock->listenSock->ipAddr);
            break;

        case 'b':
            if (resp->bytesWritten == 0) {
                mprPutCharToBuf(buf, '-');
            } else {
                mprPutIntToBuf(buf, resp->bytesWritten);
            } 
            break;

        case 'B':                           /* Bytes written (minus headers) */
            mprPutIntToBuf(buf, resp->bytesWritten - resp->headerSize);
            break;

        case 'h':                           /* Remote host */
            mprPutStringToBuf(buf, conn->remoteIpAddr);
            break;

        case 'n':                           /* Local host */
            mprPutStringToBuf(buf, req->parsedUri->host);
            break;

        case 'l':                           /* Supplied in authorization */
            mprPutStringToBuf(buf, req->user ? req->user : "******");
            break;

        case 'O':                           /* Bytes written (including headers) */
            mprPutIntToBuf(buf, resp->bytesWritten);
            break;

        case 'r':                           /* First line of request */
            mprPutFmtToBuf(buf, "%s %s %s", req->methodName, req->parsedUri->originalUri, req->httpProtocol);
            break;

        case 's':                           /* Response code */
            mprPutIntToBuf(buf, resp->code);
            break;

        case 't':                           /* Time */
            mprPutCharToBuf(buf, '[');
            timeText = mprFormatLocalTime(conn, mprGetTime(conn));
            mprPutStringToBuf(buf, timeText);
            mprFree(timeText);
            mprPutCharToBuf(buf, ']');
            break;

        case 'u':                           /* Remote username */
            mprPutStringToBuf(buf, req->user ? req->user : "******");
            break;

        case '{':                           /* Header line */
            qualifier = fmt;
            if ((cp = strchr(qualifier, '}')) != 0) {
                fmt = &cp[1];
                *cp = '\0';
                c = *fmt++;
                mprStrcpy(keyBuf, sizeof(keyBuf), "HTTP_");
                mprStrcpy(&keyBuf[5], sizeof(keyBuf) - 5, qualifier);
                mprStrUpper(keyBuf);
                switch (c) {
                case 'i':
                    value = (char*) mprLookupHash(req->headers, keyBuf);
                    mprPutStringToBuf(buf, value ? value : "-");
                    break;
                default:
                    mprPutStringToBuf(buf, qualifier);
                }
                *cp = '}';

            } else {
                mprPutCharToBuf(buf, c);
            }
            break;

        case '>':
            if (*fmt == 's') {
                fmt++;
                mprPutIntToBuf(buf, resp->code);
            }
            break;

        default:
            mprPutCharToBuf(buf, c);
            break;
        }
    }
    mprPutCharToBuf(buf, '\n');
    mprAddNullToBuf(buf);

    mprWrite(logHost->accessLog, mprGetBufStart(buf), mprGetBufLength(buf));
}
Beispiel #27
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;
}
Beispiel #28
0
static ssize writeBody(HttpConn *conn, MprList *files)
{
    MprFile     *file;
    char        buf[HTTP_BUFSIZE], *path, *pair;
    ssize       bytes, len, count, nbytes, sofar;
    int         next, oldMode;

    if (app->upload) {
        if (httpWriteUploadData(conn, app->files, app->formData) < 0) {
            mprError("Can't write upload data %s", httpGetError(conn));
            return MPR_ERR_CANT_WRITE;
        }
    } else {
        if (app->formData) {
            count = mprGetListLength(app->formData);
            for (next = 0; (pair = mprGetNextItem(app->formData, &next)) != 0; ) {
                len = strlen(pair);
                if (next < count) {
                    len = slen(pair);
                    if (httpWrite(conn->writeq, pair, len) != len || httpWrite(conn->writeq, "&", 1) != 1) {
                        return MPR_ERR_CANT_WRITE;
                    }
                } else {
                    if (httpWrite(conn->writeq, pair, len) != len) {
                        return MPR_ERR_CANT_WRITE;
                    }
                }
            }
        }
        if (files) {
            mprAssert(mprGetListLength(files) == 1);
            for (next = 0; (path = mprGetNextItem(files, &next)) != 0; ) {
                if (strcmp(path, "-") == 0) {
                    file = mprAttachFileFd(0, "stdin", O_RDONLY | O_BINARY);
                } else {
                    file = mprOpenFile(path, O_RDONLY | O_BINARY, 0);
                }
                if (file == 0) {
                    mprError("Can't open \"%s\"", path);
                    return MPR_ERR_CANT_OPEN;
                }
                app->inFile = file;
                if (app->verbose) {
                    mprPrintf("uploading: %s\n", path);
                }
                oldMode = mprSetSocketBlockingMode(conn->sock, 1);
                while ((bytes = mprReadFile(file, buf, sizeof(buf))) > 0) {
                    sofar = 0;
                    while (bytes > 0) {
                        if ((nbytes = httpWriteBlock(conn->writeq, &buf[sofar], bytes)) < 0) {
                            mprCloseFile(file);
                            return MPR_ERR_CANT_WRITE;
                        }
                        bytes -= nbytes;
                        sofar += nbytes;
                        mprAssert(bytes >= 0);
                    }
                    mprYield(0);
                }
                httpFlushQueue(conn->writeq, 1);
                mprSetSocketBlockingMode(conn->sock, oldMode);
                mprCloseFile(file);
                app->inFile = 0;
            }
        }
        if (app->bodyData) {
            mprAddNullToBuf(app->bodyData);
            len = mprGetBufLength(app->bodyData);
            if (httpWriteBlock(conn->writeq, mprGetBufStart(app->bodyData), len) != len) {
                return MPR_ERR_CANT_WRITE;
            }
        }
    }
    return 0;
}
Beispiel #29
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;
}
Beispiel #30
0
/*
    Lexical analyser for XML. Return the next token reading input as required. It uses a one token look ahead and 
    push back mechanism (LAR1 parser). Text token identifiers are left in the tokBuf parser buffer on exit. This Lex 
    has special cases for the states MPR_XML_ELT_DATA where we have an optimized read of element data, and 
    MPR_XML_AFTER_LS where we distinguish between element names, processing instructions and comments. 
 */
static MprXmlToken getXmlToken(MprXml *xp, int state)
{
    MprBuf      *tokBuf;
    char        *cp;
    int         c, rc;

    mprAssert(state >= 0);
    tokBuf = xp->tokBuf;

    if ((c = getNextChar(xp)) < 0) {
        return MPR_XMLTOK_EOF;
    }
    mprFlushBuf(tokBuf);

    /*
        Special case parsing for names and for element data. We do this for performance so we can return to the caller 
        the largest token possible.
     */
    if (state == MPR_XML_ELT_DATA) {
        /*
            Read all the data up to the start of the closing element "<" or the start of a sub-element.
         */
        if (c == '<') {
            if ((c = getNextChar(xp)) < 0) {
                return MPR_XMLTOK_EOF;
            }
            if (c == '/') {
                return MPR_XMLTOK_LS_SLASH;
            }
            putLastChar(xp, c);
            return MPR_XMLTOK_LS;
        }
        do {
            if (mprPutCharToBuf(tokBuf, c) < 0) {
                return MPR_XMLTOK_TOO_BIG;
            }
            if ((c = getNextChar(xp)) < 0) {
                return MPR_XMLTOK_EOF;
            }
        } while (c != '<');

        /*
            Put back the last look-ahead character
         */
        putLastChar(xp, c);

        /*
            If all white space, then zero the token buffer
         */
        for (cp = tokBuf->start; *cp; cp++) {
            if (!isspace((uchar) *cp & 0x7f)) {
                return MPR_XMLTOK_TEXT;
            }
        }
        mprFlushBuf(tokBuf);
        return MPR_XMLTOK_TEXT;
    }

    while (1) {
        switch (c) {
        case ' ':
        case '\n':
        case '\t':
        case '\r':
            break;

        case '<':
            if ((c = getNextChar(xp)) < 0) {
                return MPR_XMLTOK_EOF;
            }
            if (c == '/') {
                return MPR_XMLTOK_LS_SLASH;
            }
            putLastChar(xp, c);
            return MPR_XMLTOK_LS;
    
        case '=':
            return MPR_XMLTOK_EQ;

        case '>':
            return MPR_XMLTOK_GR;

        case '/':
            if ((c = getNextChar(xp)) < 0) {
                return MPR_XMLTOK_EOF;
            }
            if (c == '>') {
                return MPR_XMLTOK_SLASH_GR;
            }
            return MPR_XMLTOK_ERR;
        
        case '\"':
        case '\'':
            xp->quoteChar = c;
            /* Fall through */

        default:
            /*
                We handle element names, attribute names and attribute values 
                here. We do NOT handle data between elements here. Read the 
                token.  Stop on white space or a closing element ">"
             */
            if (xp->quoteChar) {
                if ((c = getNextChar(xp)) < 0) {
                    return MPR_XMLTOK_EOF;
                }
                while (c != xp->quoteChar) {
                    if (mprPutCharToBuf(tokBuf, c) < 0) {
                        return MPR_XMLTOK_TOO_BIG;
                    }
                    if ((c = getNextChar(xp)) < 0) {
                        return MPR_XMLTOK_EOF;
                    }
                }
                xp->quoteChar = 0;

            } else {
                while (!isspace((uchar) c) && c != '>' && c != '/' && c != '=') {
                    if (mprPutCharToBuf(tokBuf, c) < 0) {
                        return MPR_XMLTOK_TOO_BIG;
                    }
                    if ((c = getNextChar(xp)) < 0) {
                        return MPR_XMLTOK_EOF;
                    }
                }
                putLastChar(xp, c);
            }
            if (mprGetBufLength(tokBuf) < 0) {
                return MPR_XMLTOK_ERR;
            }
            mprAddNullToBuf(tokBuf);

            if (state == MPR_XML_AFTER_LS) {
                /*
                    If we are just inside an element "<", then analyze what we have to see if we have an element name, 
                    instruction or comment. Tokbuf will hold "?" for instructions or "!--" for comments.
                 */
                if (mprLookAtNextCharInBuf(tokBuf) == '?') {
                    /*  Just ignore processing instructions */
                    rc = scanFor(xp, "?>");
                    if (rc < 0) {
                        return MPR_XMLTOK_TOO_BIG;
                    } else if (rc == 0) {
                        return MPR_XMLTOK_ERR;
                    }
                    return MPR_XMLTOK_INSTRUCTIONS;

                } else if (mprLookAtNextCharInBuf(tokBuf) == '!') {
                    if (strncmp((char*) tokBuf->start, "![CDATA[", 8) == 0) {
                        mprAdjustBufStart(tokBuf, 8);
                        rc = scanFor(xp, "]]>");
                        if (rc < 0) {
                            return MPR_XMLTOK_TOO_BIG;
                        } else if (rc == 0) {
                            return MPR_XMLTOK_ERR;
                        }
                        return MPR_XMLTOK_CDATA;

                    } else {
                        mprFlushBuf(tokBuf);
                        rc = scanFor(xp, "-->");
                        if (rc < 0) {
                            return MPR_XMLTOK_TOO_BIG;
                        } else if (rc == 0) {
                            return MPR_XMLTOK_ERR;
                        }
                        return MPR_XMLTOK_COMMENT;
                    }
                }
            }
            trimToken(xp);
            return MPR_XMLTOK_TEXT;
        }
        if ((c = getNextChar(xp)) < 0) {
            return MPR_XMLTOK_EOF;
        }
    }

    /* Should never get here */
    mprAssert(0);
    return MPR_XMLTOK_ERR;
}