Example #1
0
void maClientUnlock(MaClient *cp)
{
	mprAssert(cp);

	cp->unlock();
}
Example #2
0
/*
 *  Parse the request headers. Return true if the header parsed.
 */
static bool parseHeaders(MaConn *conn, MaPacket *packet)
{
    MaHostAddress   *address;
    MaRequest       *req;
    MaHost          *host, *hp;
    MaLimits        *limits;
    MprBuf          *content;
    char            keyBuf[MPR_MAX_STRING];
    char            *key, *value, *cp, *tok;
    int             count, keepAlive;

    req = conn->request;
    host = req->host;
    content = packet->content;
    conn->request->headerPacket = packet;
    limits = &conn->http->limits;
    keepAlive = 0;

    strcpy(keyBuf, "HTTP_");
    mprAssert(strstr((char*) content->start, "\r\n"));

    for (count = 0; content->start[0] != '\r' && !conn->connectionFailed; count++) {

        if (count >= limits->maxNumHeaders) {
            maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Too many headers");
            return 0;
        }
        if ((key = getToken(conn, ":")) == 0 || *key == '\0') {
            maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Bad header format");
            return 0;
        }

        value = getToken(conn, "\r\n");
        while (isspace((int) *value)) {
            value++;
        }
        if (conn->requestFailed) {
            continue;
        }
        mprStrUpper(key);
        for (cp = key; *cp; cp++) {
            if (*cp == '-') {
                *cp = '_';
            }
        }
        mprLog(req, 8, "Key %s, value %s", key, value);
        if (strspn(key, "%<>/\\") > 0) {
            maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Bad header key value");
            continue;
        }

        /*
         *  Define the header with a "HTTP_" prefix
         */
        mprStrcpy(&keyBuf[5], sizeof(keyBuf) - 5, key);
        mprAddDuplicateHash(req->headers, keyBuf, value);

        switch (key[0]) {
        case 'A':
            if (strcmp(key, "AUTHORIZATION") == 0) {
                value = mprStrdup(req, value);
                req->authType = mprStrTok(value, " \t", &tok);
                req->authDetails = tok;

            } else if (strcmp(key, "ACCEPT_CHARSET") == 0) {
                req->acceptCharset = value;

            } else if (strcmp(key, "ACCEPT") == 0) {
                req->accept = value;

            } else if (strcmp(key, "ACCEPT_ENCODING") == 0) {
                req->acceptEncoding = value;
            }
            break;

        case 'C':
            if (strcmp(key, "CONTENT_LENGTH") == 0) {
                if (req->length >= 0) {
                    maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Mulitple content length headers");
                    continue;
                }
                req->length = mprAtoi(value, 10);
                if (req->length < 0) {
                    maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Bad content length");
                    continue;
                }
                if (req->length >= host->limits->maxBody) {
                    maFailConnection(conn, MPR_HTTP_CODE_REQUEST_TOO_LARGE, 
                        "Request content length %Ld is too big. Limit %Ld", req->length, host->limits->maxBody);
                    continue;
                }
                mprAssert(req->length >= 0);
                req->remainingContent = req->length;
                req->contentLengthStr = value;

            } else if (strcmp(key, "CONTENT_RANGE") == 0) {
                /*
                 *  This headers specifies the range of any posted body data
                 *  Format is:  Content-Range: bytes n1-n2/length
                 *  Where n1 is first byte pos and n2 is last byte pos
                 */
                char    *sp;
                int     start, end, size;

                start = end = size = -1;
                sp = value;
                while (*sp && !isdigit((int) *sp)) {
                    sp++;
                }
                if (*sp) {
                    start = (int) mprAtoi(sp, 10);

                    if ((sp = strchr(sp, '-')) != 0) {
                        end = (int) mprAtoi(++sp, 10);
                    }
                    if ((sp = strchr(sp, '/')) != 0) {
                        /*
                         *  Note this is not the content length transmitted, but the original size of the input of which 
                         *  the client is transmitting only a portion.
                         */
                        size = (int) mprAtoi(++sp, 10);
                    }
                }
                if (start < 0 || end < 0 || size < 0 || end <= start) {
                    maFailRequest(conn, MPR_HTTP_CODE_RANGE_NOT_SATISFIABLE, "Bad content range");
                    continue;
                }
                req->inputRange = maCreateRange(conn, start, end);

            } else if (strcmp(key, "CONTENT_TYPE") == 0) {
                req->mimeType = value;
                req->form = strstr(value, "application/x-www-form-urlencoded") != 0;

            } else if (strcmp(key, "COOKIE") == 0) {
                if (req->cookie && *req->cookie) {
                    req->cookie = mprStrcat(req, -1, req->cookie, "; ", value, NULL);
                } else {
                    req->cookie = value;
                }

            } else if (strcmp(key, "CONNECTION") == 0) {
                req->connection = value;
                if (mprStrcmpAnyCase(value, "KEEP-ALIVE") == 0) {
                    keepAlive++;

                } else if (mprStrcmpAnyCase(value, "CLOSE") == 0) {
                    conn->keepAliveCount = 0;
                }
                if (!host->keepAlive) {
                    conn->keepAliveCount = 0;
                }
            }
            break;

        case 'F':
            req->forwarded = value;
            break;

        case 'H':
            if (strcmp(key, "HOST") == 0) {
                req->hostName = value;
                address = conn->address;
                if (maIsNamedVirtualHostAddress(address)) {
                    hp = maLookupVirtualHost(address, value);
                    if (hp == 0) {
                        maFailRequest(conn, 404, "No host to serve request. Searching for %s", value);
                        mprLog(conn, 1, "Can't find virtual host %s", value);
                        continue;
                    }
                    req->host = hp;
                    /*
                     *  Reassign this request to a new host
                     */
                    maRemoveConn(host, conn);
                    host = hp;
                    conn->host = hp;
                    maAddConn(hp, conn);
                }
            }
            break;

        case 'I':
            if ((strcmp(key, "IF_MODIFIED_SINCE") == 0) || (strcmp(key, "IF_UNMODIFIED_SINCE") == 0)) {
                MprTime     newDate = 0;
                char        *cp;
                bool        ifModified = (key[3] == 'M');

                if ((cp = strchr(value, ';')) != 0) {
                    *cp = '\0';
                }
                if (mprParseTime(conn, &newDate, value, MPR_UTC_TIMEZONE, NULL) < 0) {
                    mprAssert(0);
                    break;
                }
                if (newDate) {
                    setIfModifiedDate(conn, newDate, ifModified);
                    req->flags |= MA_REQ_IF_MODIFIED;
                }

            } else if ((strcmp(key, "IF_MATCH") == 0) || (strcmp(key, "IF_NONE_MATCH") == 0)) {
                char    *word, *tok;
                bool    ifMatch = key[3] == 'M';

                if ((tok = strchr(value, ';')) != 0) {
                    *tok = '\0';
                }
                req->ifMatch = ifMatch;
                req->flags |= MA_REQ_IF_MODIFIED;

                value = mprStrdup(conn, value);
                word = mprStrTok(value, " ,", &tok);
                while (word) {
                    addMatchEtag(conn, word);
                    word = mprStrTok(0, " ,", &tok);
                }

            } else if (strcmp(key, "IF_RANGE") == 0) {
                char    *word, *tok;

                if ((tok = strchr(value, ';')) != 0) {
                    *tok = '\0';
                }
                req->ifMatch = 1;
                req->flags |= MA_REQ_IF_MODIFIED;

                value = mprStrdup(conn, value);
                word = mprStrTok(value, " ,", &tok);
                while (word) {
                    addMatchEtag(conn, word);
                    word = mprStrTok(0, " ,", &tok);
                }
            }
            break;

        case 'P':
            if (strcmp(key, "PRAGMA") == 0) {
                req->pragma = value;
            }
            break;

        case 'R':
            if (strcmp(key, "RANGE") == 0) {
                if (!parseRange(conn, value)) {
                    maFailRequest(conn, MPR_HTTP_CODE_RANGE_NOT_SATISFIABLE, "Bad range");
                }
            } else if (strcmp(key, "REFERER") == 0) {
                /* NOTE: yes the header is misspelt in the spec */
                req->referer = value;
            }
            break;

        case 'T':
            if (strcmp(key, "TRANSFER_ENCODING") == 0) {
                mprStrLower(value);
                if (strcmp(value, "chunked") == 0) {
                    req->flags |= MA_REQ_CHUNKED;
                    /*
                     *  This will be revised by the chunk filter as chunks are processed and will be set to zero when the
                     *  last chunk has been received.
                     */
                    req->remainingContent = MAXINT;
                }
            }
            break;
        
#if BLD_DEBUG
        case 'X':
            if (strcmp(key, "X_APPWEB_CHUNK_SIZE") == 0) {
                mprStrUpper(value);
                conn->response->chunkSize = atoi(value);
                if (conn->response->chunkSize <= 0) {
                    conn->response->chunkSize = 0;
                } else if (conn->response->chunkSize > conn->http->limits.maxChunkSize) {
                    conn->response->chunkSize = conn->http->limits.maxChunkSize;
                }
            }
            break;
#endif

        case 'U':
            if (strcmp(key, "USER_AGENT") == 0) {
                req->userAgent = value;
            }
            break;
        }
    }
    if (conn->protocol == 0 && !keepAlive) {
        conn->keepAliveCount = 0;
    }
    if (!(req->flags & MA_REQ_CHUNKED)) {
        /*  
         *  Step over "\r\n" after headers. As an optimization, don't do this if chunked so chunking can parse a single
         *  chunk delimiter of "\r\nSIZE ...\r\n"
         */
        mprAdjustBufStart(content, 2);
    }
    mprLog(conn, 3, "Select host \"%s\"", conn->host->name);

    if (maSetRequestUri(conn, req->url, "") < 0) {
        maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Bad URI format");
        return 0;
    }
    if (conn->host->secure) {
        req->parsedUri->scheme = mprStrdup(req, "https");
    }
    req->parsedUri->port = conn->sock->port;
    req->parsedUri->host = req->hostName ? req->hostName : conn->host->name;
    return 1;
}
Example #3
0
static void reportFailure(MaConn *conn, int code, cchar *fmt, va_list args)
{
    MaResponse  *resp;
    MaRequest   *req;
    cchar       *url, *status;
    char        *emsg, *msg, *filename;

    mprAssert(fmt);
    
    if (conn->requestFailed) {
        return;
    }
    conn->requestFailed = 1;
    if (fmt == 0) {
        fmt = "";
    }
    req = conn->request;
    resp = conn->response;
    maDontCacheResponse(conn);

    msg = mprVasprintf(conn, MA_BUFSIZE, fmt, args);

    if (resp == 0 || req == 0) {
        mprLog(conn, 2, "\"%s\", code %d: %s.", mprGetHttpCodeString(conn, code), code, msg);

    } else {
        resp->code = code;
        filename = resp->filename ? resp->filename : 0;
        /* 711 is a custom error used by the test suite. */
        if (code != 711) {
            mprLog(resp, 2, "Error: \"%s\", code %d for URI \"%s\", file \"%s\": %s.", 
                mprGetHttpCodeString(conn, code), code, req->url ? req->url : "", filename ? filename : "", msg);
        }
        /*
         *  Use an error document rather than standard error boilerplate.
         */
        if (req->location) {
            url = maLookupErrorDocument(req->location, code);
            if (url && *url) {
                maRedirect(conn, 302, url);
                mprFree(msg);
                return;
            }
        }

        /*
         *  If the headers have already been filled, this alternate response body will be ignored.
         */
        if (resp->altBody == 0) {
            status = mprGetHttpCodeString(conn, code);
            /*
             *  For security, escape the message
             */
            emsg = mprEscapeHtml(resp, msg);
            resp->altBody = mprAsprintf(resp, -1, 
                "<!DOCTYPE html>\r\n"
                "<html><head><title>Document Error: %s</title></head>\r\n"
                "<body><h2>Access Error: %d -- %s</h2>\r\n<p>%s</p>\r\n</body>\r\n</html>\r\n",
                status, code, status, emsg);
        }
        resp->flags |= MA_RESP_NO_BODY;
    }
    mprFree(msg);
}
Example #4
0
/*
    Set the parse arg
 */ 
void mprXmlSetParseArg(MprXml *xp, void *parseArg)
{
    mprAssert(xp);

    xp->parseArg = parseArg;
}
Example #5
0
/*
    Parse an XML file. Return 0 for success, -1 for error.
 */ 
int mprXmlParse(MprXml *xp)
{
    mprAssert(xp);

    return parseNext(xp, MPR_XML_BEGIN);
}
Example #6
0
void MprLogService::error(char *file, int line, int flags, char *fmt, 
	va_list args)
{
	static int	recurseGate = 0;
	Mpr			*mpr;
	char		msg[MPR_MAX_LOG_STRING], buf[MPR_MAX_LOG_STRING];

	mpr = mprGetMpr();

	//
	//	Errors post close
	//
#if BLD_FEATURE_MULTITHREAD
	if (mutex == 0) {
		return;
	}
#endif

	lock();
	if (recurseGate > 0) {
		unlock();
		return;
	}
	recurseGate++;

	mprVsprintf(msg, sizeof(msg), fmt, args);

	if (flags & MPR_TRAP) {
		mprSprintf(buf, sizeof(buf), "Assertion %s, failed (%s:%d)\n",
			msg, file, line);
		output(defaultModule, flags, MPR_ERROR, buf);
		// 
		//	Break to the debugger
		//
		breakpoint(file, line);

	} else if (flags & MPR_LOG) {
		//
		//	Write to both the O/S log and to the trace log
		//
		mprSprintf(buf, sizeof(buf), "Error: %s\n", msg);
		output(defaultModule, flags, MPR_ERROR, buf);
		if (mpr) {
			mpr->writeToOsLog(buf, flags | MPR_INFO);
		}

	} else if (flags & MPR_USER) {
		mprSprintf(buf, sizeof(buf), "Error: %s\n", msg);
		output(defaultModule, flags, MPR_ERROR, buf);
		if (mpr) {
			mpr->writeToOsLog(buf, flags | MPR_WARN);
		}

	} else if (flags & MPR_ALERT) {
		// FUTURE -- TBD 

	} else {
		mprAssert(0);
	}

	recurseGate--;
	unlock();
}
Example #7
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;
}
Example #8
0
int	MprSocket::read(char *buf, int bufsize)
{
#if BLD_FEATURE_IPV6
	struct sockaddr_storage	server6;
#endif				
	struct sockaddr_in	server;
	struct sockaddr 	*sa;
	MprSocklen			addrlen;
	int					bytes, errCode;

	mprAssert(buf);
	mprAssert(bufsize > 0);
	mprAssert(~(flags & MPR_SOCKET_CLOSED));

	lock();

	if (flags & MPR_SOCKET_EOF) {
		unlock();
		return 0;
	}

again:
	if (flags & MPR_SOCKET_DATAGRAM) {
#if BLD_FEATURE_IPV6
		if (ipv6) {
			sa = (struct sockaddr*) &server6;
			addrlen = sizeof(server6);
		} else
#endif
		{
			sa = (struct sockaddr*) &server;
			addrlen = sizeof(server);
		}
		bytes = recvfrom(sock, buf, bufsize, MSG_NOSIGNAL, sa, (SocketLenPtr) &addrlen);

	} else {
		bytes = recv(sock, buf, bufsize, MSG_NOSIGNAL);
	}

	if (bytes < 0) {
		errCode = getError();
		if (errCode == EINTR) {
			goto again;

		} else if (errCode == EAGAIN || errCode == EWOULDBLOCK) {
			bytes = 0;							// No data available

		} else if (errCode == ECONNRESET) {
			flags |= MPR_SOCKET_EOF;				// Disorderly disconnect
			bytes = 0;

		} else {
			flags |= MPR_SOCKET_EOF;				// Some other error
			bytes = -errCode;
		}

	} else if (bytes == 0) {					// EOF
		flags |= MPR_SOCKET_EOF;
		mprLog(8, log, "%d: read: %d bytes, EOF\n", sock, bytes);

	} else {
		mprLog(8, log, "%d: read: %d bytes\n", sock, bytes);
	}


	unlock();
	return bytes;
}
Example #9
0
struct hostent *mprGetHostByName(char *name)
{
	Mpr				*mpr;
	struct hostent	*hp;

	mpr = mprGetMpr();
	hp = new hostent;
	memset(hp, 0, sizeof(struct hostent));

	mpr->lock();

#if VXWORKS
	struct in_addr inaddr;
	inaddr.s_addr = (ulong) hostGetByName(name);
	if (inaddr.s_addr < 0) {
		mpr->unlock();
		mprAssert(0);
		return 0;
	}
	hp->h_addrtype = AF_INET;
	hp->h_length = sizeof(int);
	hp->h_name = mprStrdup(name);
	hp->h_addr_list = 0;
	hp->h_aliases = 0;

	hp->h_addr_list = new char*[2];
	hp->h_addr_list[0] = (char *) mprMalloc(sizeof(struct in_addr));
	memcpy(&hp->h_addr_list[0], &inaddr, hp->h_length);
	hp->h_addr_list[1] = 0;

#else
	struct hostent	*ip;
	int				count, i;

	#undef gethostbyname
	ip = gethostbyname(name);
	if (ip == 0) {
		mpr->unlock();
		return 0;
	}
	hp->h_addrtype = ip->h_addrtype;
	hp->h_length = ip->h_length;
	hp->h_name = mprStrdup(ip->h_name);
	hp->h_addr_list = 0;
	hp->h_aliases = 0;

	for (count = 0; ip->h_addr_list[count] != 0; ) {
		count++;
	}
	if (count > 0) {
		count++;
		hp->h_addr_list = new char*[count];
		for (i = 0; ip->h_addr_list[i] != 0; i++) {
			memcpy(&hp->h_addr_list[i], &ip->h_addr_list[i], ip->h_length);
		}
		hp->h_addr_list[i] = 0;
	}

	for (count = 0; ip->h_aliases[count] != 0; ) {
		count++;
	}
	if (count > 0) {
		count++;
		hp->h_aliases = new char*[count];
		for (i = 0; ip->h_aliases[i] != 0; i++) {
			hp->h_aliases[i] = mprStrdup(ip->h_aliases[i]);
		}
		hp->h_aliases[i] = 0;
	}
#endif
	mpr->unlock();
	return hp;
}
Example #10
0
int ejsSetPropertyTrait(Ejs *ejs, EjsVar *vp, int slot, EjsType *propType, int attributes)
{
    mprAssert(vp->type->helpers->setPropertyTrait);
    return (vp->type->helpers->setPropertyTrait)(ejs, vp, slot, propType, attributes);
}
Example #11
0
/*
    Convert the string buffer to a Number.
 */
static MprNumber parseNumber(Ejs *ejs, cchar *str)
{
    int64       num;
    int         radix, c, negative;

    mprAssert(str);

    num = 0;
    negative = 0;

    if (*str == '-') {
        str++;
        negative = 1;
    } else if (*str == '+') {
        str++;
    }

#if BLD_FEATURE_FLOATING_POINT
    if (*str != '.' && !isdigit((int) *str)) {
        return ejs->nanValue->value;
    }

    /*
        Floating format: [DIGITS].[DIGITS][(e|E)[+|-]DIGITS]
     */
    if (!(*str == '0' && tolower((int) str[1]) == 'x')) {
        MprNumber   n;
        cchar       *cp;
        for (cp = str; *cp; cp++) {
            if (*cp == '.' || tolower((int) *cp) == 'e') {
                n = atof(str);
                if (negative) {
                    n = 0.0 - n;
                }
                return n;
            }
        }
    }
#else
    if (*str != '.' && !isdigit(*str)) {
        return 0;
    }
#endif

    /*
        Parse an integer. Observe hex and octal prefixes (0x, 0).
     */
    if (*str != '0') {
        /*
         *  Normal numbers (Radix 10)
         */
        while (isdigit((int) *str)) {
            num = (*str - '0') + (num * 10);
            str++;
        }
    } else {
        str++;
        if (tolower((int) *str) == 'x') {
            str++;
            radix = 16;
            while (*str) {
                c = tolower((int) *str);
                if (isdigit(c)) {
                    num = (c - '0') + (num * radix);
                } else if (c >= 'a' && c <= 'f') {
                    num = (c - 'a' + 10) + (num * radix);
                } else {
                    break;
                }
                str++;
            }

        } else{
            radix = 8;
            while (*str) {
                c = tolower((int) *str);
                if (isdigit(c) && c < '8') {
                    num = (c - '0') + (num * radix);
                } else {
                    break;
                }
                str++;
            }
        }
    }

    if (negative) {
        return (MprNumber) (0 - num);
    }
    return (MprNumber) num;
}
Example #12
0
/*
    Set the property name and return the slot number. Slot may be -1 to allocate a new slot.
 */
int ejsSetPropertyName(Ejs *ejs, EjsVar *vp, int slot, EjsName *qname)
{
    mprAssert(vp->type->helpers->setPropertyName);
    return (vp->type->helpers->setPropertyName)(ejs, vp, slot, qname);
}
Example #13
0
/**
    Return the number of properties in the variable.
    @return Returns the number of properties.
 */
int ejsGetPropertyCount(Ejs *ejs, EjsVar *vp)
{
    mprAssert(vp->type->helpers->getPropertyCount);
    return (vp->type->helpers->getPropertyCount)(ejs, vp);
}
Example #14
0
static int compileInner(EcCompiler *cp, int argc, char **argv)
{
    Ejs         *ejs;
    EjsModule   *mp;
    MprList     *nodes;
    EjsBlock    *block;
    EcLocation  loc;
    cchar       *ext;
    char        *msg;
    int         next, i, j, nextModule, lflags, rc, paused;

    ejs = cp->ejs;
    if ((nodes = mprCreateList(-1, 0)) == 0) {
        return EJS_ERR;
    }
    cp->nodes = nodes;

    /*
        Warn about source files mentioned multiple times.
        TODO OPT. This is slow.
     */
    for (i = 0; i < argc; i++) {
        for (j = 0; j < argc; j++) {
            if (i == j) {
                continue;
            }
            if (mprSamePath(argv[i], argv[j])) {
                compileError(cp, "Loading source %s multiple times. Ignoring extra copies.", argv[i]);
                return EJS_ERR;
            }
        }
        if (cp->outputFile && mprSamePath(cp->outputFile, argv[i])) {
            compileError(cp, "Output file is the same as input file: %s", argv[i]);
            return EJS_ERR;
        }
    }

    /*
        Compile source files and load any module files
     */
    for (i = 0; i < argc && !cp->fatalError; i++) {
        ext = mprGetPathExt(argv[i]);
        if (scasecmp(ext, "mod") == 0 || scasecmp(ext, BIT_SHOBJ) == 0) {
            nextModule = mprGetListLength(ejs->modules);
            lflags = cp->strict ? EJS_LOADER_STRICT : 0;
            if ((rc = ejsLoadModule(cp->ejs, ejsCreateStringFromAsc(ejs, argv[i]), -1, -1, lflags)) < 0) {
                msg = sfmt("Error initializing module %s\n%s", argv[i], ejsGetErrorMsg(cp->ejs, 1));
                memset(&loc, 0, sizeof(EcLocation));
                loc.filename = sclone(argv[i]);
                if (rc == MPR_ERR_CANT_INITIALIZE) {
                    ecError(cp, "Error", &loc, msg);
                } else {
                    ecError(cp, "Error", &loc, msg);
                }
                cp->nodes = NULL;
                return EJS_ERR;
            }
            if (cp->merge) {
                /*
                    If merging, we must emit the loaded module into the output. So add to the compiled modules list.
                 */
                for (next = nextModule; (mp = mprGetNextItem(ejs->modules, &next)) != 0; ) {
                    if (mprLookupItem(cp->modules, mp) < 0 && mprAddItem(cp->modules, mp) < 0) {
                        compileError(cp, "Can't add module %s", mp->name);
                    }
                }
            }
            mprAddItem(nodes, 0);
        } else  {
            mprAssert(!MPR->marking);
            paused = ejsBlockGC(ejs);
            mprAddItem(nodes, ecParseFile(cp, argv[i]));
            ejsUnblockGC(ejs, paused);
        }
        mprAssert(!MPR->marking);
    }
    mprAssert(ejs->result == 0 || (MPR_GET_GEN(MPR_GET_MEM(ejs->result)) != MPR->heap->dead));


    /*
        Allocate the eval frame stack. This is used for property lookups. We have one dummy block at the top always.
     */
    block = ejsCreateBlock(ejs, 0);
    mprSetName(block, "Compiler");
    ejsPushBlock(ejs, block);
    
    /*
        Process the internal representation and generate code
     */
    paused = ejsBlockGC(ejs);
    if (!cp->parseOnly && cp->errorCount == 0) {
        ecResetParser(cp);
        if (ecAstProcess(cp) < 0) {
            ejsPopBlock(ejs);
            cp->nodes = NULL;
            ejsUnblockGC(ejs, paused);
            return EJS_ERR;
        }
        if (cp->errorCount == 0) {
            ecResetParser(cp);
            if (ecCodeGen(cp) < 0) {
                ejsPopBlock(ejs);
                cp->nodes = NULL;
                ejsUnblockGC(ejs, paused);
                return EJS_ERR;
            }
        }
    }
    ejsPopBlock(ejs);
    mprAssert(ejs->result == 0 || (MPR_GET_GEN(MPR_GET_MEM(ejs->result)) != MPR->heap->dead));

    /*
        Add compiled modules to the interpreter
     */
    for (next = 0; ((mp = (EjsModule*) mprGetNextItem(cp->modules, &next)) != 0); ) {
        ejsAddModule(cp->ejs, mp);
    }
    cp->nodes = NULL;
    ejsUnblockGC(ejs, paused);
    if (!paused) {
        mprYield(0);
    }
    mprAssert(ejs->result == 0 || (MPR_GET_GEN(MPR_GET_MEM(ejs->result)) != MPR->heap->dead));
    return (cp->errorCount > 0) ? EJS_ERR: 0;
}
Example #15
0
/*
    Configure the server. If the configFile is defined, use it. If not, then consider home, documents, ip and port.
 */
int maConfigureServer(MaServer *server, cchar *configFile, cchar *home, cchar *documents, cchar *ip, int port)
{
    MaAppweb        *appweb;
    Http            *http;
    HttpEndpoint    *endpoint;
    HttpHost        *host;
    HttpRoute       *route;
    char            *path;

    appweb = server->appweb;
    http = appweb->http;

    if (configFile) {
        path = mprGetAbsPath(configFile);
        if (maParseConfig(server, path, 0) < 0) {
            /* mprUserError("Can't configure server using %s", path); */
            return MPR_ERR_CANT_INITIALIZE;
        }
        return 0;

    } else {
        mprLog(2, "DocumentRoot %s", documents);
        if ((endpoint = httpCreateConfiguredEndpoint(home, documents, ip, port)) == 0) {
            return MPR_ERR_CANT_OPEN;
        }
        maAddEndpoint(server, endpoint);
        host = mprGetFirstItem(endpoint->hosts);
        mprAssert(host);
        route = mprGetFirstItem(host->routes);
        mprAssert(route);

#if UNUSED
        searchPath = getSearchPath(dir);
        mprSetModuleSearchPath(searchPath);
#endif

#if BLD_FEATURE_CGI
        maLoadModule(appweb, "cgiHandler", "mod_cgi");
        if (httpLookupStage(http, "cgiHandler")) {
            httpAddRouteHandler(route, "cgiHandler", "cgi cgi-nph bat cmd pl py");
            /*
                Add cgi-bin with a route for the /cgi-bin URL prefix.
             */
            path = "cgi-bin";
            if (mprPathExists(path, X_OK)) {
                HttpRoute *cgiRoute;
                cgiRoute = httpCreateAliasRoute(route, "/cgi-bin/", path, 0);
                mprLog(4, "ScriptAlias \"/cgi-bin/\":\"%s\"", path);
                httpSetRouteHandler(cgiRoute, "cgiHandler");
                httpFinalizeRoute(cgiRoute);
            }
        }
#endif
#if BLD_FEATURE_ESP
        maLoadModule(appweb, "espHandler", "mod_esp");
        if (httpLookupStage(http, "espHandler")) {
            httpAddRouteHandler(route, "espHandler", "esp");
        }
#endif
#if BLD_FEATURE_EJSCRIPT
        maLoadModule(appweb, "ejsHandler", "mod_ejs");
        if (httpLookupStage(http, "ejsHandler")) {
            httpAddRouteHandler(route, "ejsHandler", "ejs");
        }
#endif
#if BLD_FEATURE_PHP
        maLoadModule(appweb, "phpHandler", "mod_php");
        if (httpLookupStage(http, "phpHandler")) {
            httpAddRouteHandler(route, "phpHandler", "php");
        }
#endif
        httpAddRouteHandler(route, "fileHandler", "");
        httpFinalizeRoute(route);
    }
    if (home) {
        maSetServerHome(server, home);
    }
    if (ip || port > 0) {
        maSetServerAddress(server, ip, port);
    }
    return 0;
}
Example #16
0
int MprSocket::openServer(char *addr, int portNum, MprSocketAcceptProc acceptFn, 
						  void *data, int initialFlags)
{
#if BLD_FEATURE_IPV6
	struct addrinfo		hints, *res;
	struct sockaddr_storage	sockAddr6;
	char 				portNumString[MPR_MAX_IP_PORT];
	char 				addrBuf[MPR_MAX_IP_ADDR];
	char 				*bindName;
#endif
	struct sockaddr_in	sockAddr;
	struct sockaddr 	*sa;
	struct hostent		*hostent;
	MprSocklen 			addrlen;
	int					datagram, rc;

	mprAssert(addr);

	if (addr == 0 || *addr == '\0') {
		mprLog(6, log, "openServer: *:%d, flags %x\n", portNum, initialFlags);
	} else {
		mprLog(6, log, "openServer: %s:%d, flags %x\n", addr, portNum, initialFlags);
	}


#if BLD_FEATURE_IPV6

	if (addr[0] == '[') {
		ipv6 = 1;
		mprStrcpy(addrBuf, sizeof(addrBuf), &addr[1]);
		mprAssert(addrBuf[strlen(addrBuf) - 1] == ']');
		addrBuf[strlen(addrBuf) - 1] = '\0';
		addr = addrBuf;
	}

	if (ipv6) {
		memset((char *) &hints, '\0', sizeof(hints));
		memset((char *) &sockAddr6, '\0', sizeof(struct sockaddr_storage));

		mprSprintf(portNumString, sizeof(portNumString), "%d", portNum);

		hints.ai_socktype = SOCK_STREAM;
		hints.ai_family = AF_INET6;

		if (strcmp(addr, "") != 0) {
			bindName = addr;
		} else {
			bindName = NULL;
			hints.ai_flags |= AI_PASSIVE; 				/* Bind to 0.0.0.0 and :: */
														/* Sets to IN6ADDR_ANY_INIT */
		}
			
		rc = getaddrinfo(bindName, portNumString, &hints, &res);
		if (rc) {
			return MPR_ERR_CANT_OPEN;

		}
		sa = (struct sockaddr*) &sockAddr6;
		memcpy(sa, res->ai_addr, res->ai_addrlen);
		addrlen = res->ai_addrlen;
		freeaddrinfo(res);

	} else 
#endif
	{
		/*
		 *	TODO could we use getaddrinfo in all cases. ie. merge with IPV6 code
		 */
		memset((char *) &sockAddr, '\0', sizeof(struct sockaddr_in));
		addrlen = sizeof(struct sockaddr_in);
		sockAddr.sin_family = AF_INET;

		sockAddr.sin_port = htons((short) (portNum & 0xFFFF));
		if (strcmp(addr, "") != 0) {
			sockAddr.sin_addr.s_addr = inet_addr(addr);
			if (sockAddr.sin_addr.s_addr == INADDR_NONE) {
				hostent = mprGetHostByName(addr);
				if (hostent != 0) {
					memcpy((char*) &sockAddr.sin_addr, (char*) hostent->h_addr_list[0], 
						(size_t) hostent->h_length);
					mprFreeGetHostByName(hostent);
				} else {
					return MPR_ERR_NOT_FOUND;
				}
			}
		} else {
			sockAddr.sin_addr.s_addr = INADDR_ANY;
		}
		sa = (struct sockaddr*) &sockAddr;
	}

	lock();
	port = portNum;
	acceptCallback = acceptFn;
	acceptData = data;

	flags = (initialFlags & 
		(MPR_SOCKET_BROADCAST | MPR_SOCKET_DATAGRAM | MPR_SOCKET_BLOCK | 
		 MPR_SOCKET_LISTENER | MPR_SOCKET_NOREUSE | MPR_SOCKET_NODELAY));

	ipAddr = mprStrdup(addr);

	datagram = flags & MPR_SOCKET_DATAGRAM;

	//
	//	Create the O/S socket
	//
	sock = socket(sa->sa_family, datagram ? SOCK_DGRAM: SOCK_STREAM, 0);
	if (sock < 0) {
		unlock();
		return MPR_ERR_CANT_OPEN;
	}
#if !WIN && !WINCE && !VXWORKS
	fcntl(sock, F_SETFD, FD_CLOEXEC);		// Children won't inherit this fd
#endif

#if CYGWIN || LINUX || MACOSX || VXWORKS || FREEBSD
	if (!(flags & MPR_SOCKET_NOREUSE)) {
		rc = 1;
		setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &rc, sizeof(rc));
	}
#endif

	rc = bind(sock, sa, addrlen);
	// rc = bind(sock, res->ai_addr, res->ai_addrlen);
	if (rc < 0) {
		int err = errno;
		err = err;
		::closesocket(sock);
		sock = -1;
		unlock();
		return MPR_ERR_CANT_OPEN;
	}

	if (! datagram) {
		flags |= MPR_SOCKET_LISTENER;
		if (listen(sock, SOMAXCONN) < 0) {
			::closesocket(sock);
			sock = -1;
			unlock();
			return MPR_ERR_CANT_OPEN;
		}
		handler = new MprSelectHandler(sock, MPR_SOCKET_READABLE, 
			(MprSelectProc) acceptProcWrapper, (void*) this, handlerPriority);
	}
	handlerMask |= MPR_SOCKET_READABLE;

//TODO - what about WINCE?
#if WIN
	//
	//	Delay setting reuse until now so that we can be assured that we
	//	have exclusive use of the port.
	//
	if (!(flags & MPR_SOCKET_NOREUSE)) {
		rc = 1;
		setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &rc, sizeof(rc));
	}
#endif

	setBlockingMode((bool) (flags & MPR_SOCKET_BLOCK));

	//
	//	TCP/IP stacks have the No delay option (nagle algorithm) on by default.
	//
	if (flags & MPR_SOCKET_NODELAY) {
		setNoDelay(1);
	}
	unlock();
	return sock;
}
Example #17
0
int MprLogService::setLogSpec(char *fileSpec)
{
	MprLogModule	*mp;
	MprLogListener	*lp;
	char			namBuf[MPR_MAX_FNAME];
	char			*spec, *cp, *sizeStr;
	int				maxSize;

	mprAssert(!logging);
#if BLD_FEATURE_MULTITHREAD
	if (mutex == 0) {
		mutex = new MprMutex();
	}
#endif
	lock();

	logging = 1;
	if (fileSpec == NULL || *fileSpec == '\0') {
		fileSpec = "trace.txt";
	}

	logSpec = mprStrdup(fileSpec);
	spec = mprStrdup(fileSpec);
	for (cp = spec; *cp; cp++) {
		if (*cp == ':' && isdigit(cp[1])) {
			break;
		}
	}

	maxSize = MPR_MAX_LOG_SIZE;
	if (*cp) {
		*cp++ = '\0';
		moduleSpecs = strchr(cp, ',');

		sizeStr = strchr(cp, '.');
		if (sizeStr != 0) {
			*sizeStr++ = '\0';
			maxSize = atoi(sizeStr);					// Size in MB
		}

		//
		//	Set all modules to the default trace level and then examine
		//	the modules spec to override specified modules
		//
		defaultLevel = atoi(cp);
		if (defaultLevel < 0) {
			defaultLevel = 0;
		}

		mp = (MprLogModule*) moduleList.getFirst();
		while (mp) {
			mp->setLevel(defaultLevel);
			mp = (MprLogModule*) moduleList.getNext(mp);
		}

		if (moduleSpecs) {
			moduleSpecs++;
			mp = (MprLogModule*) moduleList.getFirst();
			while (mp) {
				mprSprintf(namBuf, sizeof(namBuf), "%s:", mp->getName());
				if ((cp = strstr(moduleSpecs, namBuf)) != 0) {
					if ((cp = strchr(cp, ':')) != 0) {
						mp->setLevel(atoi(++cp));
					}
				}
				mp = (MprLogModule*) moduleList.getNext(mp);
			}
		}
	}
	if (spec != 0 && *spec != '\0') {
		lp = (MprLogListener*) listeners.getFirst();
		while (lp) {
			if (lp->setLogSpec(spec, maxSize) < 0) {
				mprFree(spec);
				unlock();
				return MPR_ERR_CANT_OPEN;
			}
			lp = (MprLogListener*) listeners.getNext(lp);
		}
	}
	mprFree(spec);
	unlock();
	return 0;
}
Example #18
0
int MprSocket::openClient(char *addr, int portNum, int initialFlags)
{
#if BLD_FEATURE_IPV6
	struct addrinfo 	hints, *res;
	struct sockaddr_storage	remoteAddr6;
	char 				portNum_string[MPR_MAX_IP_PORT];
	char 				addrBuf[MPR_MAX_IP_ADDR];
#endif
	struct sockaddr_in	remoteAddr;
	struct hostent		*hostent;
	struct sockaddr 	*sa;
	MprSocklen			addrlen;
	int					broadcast, datagram, rc, err;

	mprLog(6, log, "openClient: %s:%d, flags %x\n", addr, portNum, 
		initialFlags);

#if BLD_FEATURE_IPV6
	if (addr[0] == '[') {
		ipv6 = 1;
		mprStrcpy(addrBuf, sizeof(addr), &addr[1]);
		mprAssert(addrBuf[strlen(addrBuf) - 2] == ']');
		addrBuf[strlen(addrBuf) - 2] = '\0';
		addr = addrBuf;
	} else {
        ipv6 = 0;
    }

	if (ipv6) {
		memset((char*) &hints, '\0', sizeof(hints));
		memset((char*) &remoteAddr6, '\0', sizeof(struct sockaddr_storage));

		mprSprintf(portNum_string, sizeof(portNum_string), "%d", portNum);

		hints.ai_socktype = SOCK_STREAM;

		rc = getaddrinfo(addr, portNum_string, &hints, &res);
		if (rc) {
			/* no need to unlock yet */
			return MPR_ERR_CANT_OPEN;

		}
		sa = (struct sockaddr*) &remoteAddr6;
		memcpy(sa, res->ai_addr, res->ai_addrlen);
		addrlen = res->ai_addrlen;
		freeaddrinfo(res);
		
	} else 
#endif
	{
		memset((char *) &remoteAddr, '\0', sizeof(struct sockaddr_in));
		remoteAddr.sin_family = AF_INET;
		remoteAddr.sin_port = htons((short) (portNum & 0xFFFF));
		sa = (struct sockaddr*) &remoteAddr;
		addrlen = sizeof(remoteAddr);
	}
		
	lock();
	port = portNum;
	flags = (initialFlags & 
		(MPR_SOCKET_BROADCAST | MPR_SOCKET_DATAGRAM | MPR_SOCKET_BLOCK | 
		 MPR_SOCKET_LISTENER | MPR_SOCKET_NOREUSE | MPR_SOCKET_NODELAY));

	//	Save copy of the address
	ipAddr = mprStrdup(addr);

#if BLD_FEATURE_IPV6
	if (!ipv6) {
		// Nothing here
	} else 
#endif
	{
		remoteAddr.sin_addr.s_addr = inet_addr(ipAddr);
		if (remoteAddr.sin_addr.s_addr == INADDR_NONE) {
			hostent = mprGetHostByName(ipAddr);
			if (hostent != 0) {
				memcpy((char*) &remoteAddr.sin_addr, (char*) hostent->h_addr_list[0], 
					(size_t) hostent->h_length);
				mprFreeGetHostByName(hostent);
			} else {
				unlock();
				return MPR_ERR_NOT_FOUND;
			}
		}
	}

	broadcast = flags & MPR_SOCKET_BROADCAST;
	if (broadcast) {
		flags |= MPR_SOCKET_DATAGRAM;
	}
	datagram = flags & MPR_SOCKET_DATAGRAM;

	//
	//	Create the O/S socket
	//
	sock = socket(sa->sa_family, datagram ? SOCK_DGRAM: SOCK_STREAM, 0);
	if (sock < 0) {
		err = getError();
		unlock();
		return -err;
	}
#if !WIN && !WINCE && !VXWORKS
	fcntl(sock, F_SETFD, FD_CLOEXEC);		// Children won't inherit this fd
#endif

	if (broadcast) {
		int	flag = 1;
		if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *) &flag, sizeof(flag)) < 0) {
			err = getError();
			::closesocket(sock);
			sock = -1;
			unlock();
			return -err;
		}
	}
 
	if (!datagram) {
		flags |= MPR_SOCKET_CONNECTING;
		rc = connect(sock, sa, addrlen);
		if (rc < 0) {
			err = getError();
			::closesocket(sock);
			sock = -1;
			unlock();
#if UNUSED
			//
			//	If the listen backlog is too high, ECONNREFUSED is returned
			//
			if (err == EADDRINUSE || err == ECONNREFUSED) {
				return MPR_ERR_BUSY;
			}
#endif
			return -err;
		}
	}

	setBlockingMode((bool) (flags & MPR_SOCKET_BLOCK));

	//
	//	TCP/IP stacks have the No delay option (nagle algorithm) on by default.
	//
	if (flags & MPR_SOCKET_NODELAY) {
		setNoDelay(1);
	}
	unlock();
	return sock;
}
Example #19
0
/*
    XML recursive descent parser. Return -1 for errors, 0 for EOF and 1 if there is still more data to parse.
 */
static int parseNext(MprXml *xp, int state)
{
    MprXmlHandler   handler;
    MprXmlToken     token;
    MprBuf          *tokBuf;
    char            *tname, *aname;
    int             rc;

    mprAssert(state >= 0);

    tokBuf = xp->tokBuf;
    handler = xp->handler;
    tname = aname = 0;
    rc = 0;
    
    /*
        In this parse loop, the state is never assigned EOF or ERR. In such cases we always return EOF or ERR.
     */
    while (1) {

        token = getXmlToken(xp, state);

        if (token == MPR_XMLTOK_TOO_BIG) {
            xmlError(xp, "XML token is too big");
            return MPR_ERR_WONT_FIT;
        }

        switch (state) {
        case MPR_XML_BEGIN:     /* ------------------------------------------ */
            /*
                Expect to get an element, comment or processing instruction 
             */
            switch (token) {
            case MPR_XMLTOK_EOF:
                return 0;

            case MPR_XMLTOK_LS:
                /*
                    Recurse to handle the new element, comment etc.
                 */
                rc = parseNext(xp, MPR_XML_AFTER_LS);
                if (rc < 0) {
                    return rc;
                }
                break;

            default:
                xmlError(xp, "Syntax error");
                return MPR_ERR_BAD_SYNTAX;
            }
            break;

        case MPR_XML_AFTER_LS: /* ------------------------------------------ */
            switch (token) {
            case MPR_XMLTOK_COMMENT:
                state = MPR_XML_COMMENT;
                rc = (*handler)(xp, state, "!--", 0, mprGetBufStart(tokBuf));
                if (rc < 0) {
                    return rc;
                }
                return 1;

            case MPR_XMLTOK_CDATA:
                state = MPR_XML_CDATA;
                rc = (*handler)(xp, state, "!--", 0, mprGetBufStart(tokBuf));
                if (rc < 0) {
                    return rc;
                }
                return 1;

            case MPR_XMLTOK_INSTRUCTIONS:
                /* Just ignore processing instructions */
                return 1;

            case MPR_XMLTOK_TEXT:
                state = MPR_XML_NEW_ELT;
                tname = sclone(mprGetBufStart(tokBuf));
                if (tname == 0) {
                    mprAssert(!MPR_ERR_MEMORY);
                    return MPR_ERR_MEMORY;
                }
                rc = (*handler)(xp, state, tname, 0, 0);
                if (rc < 0) {
                    return rc;
                }
                break;

            default:
                xmlError(xp, "Syntax error");
                return MPR_ERR_BAD_SYNTAX;
            }
            break;

        case MPR_XML_NEW_ELT:   /* ------------------------------------------ */
            /*
                We have seen the opening "<element" for a new element and have not yet seen the terminating 
                ">" of the opening element.
             */
            switch (token) {
            case MPR_XMLTOK_TEXT:
                /*
                    Must be an attribute name
                 */
                aname = sclone(mprGetBufStart(tokBuf));
                token = getXmlToken(xp, state);
                if (token != MPR_XMLTOK_EQ) {
                    xmlError(xp, "Missing assignment for attribute \"%s\"", aname);
                    return MPR_ERR_BAD_SYNTAX;
                }

                token = getXmlToken(xp, state);
                if (token != MPR_XMLTOK_TEXT) {
                    xmlError(xp, "Missing value for attribute \"%s\"", aname);
                    return MPR_ERR_BAD_SYNTAX;
                }
                state = MPR_XML_NEW_ATT;
                rc = (*handler)(xp, state, tname, aname, mprGetBufStart(tokBuf));
                if (rc < 0) {
                    return rc;
                }
                state = MPR_XML_NEW_ELT;
                break;

            case MPR_XMLTOK_GR:
                /*
                    This is ">" the termination of the opening element
                 */
                if (*tname == '\0') {
                    xmlError(xp, "Missing element name");
                    return MPR_ERR_BAD_SYNTAX;
                }

                /*
                    Tell the user that the opening element is now complete
                 */
                state = MPR_XML_ELT_DEFINED;
                rc = (*handler)(xp, state, tname, 0, 0);
                if (rc < 0) {
                    return rc;
                }
                state = MPR_XML_ELT_DATA;
                break;

            case MPR_XMLTOK_SLASH_GR:
                /*
                    If we see a "/>" then this is a solo element
                 */
                if (*tname == '\0') {
                    xmlError(xp, "Missing element name");
                    return MPR_ERR_BAD_SYNTAX;
                }
                state = MPR_XML_SOLO_ELT_DEFINED;
                rc = (*handler)(xp, state, tname, 0, 0);
                if (rc < 0) {
                    return rc;
                }
                return 1;
    
            default:
                xmlError(xp, "Syntax error");
                return MPR_ERR_BAD_SYNTAX;
            }
            break;

        case MPR_XML_ELT_DATA:      /* -------------------------------------- */
            /*
                We have seen the full opening element "<name ...>" and now await data or another element.
             */
            if (token == MPR_XMLTOK_LS) {
                /*
                    Recurse to handle the new element, comment etc.
                 */
                rc = parseNext(xp, MPR_XML_AFTER_LS);
                if (rc < 0) {
                    return rc;
                }
                break;

            } else if (token == MPR_XMLTOK_LS_SLASH) {
                state = MPR_XML_END_ELT;
                break;

            } else if (token != MPR_XMLTOK_TEXT) {
                return rc;
            }
            if (mprGetBufLength(tokBuf) > 0) {
                /*
                    Pass the data between the element to the user
                 */
                rc = (*handler)(xp, state, tname, 0, mprGetBufStart(tokBuf));
                if (rc < 0) {
                    return rc;
                }
            }
            break;

        case MPR_XML_END_ELT:           /* -------------------------------------- */
            if (token != MPR_XMLTOK_TEXT) {
                xmlError(xp, "Missing closing element name for \"%s\"", tname);
                return MPR_ERR_BAD_SYNTAX;
            }
            /*
                The closing element name must match the opening element name 
             */
            if (strcmp(tname, mprGetBufStart(tokBuf)) != 0) {
                xmlError(xp, "Closing element name \"%s\" does not match on line %d. Opening name \"%s\"",
                    mprGetBufStart(tokBuf), xp->lineNumber, tname);
                return MPR_ERR_BAD_SYNTAX;
            }
            rc = (*handler)(xp, state, tname, 0, 0);
            if (rc < 0) {
                return rc;
            }
            if (getXmlToken(xp, state) != MPR_XMLTOK_GR) {
                xmlError(xp, "Syntax error");
                return MPR_ERR_BAD_SYNTAX;
            }
            return 1;

        case MPR_XML_EOF:       /* ---------------------------------------------- */
            return 0;

        case MPR_XML_ERR:   /* ---------------------------------------------- */
        default:
            return MPR_ERR;
        }
    }
    mprAssert(0);
}
Example #20
0
void MprSocket::close(int timeout)
{
	MprSelectService	*ss;
	Mpr					*mpr;
	char				buf[1024];
	int					handlerFlags, timesUp;

	mpr = mprGetMpr();

	mprLog(7, log, "%d: close\n", sock);
	ss = mpr->selectService;

	lock();
	mprAssert(!(flags & MPR_SOCKET_CLOSED));
	if (flags & MPR_SOCKET_CLOSED) {
		unlock();
		return;
	}
	flags |= MPR_SOCKET_CLOSED;
	handlerFlags = (handler) ? handler->getFlags() : 0;

	if (handler) {
		handler->dispose();
		handler = 0;
	}

	if (sock >= 0) {
		//
		//	Do a graceful shutdown. Read any outstanding read data to prevent
		//	resets. Then do a shutdown to send a FIN and read outstanding 
		//	data. All non-blocking.
		//
//TODO - what about WINCE?
#if WIN
		if (ss->getFlags() & MPR_ASYNC_SELECT) {

			if (handlerFlags & MPR_SELECT_CLIENT_CLOSED) {
				//
				//	Client initiated close. We have already received an FD_CLOSE
				//
				closesocket(sock);
				sock = -1;

			} else {

				if (shutdown(sock, SHUT_WR) == 0) {
					//
					//	Do a graceful shutdown. Read any outstanding read data to 
					//	prevent resets. Then do a shutdown to send a FIN and lastly
					//	read data when the FD_CLOSE is received (see select.cpp). 
					//	All done non-blocking.
					//
					timesUp = mprGetTime(0) + timeout;
					do {
    					if (recv(sock, buf, sizeof(buf), 0) <= 0) {
							break;
						}
					} while (mprGetTime(0) < timesUp);
				}

				//
				//	Delayed close call must be first so we are ready when the
				//	FD_CLOSE arrives. Other way round and there is a race if 
				//	multi-threaded. 
				//
				ss->delayedClose(sock);

				//
				//	We need to ensure we receive an FD_CLOSE to complete the
				//	delayed close. Despite disposing the hander above, socket 
				//	messages will still be sent from windows and so select can 
				//	cleanup the delayed close socket.
				//
				WSAAsyncSelect(sock, ss->getHwnd(), ss->getMessage(), FD_CLOSE);
			}
		
		} else {
#endif
			if (shutdown(sock, SHUT_WR) < 0) {
				ss->delayedClose(sock);

			} else {
				setBlockingMode(0);
				timesUp = mprGetTime(0) + timeout;
				do {
					if (recv(sock, buf, sizeof(buf), 0) <= 0) {
						break;
					}
					
				} while (mprGetTime(0) < timesUp);
			}

			//
			//	Use delayed close to prevent anyone else reusing the socket
			//	while select has not fully cleaned it out of its masks.
			//
			ss->delayedClose(sock);
			ss->awaken(0);
		}
#if WIN
	}
#endif

	//
	//	Re-initialize all socket variables so the Socket can be reused.
	//
	acceptCallback = 0;
	acceptData = 0;
	selectEvents = 0;
	currentEvents = 0;
	error = 0;
	flags = MPR_SOCKET_CLOSED;
	ioCallback = 0;
	ioData = 0;
	ioData2 = 0;
	handlerMask = 0;
	handlerPriority = MPR_NORMAL_PRIORITY;
	interestEvents = 0;
	port = -1;
	sock = -1;

	if (ipAddr) {
		mprFree(ipAddr);
		ipAddr = 0;
	}

	unlock();
}
Example #21
0
void mprXmlSetParserHandler(MprXml *xp, MprXmlHandler h)
{
    mprAssert(xp);
    xp->handler = h;
}
Example #22
0
int	MprSocket::write(char *buf, int bufsize)
{
#if BLD_FEATURE_IPV6
	struct addrinfo 	hints, *res;
	struct sockaddr_storage	server6;
	char 				port_string[MPR_MAX_IP_PORT];
	int 				rc;
#endif				
	struct sockaddr_in	server;
	struct sockaddr 	*sa;
	MprSocklen 			addrlen;
	int					sofar, errCode, len, written;

	mprAssert(buf);
	mprAssert(bufsize >= 0);
	mprAssert((flags & MPR_SOCKET_CLOSED) == 0);

	addrlen = 0;
	sa = 0;

	lock();

	if (flags & (MPR_SOCKET_BROADCAST | MPR_SOCKET_DATAGRAM)) {
#if BLD_FEATURE_IPV6
		if (ipv6) {
			memset((char *) &hints, '\0', sizeof(hints));
			memset((char *) &server, '\0', sizeof(struct sockaddr_storage));
			
			mprSprintf(port_string, sizeof(port_string), "%d", port);

			hints.ai_socktype = SOCK_STREAM;
			hints.ai_flags = AI_NUMERICHOST;

			if (strcmp(ipAddr, "") == 0) {
				//	Note that IPv6 does not support broadcast, there is no
				//	255.255.255.255 equiv. Multicast can be used over a specific 
				//	link, but the user must provide that address plus %scope_id.
				unlock();
				return -1;
			}

			rc = getaddrinfo(ipAddr, port_string, &hints, &res);
			if (rc) {
				unlock();
				return -1;

			} else {
				memcpy(&server, res->ai_addr, res->ai_addrlen);
				addrlen = res->ai_addrlen;
				freeaddrinfo(res);
			}
			sa = (struct sockaddr*) &server6;

		} else 
#endif
		{
			memset((char*) &server, '\0', sizeof(struct sockaddr_in));
			addrlen = sizeof(struct sockaddr_in);
			server.sin_family = AF_INET;

			server.sin_port = htons((short) (port & 0xFFFF));
			if (strcmp(ipAddr, "") != 0) {
				server.sin_addr.s_addr = inet_addr(ipAddr);
			} else {
				server.sin_addr.s_addr = INADDR_ANY;
			}
			sa = (struct sockaddr*) &server;
		}
	}
	
		
	if (flags & MPR_SOCKET_EOF) {
		sofar = bufsize;

	} else {
		errCode = 0;
		len = bufsize;
		sofar = 0;
		while (len > 0) {
			if ((flags & MPR_SOCKET_BROADCAST) || 
					(flags & MPR_SOCKET_DATAGRAM)) {
				written = sendto(sock, &buf[sofar], len, MSG_NOSIGNAL, sa, addrlen);
			} else {
				written = send(sock, &buf[sofar], len, MSG_NOSIGNAL);
			}
			if (written < 0) {
				errCode = getError();
				if (errCode == EINTR) {
					mprLog(8, log, "%d: write: EINTR\n", sock);
					continue;
				} else if (errCode == EAGAIN || errCode == EWOULDBLOCK) {
					mprLog(8, log, "%d: write: EAGAIN returning %d\n", sock, sofar);
					unlock();
					return sofar;
				}
				mprLog(8, log, "%d: write: error %d\n", sock, -errCode);
				unlock();
				return -errCode;
			}
			len -= written;
			sofar += written;
		}
	}

	mprLog(8, log, "%d: write: %d bytes, ask %d, flags %x\n", sock, sofar, bufsize, flags);

	unlock();
	return sofar;
}
Example #23
0
/*
    Set the parse arg
 */ 
void *mprXmlGetParseArg(MprXml *xp)
{
    mprAssert(xp);

    return xp->parseArg;
}
Example #24
0
/*
 *  Add a shell parameter then do the regular init
 */
Mpr *mprCreateEx(int argc, char **argv, MprAllocNotifier cback, void *shell)
{
    MprFileSystem   *fs;
    Mpr             *mpr;
    char            *cp;

    if (cback == 0) {
        cback = memoryFailure;
    }
    mpr = (Mpr*) mprCreateAllocService(cback, (MprDestructor) mprDestructor);

    if (mpr == 0) {
        mprAssert(mpr);
        return 0;
    }
    
    /*
     *  Wince and Vxworks passes an arg via argc, and the program name in argv. NOTE: this will only work on 32-bit systems.
     */
#if WINCE
    mprMakeArgv(mpr, (char*) argv, mprToAsc(mpr, (uni*) argc), &argc, &argv);
#elif VXWORKS
    mprMakeArgv(mpr, NULL, (char*) argc, &argc, &argv);
#endif
    mpr->argc = argc;
    mpr->argv = argv;

    mpr->name = mprStrdup(mpr, BLD_PRODUCT);
    mpr->title = mprStrdup(mpr, BLD_NAME);
    mpr->version = mprStrdup(mpr, BLD_VERSION);
    mpr->idleCallback = mprServicesAreIdle;

    if (mprCreateTimeService(mpr) < 0) {
        goto error;
    }
    if ((mpr->osService = mprCreateOsService(mpr)) < 0) {
        goto error;
    }

    /*
     *  See if any of the preceeding allocations failed and mark all blocks allocated so far as required.
     *  They will then be omitted from leak reports.
     */
    if (mprHasAllocError(mpr)) {
        goto error;
    }

#if BREW
    mprSetShell(mpr, shell);
#endif

#if BLD_FEATURE_MULTITHREAD
    mpr->multiThread = 1;
    if ((mpr->threadService = mprCreateThreadService(mpr)) == 0) {
        goto error;
    }
    mpr->mutex = mprCreateLock(mpr);
    mpr->spin = mprCreateSpinLock(mpr);
#endif

    if ((fs = mprCreateFileSystem(mpr, "/")) == 0) {
        goto error;
    }
    mprAddFileSystem(mpr, fs);

    if ((mpr->moduleService = mprCreateModuleService(mpr)) == 0) {
        goto error;
    }
    if ((mpr->dispatcher = mprCreateDispatcher(mpr)) == 0) {
        goto error;
    }
#if BLD_FEATURE_CMD
    if ((mpr->cmdService = mprCreateCmdService(mpr)) == 0) {
        goto error;
    }
#endif
#if BLD_FEATURE_MULTITHREAD
    if ((mpr->workerService = mprCreateWorkerService(mpr)) == 0) {
        goto error;
    }
#endif
    if ((mpr->waitService = mprCreateWaitService(mpr)) == 0) {
        goto error;
    }
    if ((mpr->socketService = mprCreateSocketService(mpr)) == 0) {
        goto error;
    }
#if BLD_FEATURE_HTTP
    if ((mpr->httpService = mprCreateHttpService(mpr)) == 0) {
        goto error;
    }
#endif

    if (mpr->argv && mpr->argv[0] && *mpr->argv[0]) {
        mprFree(mpr->name);
        mpr->name = mprGetPathBase(mpr, mpr->argv[0]);
        if ((cp = strchr(mpr->name, '.')) != 0) {
            *cp = '\0';
        }
    }

    /*
     *  Now catch all memory allocation errors up to this point. Should be none.
     */
    if (mprHasAllocError(mpr)) {
        goto error;
    }
    return mpr;

/*
 *  Error return
 */
error:
    mprFree(mpr);
    return 0;
}
Example #25
0
/*
 *  Create the host addresses for a host. Called for hosts or for NameVirtualHost directives (host == 0).
 */
int maCreateHostAddresses(MaServer *server, MaHost *host, cchar *configValue)
{
    MaListen        *listen;
    MaHostAddress   *address;
    char            *ipAddrPort, *ipAddr, *value, *tok;
    char            addrBuf[MPR_MAX_IP_ADDR_PORT];
    int             next, port;

    address = 0;
    value = mprStrdup(server, configValue);
    ipAddrPort = mprStrTok(value, " \t", &tok);

    while (ipAddrPort) {
        if (mprStrcmpAnyCase(ipAddrPort, "_default_") == 0) {
            mprAssert(0);
            ipAddrPort = "*:*";
        }

        if (mprParseIp(server, ipAddrPort, &ipAddr, &port, -1) < 0) {
            mprError(server, "Can't parse ipAddr %s", ipAddrPort);
            continue;
        }
        mprAssert(ipAddr && *ipAddr);
        if (ipAddr[0] == '*') {
            ipAddr = mprStrdup(server, "");
        }

        /*
         *  For each listening endpiont,
         */
        for (next = 0; (listen = mprGetNextItem(server->listens, &next)) != 0; ) {
            if (port > 0 && port != listen->port) {
                continue;
            }
            if (listen->ipAddr[0] != '\0' && ipAddr[0] != '\0' && strcmp(ipAddr, listen->ipAddr) != 0) {
                continue;
            }

            /*
             *  Find the matching host address or create a new one
             */
            if ((address = maLookupHostAddress(server, listen->ipAddr, listen->port)) == 0) {
                address = maCreateHostAddress(server, listen->ipAddr, listen->port);
                mprAddItem(server->hostAddresses, address);
            }

            /*
             *  If a host is specified
             */
            if (host == 0) {
                maSetNamedVirtualHostAddress(address);

            } else {
                maInsertVirtualHost(address, host);
                if (listen->ipAddr[0] != '\0') {
                    mprSprintf(addrBuf, sizeof(addrBuf), "%s:%d", listen->ipAddr, listen->port);
                } else {
                    mprSprintf(addrBuf, sizeof(addrBuf), "%s:%d", ipAddr, listen->port);
                }
                maSetHostName(host, addrBuf);
            }
        }
        mprFree(ipAddr);
        ipAddrPort = mprStrTok(0, " \t", &tok);
    }

    if (host) {
        if (address == 0) {
            mprError(server, "No valid IP address for host %s", host->name);
            mprFree(value);
            return MPR_ERR_CANT_INITIALIZE;
        }
        if (maIsNamedVirtualHostAddress(address)) {
            maSetNamedVirtualHost(host);
        }
    }

    mprFree(value);

    return 0;
}
Example #26
0
static void netOutgoingService(HttpQueue *q)
{
    HttpConn    *conn;
    HttpTx      *tx;
    ssize       written;
    int         errCode;

    conn = q->conn;
    tx = conn->tx;
    conn->lastActivity = conn->http->now;
    mprAssert(conn->sock);
    
    if (!conn->sock || conn->connectorComplete) {
        return;
    }
    if (tx->flags & HTTP_TX_NO_BODY) {
        httpDiscardQueueData(q, 1);
    }
    if ((tx->bytesWritten + q->count) > conn->limits->transmissionBodySize) {
        httpError(conn, HTTP_CODE_REQUEST_TOO_LARGE | ((tx->bytesWritten) ? HTTP_ABORT : 0),
            "Http transmission aborted. Exceeded transmission max body of %,Ld bytes", conn->limits->transmissionBodySize);
        if (tx->bytesWritten) {
            httpConnectorComplete(conn);
            return;
        }
    }
    if (tx->flags & HTTP_TX_SENDFILE) {
        /* Relay via the send connector */
        if (tx->file == 0) {
            if (tx->flags & HTTP_TX_HEADERS_CREATED) {
                tx->flags &= ~HTTP_TX_SENDFILE;
            } else {
                tx->connector = conn->http->sendConnector;
                httpSendOpen(q);
            }
        }
        if (tx->file) {
            httpSendOutgoingService(q);
            return;
        }
    }
    while (q->first || q->ioIndex) {
        if (q->ioIndex == 0 && buildNetVec(q) <= 0) {
            break;
        }
        /*  
            Issue a single I/O request to write all the blocks in the I/O vector
         */
        mprAssert(q->ioIndex > 0);
        written = mprWriteSocketVector(conn->sock, q->iovec, q->ioIndex);
        LOG(5, "Net connector wrote %d, written so far %Ld, q->count %d/%d", written, tx->bytesWritten, q->count, q->max);
        if (written < 0) {
            errCode = mprGetError(q);
            if (errCode == EAGAIN || errCode == EWOULDBLOCK) {
                /*  Socket full, wait for an I/O event */
                httpSocketBlocked(conn);
                break;
            }
            if (errCode != EPIPE && errCode != ECONNRESET) {
                LOG(5, "netOutgoingService write failed, error %d", errCode);
            }
            httpError(conn, HTTP_ABORT | HTTP_CODE_COMMS_ERROR, "Write error %d", errCode);
            httpConnectorComplete(conn);
            break;

        } else if (written == 0) {
            /*  Socket full, wait for an I/O event */
            httpSocketBlocked(conn);
            break;

        } else if (written > 0) {
            tx->bytesWritten += written;
            freeNetPackets(q, written);
            adjustNetVec(q, written);
        }
    }
    if (q->ioCount == 0) {
        if ((q->flags & HTTP_QUEUE_EOF)) {
            httpConnectorComplete(conn);
        } else {
            httpNotifyWritable(conn);
        }
    }
}
Example #27
0
/*
 *  Process request body data (typically post or put content). Packet will be null if the client closed the 
 *  connection to signify end of data.
 */
static bool processContent(MaConn *conn, MaPacket *packet)
{
    MaRequest       *req;
    MaResponse      *resp;
    MaQueue         *q;
    MaHost          *host;
    MprBuf          *content;
    int64           remaining;
    int             nbytes;

    req = conn->request;
    resp = conn->response;
    host = conn->host;
    q = &resp->queue[MA_QUEUE_RECEIVE];

    mprAssert(packet);
    if (packet == 0) {
        return 0;
    }
    if (conn->connectionFailed) {
        conn->state = MPR_HTTP_STATE_PROCESSING;
        maPutForService(resp->queue[MA_QUEUE_SEND].nextQ, maCreateHeaderPacket(resp), 1);
        return 1;
    }
    content = packet->content;
    if (req->flags & MA_REQ_CHUNKED) {
        if ((remaining = getChunkPacketSize(conn, content)) == 0) {
            /* Need more data or bad chunk specification */
            if (mprGetBufLength(content) > 0) {
                conn->input = packet;
            }
            return 0;
        }
    } else {
        remaining = req->remainingContent;
    }
    nbytes = (int) min(remaining, mprGetBufLength(content));
    mprAssert(nbytes >= 0);
    mprLog(conn, 7, "processContent: packet of %d bytes, remaining %Ld", mprGetBufLength(content), remaining);

    if (maShouldTrace(conn, MA_TRACE_REQUEST | MA_TRACE_BODY)) {
        maTraceContent(conn, packet, 0, 0, MA_TRACE_REQUEST | MA_TRACE_BODY);
    }
    if (nbytes > 0) {
        mprAssert(maGetPacketLength(packet) > 0);
        remaining -= nbytes;
        req->remainingContent -= nbytes;
        req->receivedContent += nbytes;

        if (req->receivedContent >= host->limits->maxBody) {
            conn->keepAliveCount = 0;
            maFailConnection(conn, MPR_HTTP_CODE_REQUEST_TOO_LARGE, 
                "Request content body is too big %Ld vs limit %Ld", 
                req->receivedContent, host->limits->maxBody);
            return 1;
        } 

        if (packet == req->headerPacket) {
            /* Preserve headers if more data to come. Otherwise handlers may free the packet and destory the headers */
            packet = maSplitPacket(resp, packet, 0);
        } else {
            mprStealBlock(resp, packet);
        }
        conn->input = 0;
        if (remaining == 0 && mprGetBufLength(packet->content) > nbytes) {
            /*
             *  Split excess data belonging to the next pipelined request.
             */
            mprLog(conn, 7, "processContent: Split packet of %d at %d", maGetPacketLength(packet), nbytes);
            conn->input = maSplitPacket(conn, packet, nbytes);
            mprAssert(mprGetParent(conn->input) == conn);
        }
        if ((q->count + maGetPacketLength(packet)) > q->max) {
            conn->keepAliveCount = 0;
            maFailConnection(q->conn, MPR_HTTP_CODE_REQUEST_TOO_LARGE, "Too much body data");
            return 1;
        }
        maPutNext(q, packet);

    } else {
        conn->input = 0;
        mprStealBlock(resp, packet);
    }
    if (req->remainingContent == 0 || conn->requestFailed) {
        /*
         *  End of input. Send a zero packet EOF signal and enable the handler send queue.
         */
        if (req->remainingContent > 0 && conn->protocol > 0 && !conn->requestFailed) {
            maFailConnection(conn, MPR_HTTP_CODE_COMMS_ERROR, "Insufficient content data sent with request");

        } else {
            maPutNext(q, maCreateEndPacket(resp));
            conn->state = MPR_HTTP_STATE_PROCESSING;
            maRunPipeline(conn);
        }
        return 1;
    }
    maServiceQueues(conn);
    return conn->input ? mprGetBufLength(conn->input->content) : 0;
}
Example #28
0
/*
 *  Get the next chunk size. Chunked data format is:
 *      Chunk spec <CRLF>
 *      Data <CRLF>
 *      Chunk spec (size == 0) <CRLF>
 *      <CRLF>
 *  Chunk spec is: "HEX_COUNT; chunk length DECIMAL_COUNT\r\n". The "; chunk length DECIMAL_COUNT is optional.
 *  As an optimization, use "\r\nSIZE ...\r\n" as the delimiter so that the CRLF after data does not special consideration.
 *  Achive this by parseHeaders reversing the input start by 2.
 */
static void incomingChunkData(MaQueue *q, MaPacket *packet)
{
    MaConn      *conn;
    MaRequest   *req;
    MprBuf      *buf;
    char        *start, *cp;
    int         bad;

    conn = q->conn;
    req = conn->request;
    buf = packet->content;

    mprAssert(req->flags & MA_REQ_CHUNKED);

    if (packet->content == 0) {
        if (req->chunkState == MA_CHUNK_DATA) {
            maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Bad chunk state");
            return;
        }
        req->chunkState = MA_CHUNK_EOF;
    }
    
    /*
     *  NOTE: the request head ensures that packets are correctly sized by packet inspection. The packet will never
     *  have more data than the chunk state expects.
     */
    switch (req->chunkState) {
    case MA_CHUNK_START:
        /*
         *  Validate:  "\r\nSIZE.*\r\n"
         */
        if (mprGetBufLength(buf) < 5) {
            break;
        }
        start = mprGetBufStart(buf);
        bad = (start[0] != '\r' || start[1] != '\n');
        for (cp = &start[2]; cp < buf->end && *cp != '\n'; cp++) {}
        if (*cp != '\n' && (cp - start) < 80) {
            break;
        }
        bad += (cp[-1] != '\r' || cp[0] != '\n');
        if (bad) {
            maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Bad chunk specification");
            return;
        }
        req->chunkSize = (int) mprAtoi(&start[2], 16);
        if (!isxdigit((int) start[2]) || req->chunkSize < 0) {
            maFailConnection(conn, MPR_HTTP_CODE_BAD_REQUEST, "Bad chunk specification");
            return;
        }
        mprAdjustBufStart(buf, (int) (cp - start + 1));
        req->remainingContent = req->chunkSize;
        if (req->chunkSize == 0) {
            req->chunkState = MA_CHUNK_EOF;
            /*
             *  We are lenient if the request does not have a trailing "\r\n" after the last chunk
             */
            cp = mprGetBufStart(buf);
            if (mprGetBufLength(buf) == 2 && *cp == '\r' && cp[1] == '\n') {
                mprAdjustBufStart(buf, 2);
            }
        } else {
            req->chunkState = MA_CHUNK_DATA;
        }
        mprAssert(mprGetBufLength(buf) == 0);
        maFreePacket(q, packet);
        mprLog(q, 5, "chunkFilter: start incoming chunk of %d bytes", req->chunkSize);
        break;

    case MA_CHUNK_DATA:
        mprAssert(maGetPacketLength(packet) <= req->chunkSize);
        mprLog(q, 5, "chunkFilter: data %d bytes, req->remainingContent %d", maGetPacketLength(packet), 
            req->remainingContent);
        maPutNext(q, packet);
        if (req->remainingContent == 0) {
            req->chunkState = MA_CHUNK_START;
            req->remainingContent = MA_BUFSIZE;
        }
        break;

    case MA_CHUNK_EOF:
        mprAssert(maGetPacketLength(packet) == 0);
        maPutNext(q, packet);
        mprLog(q, 5, "chunkFilter: last chunk");
        break;    

    default:
        mprAssert(0);
    }
}
Example #29
0
//
//	Algorithm originally in the GoAhead WebServer.
//
int MaUrl::parse(char *url)
{
	char	*tok, *cp, *portStr, *last_delim, *hostbuf, *portbuf;
	char 	*htmlExt = "html";
	int		c, len, ulen;

	mprAssert(url && *url);

	if (parsedUrlBuf) {
		mprFree(parsedUrlBuf);
	}

	ulen = strlen(url);

	//
	//	Allocate a single buffer to hold all the cracked fields.
	//	Store host, port and url strings (3 nulls).
	//
	len = ulen * 2 + MAX_PORT_LEN + 3;
	parsedUrlBuf = (char*) mprMalloc(len * sizeof(char));
	portbuf = &parsedUrlBuf[len - MAX_PORT_LEN - 1];
	hostbuf = &parsedUrlBuf[ulen+1];
	strcpy(parsedUrlBuf, url);
	url = parsedUrlBuf;

	//
	//	Defaults for missing ULR fields
	//
	strcpy(portbuf, "80");
	portStr = portbuf;
	uri = "/";
	proto = "http";
	host = "localhost";
	query = "";
	ext = htmlExt;

	if (strncmp(url, "http://", 7) == 0) {
		tok = &url[7];
		tok[-3] = '\0';
		proto = url;
		host = tok;
		for (cp = tok; *cp; cp++) {
			if (*cp == '/') {
				break;
			}
			if (*cp == ':') {
				*cp++ = '\0';
				portStr = cp;
				tok = cp;
			}
		}
		if ((cp = strchr(tok, '/')) != NULL) {
			c = *cp;
			*cp = '\0';
			mprStrcpy(hostbuf, ulen + 1, host);
			mprStrcpy(portbuf, MAX_PORT_LEN, portStr);
			*cp = c;
			host = hostbuf;
			portStr = portbuf;
			uri = cp;
			tok = cp;
		}

	} else {
		uri = url;
		tok = url;
	}

	//
	//	Split off the query string.
	//
	if ((cp = strchr(tok, '?')) != NULL) {
		*cp++ = '\0';
		query = cp;
		uri = tok;
		tok = query;
	}

	//
	//	Split off fragment identifier.
	// 
	if ((cp = strchr(tok, '#')) != NULL) {
		*cp++ = '\0';
		if (*query == 0) {
			uri = tok;
		}
	}

	//
	//	FUTURE -- this logic could be improved
	//
	if ((cp = strrchr(uri, '.')) != NULL) {
		if ((last_delim = strrchr(uri, '/')) != NULL) {
			if (last_delim > cp) {
				ext = htmlExt;
			} else {
				ext = cp + 1;
#if WIN
				mprStrLower(ext);
#endif
			}
		} else {
			ext = cp + 1;
#if WIN
			mprStrLower(ext);
#endif
		}
	} else {
		if (uri[strlen(uri) - 1] == '/') {
			ext = htmlExt;
		}
	}

	port = atoi(portStr);
	return 0;
}
Example #30
0
void maClientLock(MaClient *cp)
{
	mprAssert(cp);

	cp->lock();
}