/* Parse the cert info and write properties to the buffer. Modifies the info argument. */ static void parseCertFields(MprBuf *buf, char *info) { char c, *cp, *term, *key, *value; if (info) { key = 0; term = cp = info; do { c = *cp; if (c == '/' || c == '\0') { *cp = '\0'; key = ssplit(term, "=", &value); if (smatch(key, "emailAddress")) { key = "email"; } mprPutToBuf(buf, "\"%s\":\"%s\",", key, value); term = &cp[1]; *cp = c; } } while (*cp++ != '\0'); if (key) { mprAdjustBufEnd(buf, -1); } } }
PUBLIC int httpApplyUserGroup() { #if ME_UNIX_LIKE Http *http; http = HTTP; if (http->userChanged || http->groupChanged) { if (!smatch(MPR->logPath, "stdout") && !smatch(MPR->logPath, "stderr")) { if (chown(MPR->logPath, http->uid, http->gid) < 0) { mprLog("critical http", 0, "Cannot change ownership on %s", MPR->logPath); } } } if (httpApplyChangedGroup() < 0 || httpApplyChangedUser() < 0) { return MPR_ERR_CANT_COMPLETE; } if (http->userChanged || http->groupChanged) { struct group *gp; gid_t glist[64], gid; MprBuf *gbuf = mprCreateBuf(0, 0); cchar *groups; int i, ngroup; gid = getgid(); ngroup = getgroups(sizeof(glist) / sizeof(gid_t), glist); if (ngroup > 1) { mprPutStringToBuf(gbuf, ", groups: "); for (i = 0; i < ngroup; i++) { if (glist[i] == gid) continue; if ((gp = getgrgid(glist[i])) != 0) { mprPutToBuf(gbuf, "%s (%d) ", gp->gr_name, glist[i]); } else { mprPutToBuf(gbuf, "(%d) ", glist[i]); } } } groups = mprGetBufStart(gbuf); mprLog("info http", 2, "Running as user \"%s\" (%d), group \"%s\" (%d)%s", http->user, http->uid, http->group, http->gid, groups); } #endif return 0; }
/* Create a final range packet that follows all the data */ static HttpPacket *createFinalRangePacket(HttpStream *stream) { HttpPacket *packet; HttpTx *tx; tx = stream->tx; packet = httpCreatePacket(HTTP_RANGE_BUFSIZE); packet->flags |= HTTP_PACKET_RANGE | HTTP_PACKET_DATA; mprPutToBuf(packet->content, "\r\n--%s--\r\n", tx->rangeBoundary); return packet; }
/* Get the SSL state of the socket in a buffer */ static char *getOssState(MprSocket *sp) { OpenSocket *osp; MprBuf *buf; X509_NAME *xSubject; X509 *cert; char *prefix, subject[512], issuer[512], peer[512]; osp = sp->sslSocket; buf = mprCreateBuf(0, 0); mprPutToBuf(buf, "PROVIDER=openssl,CIPHER=%s,SESSION=%s,", SSL_get_cipher(osp->handle), sp->session); if ((cert = SSL_get_peer_certificate(osp->handle)) == 0) { mprPutToBuf(buf, "%s=\"none\",", sp->acceptIp ? "CLIENT_CERT" : "SERVER_CERT"); } else { xSubject = X509_get_subject_name(cert); X509_NAME_get_text_by_NID(xSubject, NID_commonName, peer, sizeof(peer) - 1); mprPutToBuf(buf, "PEER=\"%s\",", peer); prefix = sp->acceptIp ? "CLIENT_" : "SERVER_"; X509_NAME_oneline(X509_get_subject_name(cert), subject, sizeof(subject) -1); parseCertFields(buf, prefix, "S_", &subject[1]); X509_NAME_oneline(X509_get_issuer_name(cert), issuer, sizeof(issuer) -1); parseCertFields(buf, prefix, "I_", &issuer[1]); X509_free(cert); } if ((cert = SSL_get_certificate(osp->handle)) != 0) { prefix = sp->acceptIp ? "SERVER_" : "CLIENT_"; X509_NAME_oneline(X509_get_subject_name(cert), subject, sizeof(subject) -1); parseCertFields(buf, prefix, "S_", &subject[1]); X509_NAME_oneline(X509_get_issuer_name(cert), issuer, sizeof(issuer) -1); parseCertFields(buf, prefix, "I_", &issuer[1]); /* Don't call X509_free on own cert */ } return mprGetBufStart(buf); }
/* Map iana names to OpenSSL names so users can provide IANA names as well as OpenSSL cipher names */ static cchar *mapCipherNames(cchar *ciphers) { MprBuf *buf; CipherMap *cp; char *cipher, *next; if (!ciphers || *ciphers == 0) { return 0; } buf = mprCreateBuf(0, 0); for (next = sclone(ciphers); (cipher = stok(next, ":, \t", &next)) != 0; ) { for (cp = cipherMap; cp->name; cp++) { if (smatch(cp->name, cipher)) { mprPutToBuf(buf, "%s:", cp->ossName); break; } } if (cp->name == 0) { mprPutToBuf(buf, "%s:", cipher); } } return mprBufToString(buf); }
/* 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); }
PUBLIC cchar *sjoinArgs(int argc, cchar **argv, cchar *sep) { MprBuf *buf; int i; if (sep == 0) { sep = ""; } buf = mprCreateBuf(0, 0); for (i = 0; i < argc; i++) { mprPutToBuf(buf, "%s%s", argv[i], sep); } if (argc > 0) { mprAdjustBufEnd(buf, -1); } return mprBufToString(buf); }
/* Create a range boundary packet */ static HttpPacket *createRangePacket(HttpStream *stream, HttpRange *range) { HttpPacket *packet; HttpTx *tx; char *length; tx = stream->tx; length = (tx->entityLength >= 0) ? itos(tx->entityLength) : "*"; packet = httpCreatePacket(HTTP_RANGE_BUFSIZE); packet->flags |= HTTP_PACKET_RANGE | HTTP_PACKET_DATA; mprPutToBuf(packet->content, "\r\n--%s\r\n" "Content-Range: bytes %lld-%lld/%s\r\n\r\n", tx->rangeBoundary, range->start, range->end - 1, length); return packet; }
/* Prepare form data as a series of key-value pairs. Data is formatted according to www-url-encoded specs by mprSetHttpFormData. Objects are flattened into a one level key/value pairs. Keys can have embedded "." separators. E.g. name=value&address=77%20Park%20Lane */ static void prepForm(Ejs *ejs, EjsHttp *hp, cchar *prefix, EjsObj *data) { EjsName qname; EjsObj *vp; EjsString *value; cchar *key, *sep, *vstr; char *encodedKey, *encodedValue, *newPrefix, *newKey; int i, count; count = ejsGetLength(ejs, data); for (i = 0; i < count; i++) { if (ejsIs(ejs, data, Array)) { key = itos(i); } else { qname = ejsGetPropertyName(ejs, data, i); key = ejsToMulti(ejs, qname.name); } vp = ejsGetProperty(ejs, data, i); if (vp == 0) { continue; } if (ejsGetLength(ejs, vp) > 0) { if (prefix) { newPrefix = sfmt("%s.%s", prefix, key); prepForm(ejs, hp, newPrefix, vp); } else { prepForm(ejs, hp, key, vp); } } else { value = ejsToString(ejs, vp); sep = (mprGetBufLength(hp->requestContent) > 0) ? "&" : ""; if (prefix) { newKey = sjoin(prefix, ".", key, NULL); encodedKey = mprUriEncode(newKey, MPR_ENCODE_URI_COMPONENT); } else { encodedKey = mprUriEncode(key, MPR_ENCODE_URI_COMPONENT); } vstr = ejsToMulti(ejs, value); encodedValue = mprUriEncode(vstr, MPR_ENCODE_URI_COMPONENT); mprPutToBuf(hp->requestContent, "%s%s=%s", sep, encodedKey, encodedValue); } } }
/* Prepare form data using json encoding. The objects are json encoded then URI encoded to be safe. */ static void prepForm(Ejs *ejs, EjsHttp *hp, char *prefix, EjsObj *data) { EjsName qname; EjsObj *vp; EjsString *value; cchar *key, *sep; char *encodedKey, *encodedValue, *newPrefix, *newKey; int i, count; jdata = ejsToJSON(ejs, data, NULL); if (prefix) { newKey = sjoin(prefix, ".", key, NULL); encodedKey = mprUriEncode(newKey, MPR_ENCODE_URI_COMPONENT); } else { encodedKey = mprUriEncode(key, MPR_ENCODE_URI_COMPONENT); } encodedValue = mprUriEncode(value->value, MPR_ENCODE_URI_COMPONENT); mprPutToBuf(hp->requestContent, "%s%s=%s", sep, encodedKey, encodedValue); }
/* Parse the cert info and write properties to the buffer. Modifies the info argument. */ static void parseCertFields(MprBuf *buf, char *prefix, char *prefix2, char *info) { char c, *cp, *term, *key, *value; if (info) { term = cp = info; do { c = *cp; if (c == '/' || c == '\0') { *cp = '\0'; key = ssplit(term, "=", &value); if (smatch(key, "emailAddress")) { key = "EMAIL"; } mprPutToBuf(buf, "%s%s%s=%s,", prefix, prefix2, key, value); term = &cp[1]; *cp = c; } } while (*cp++ != '\0'); } }
static char *getOssSession(MprSocket *sp) { SSL_SESSION *sess; OpenSocket *osp; MprBuf *buf; int i; osp = sp->sslSocket; if ((sess = SSL_get0_session(osp->handle)) != 0) { if (sess->session_id_length == 0 && osp->handle->tlsext_ticket_expected) { return sclone("ticket"); } buf = mprCreateBuf((sess->session_id_length * 2) + 1, 0); assert(buf->start); for (i = 0; i < (int) sess->session_id_length; i++) { mprPutToBuf(buf, "%02X", (uchar) sess->session_id[i]); } return mprBufToString(buf); } return 0; }
static EjsString *serialize(Ejs *ejs, EjsAny *vp, Json *json) { EjsName qname; EjsFunction *fn; EjsString *result, *sv; EjsTrait *trait; EjsObj *pp, *obj, *replacerArgs[2]; wchar *cp; cchar *key; int c, isArray, i, count, slotNum, quotes; /* The main code below can handle Arrays, Objects, objects derrived from Object and also native classes with properties. All others just use toString. */ count = ejsIsPot(ejs, vp) ? ejsGetLength(ejs, vp) : 0; if (count == 0 && TYPE(vp) != ESV(Object) && TYPE(vp) != ESV(Array)) { // OPT - need some flag for this test. if (!ejsIsDefined(ejs, vp) || ejsIs(ejs, vp, Boolean) || ejsIs(ejs, vp, Number)) { return ejsToString(ejs, vp); } else if (json->regexp) { return ejsToString(ejs, vp); } else { return ejsToLiteralString(ejs, vp); } } obj = vp; json->nest++; if (json->buf == 0) { json->buf = mprCreateBuf(0, 0); mprAddRoot(json->buf); } isArray = ejsIs(ejs, vp, Array); mprPutCharToWideBuf(json->buf, isArray ? '[' : '{'); if (json->pretty) { mprPutCharToWideBuf(json->buf, '\n'); } if (++ejs->serializeDepth <= json->depth && !VISITED(obj)) { SET_VISITED(obj, 1); for (slotNum = 0; slotNum < count && !ejs->exception; slotNum++) { trait = ejsGetPropertyTraits(ejs, obj, slotNum); if (trait && (trait->attributes & (EJS_TRAIT_HIDDEN | EJS_TRAIT_DELETED | EJS_FUN_INITIALIZER | EJS_FUN_MODULE_INITIALIZER)) && !json->hidden) { continue; } pp = ejsGetProperty(ejs, obj, slotNum); if (ejs->exception) { SET_VISITED(obj, 0); json->nest--; return 0; } if (pp == 0) { continue; } if (isArray) { key = itos(slotNum); qname.name = ejsCreateStringFromAsc(ejs, key); qname.space = ESV(empty); } else { qname = ejsGetPropertyName(ejs, vp, slotNum); } quotes = json->quotes; if (!quotes) { // UNICODE for (cp = qname.name->value; cp < &qname.name->value[qname.name->length]; cp++) { if (!isalnum((uchar) *cp) && *cp != '_') { quotes = 1; break; } } } if (json->pretty) { for (i = 0; i < ejs->serializeDepth; i++) { mprPutStringToWideBuf(json->buf, json->indent); } } if (!isArray) { if (json->namespaces) { if (qname.space != ESV(empty)) { mprPutToBuf(json->buf, "\"%@\"::", qname.space); } } if (quotes) { mprPutCharToWideBuf(json->buf, '"'); } for (cp = qname.name->value; cp && *cp; cp++) { c = *cp; if (c == '"' || c == '\\') { mprPutCharToWideBuf(json->buf, '\\'); mprPutCharToWideBuf(json->buf, c); } else { mprPutCharToWideBuf(json->buf, c); } } if (quotes) { mprPutCharToWideBuf(json->buf, '"'); } mprPutCharToWideBuf(json->buf, ':'); if (json->pretty) { mprPutCharToWideBuf(json->buf, ' '); } } fn = (EjsFunction*) ejsGetPropertyByName(ejs, TYPE(pp)->prototype, N(NULL, "toJSON")); // OPT - check that this is going directly to serialize most of the time if (!ejsIsFunction(ejs, fn) || (fn->isNativeProc && fn->body.proc == (EjsProc) ejsObjToJSON)) { sv = serialize(ejs, pp, json); } else { sv = (EjsString*) ejsRunFunction(ejs, fn, pp, 1, &json->options); } if (sv == 0 || !ejsIs(ejs, sv, String)) { if (ejs->exception) { ejsThrowTypeError(ejs, "Cannot serialize property %@", qname.name); SET_VISITED(obj, 0); return 0; } } else { if (json->replacer) { replacerArgs[0] = (EjsObj*) qname.name; replacerArgs[1] = (EjsObj*) sv; /* function replacer(key: String, value: String): String */ sv = ejsRunFunction(ejs, json->replacer, obj, 2, (EjsObj**) replacerArgs); } mprPutBlockToBuf(json->buf, sv->value, sv->length * sizeof(wchar)); } if ((slotNum + 1) < count || json->commas) { mprPutCharToWideBuf(json->buf, ','); } if (json->pretty) { mprPutCharToWideBuf(json->buf, '\n'); } } SET_VISITED(obj, 0); } --ejs->serializeDepth; if (json->pretty) { for (i = ejs->serializeDepth; i > 0; i--) { mprPutStringToWideBuf(json->buf, json->indent); } } mprPutCharToWideBuf(json->buf, isArray ? ']' : '}'); mprAddNullToWideBuf(json->buf); if (--json->nest == 0) { result = ejsCreateString(ejs, mprGetBufStart(json->buf), mprGetBufLength(json->buf) / sizeof(wchar)); mprRemoveRoot(json->buf); } else { result = 0; } return result; }
PUBLIC void httpWriteHeaders(HttpQueue *q, HttpPacket *packet) { Http *http; HttpConn *conn; HttpTx *tx; HttpUri *parsedUri; MprKey *kp; MprBuf *buf; int level; assert(packet->flags == HTTP_PACKET_HEADER); conn = q->conn; http = conn->http; tx = conn->tx; buf = packet->content; if (tx->flags & HTTP_TX_HEADERS_CREATED) { return; } tx->flags |= HTTP_TX_HEADERS_CREATED; tx->responded = 1; if (conn->headersCallback) { /* Must be before headers below */ (conn->headersCallback)(conn->headersCallbackArg); } if (tx->flags & HTTP_TX_USE_OWN_HEADERS && !conn->error) { conn->keepAliveCount = 0; return; } setHeaders(conn, packet); if (conn->endpoint) { mprPutStringToBuf(buf, conn->protocol); mprPutCharToBuf(buf, ' '); mprPutIntToBuf(buf, tx->status); mprPutCharToBuf(buf, ' '); mprPutStringToBuf(buf, httpLookupStatus(http, tx->status)); } else { mprPutStringToBuf(buf, tx->method); mprPutCharToBuf(buf, ' '); parsedUri = tx->parsedUri; if (http->proxyHost && *http->proxyHost) { if (parsedUri->query && *parsedUri->query) { mprPutToBuf(buf, "http://%s:%d%s?%s %s", http->proxyHost, http->proxyPort, parsedUri->path, parsedUri->query, conn->protocol); } else { mprPutToBuf(buf, "http://%s:%d%s %s", http->proxyHost, http->proxyPort, parsedUri->path, conn->protocol); } } else { if (parsedUri->query && *parsedUri->query) { mprPutToBuf(buf, "%s?%s %s", parsedUri->path, parsedUri->query, conn->protocol); } else { mprPutStringToBuf(buf, parsedUri->path); mprPutCharToBuf(buf, ' '); mprPutStringToBuf(buf, conn->protocol); } } } if ((level = httpShouldTrace(conn, HTTP_TRACE_TX, HTTP_TRACE_FIRST, tx->ext)) >= mprGetLogLevel(tx)) { mprAddNullToBuf(buf); mprLog(level, " %s", mprGetBufStart(buf)); } mprPutStringToBuf(buf, "\r\n"); /* Output headers */ kp = mprGetFirstKey(conn->tx->headers); while (kp) { mprPutStringToBuf(packet->content, kp->key); mprPutStringToBuf(packet->content, ": "); if (kp->data) { mprPutStringToBuf(packet->content, kp->data); } mprPutStringToBuf(packet->content, "\r\n"); kp = mprGetNextKey(conn->tx->headers, kp); } /* By omitting the "\r\n" delimiter after the headers, chunks can emit "\r\nSize\r\n" as a single chunk delimiter */ if (tx->length >= 0 || tx->chunkSize <= 0) { mprPutStringToBuf(buf, "\r\n"); } if (tx->altBody) { /* Error responses are emitted here */ mprPutStringToBuf(buf, tx->altBody); httpDiscardQueueData(tx->queue[HTTP_QUEUE_TX]->nextQ, 0); } tx->headerSize = mprGetBufLength(buf); tx->flags |= HTTP_TX_HEADERS_CREATED; q->count += httpGetPacketLength(packet); }
/* Get the SSL state of the socket in a buffer */ static char *getOssState(MprSocket *sp) { OpenSocket *osp; MprBuf *buf; X509 *cert; char subject[512], issuer[512]; osp = sp->sslSocket; buf = mprCreateBuf(0, 0); mprPutToBuf(buf, "{\"provider\":\"openssl\",\"cipher\":\"%s\",\"session\":\"%s\",", SSL_get_cipher(osp->handle), sp->session); mprPutToBuf(buf, "\"peer\":\"%s\",", sp->peerName); mprPutToBuf(buf, "\"%s\":{", sp->acceptIp ? "client" : "server"); if ((cert = SSL_get_peer_certificate(osp->handle)) != 0) { X509_NAME_oneline(X509_get_issuer_name(cert), issuer, sizeof(issuer) -1); mprPutToBuf(buf, "\"issuer\": {"); parseCertFields(buf, &issuer[1]); mprPutToBuf(buf, "},"); X509_NAME_oneline(X509_get_subject_name(cert), subject, sizeof(subject) -1); mprPutToBuf(buf, "\"subject\": {"); parseCertFields(buf, &subject[1]); mprPutToBuf(buf, "},"); X509_free(cert); } if ((cert = SSL_get_certificate(osp->handle)) != 0) { mprPutToBuf(buf, "\"issuer\": {"); X509_NAME_oneline(X509_get_issuer_name(cert), issuer, sizeof(issuer) -1); parseCertFields(buf, &issuer[1]); mprPutToBuf(buf, "},"); mprPutToBuf(buf, "\"subject\": {"); X509_NAME_oneline(X509_get_subject_name(cert), subject, sizeof(subject) -1); parseCertFields(buf, &subject[1]); mprPutToBuf(buf, "},"); /* Don't call X509_free on own cert */ } mprAdjustBufEnd(buf, -1); mprPutToBuf(buf, "}}"); return mprBufToString(buf); }
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)); }
/* Process the content data. Returns < 0 on error == 0 when more data is needed == 1 when data successfully written */ static int processUploadData(HttpQueue *q) { HttpConn *conn; HttpPacket *packet; MprBuf *content; Upload *up; ssize size, dataLen; bool pureData; char *data, *bp, *key; conn = q->conn; up = q->queueData; content = q->first->content; packet = 0; size = mprGetBufLength(content); if (size < up->boundaryLen) { /* Incomplete boundary. Return and get more data */ return 0; } bp = getBoundary(mprGetBufStart(content), size, up->boundary, up->boundaryLen, &pureData); if (bp == 0) { if (up->clientFilename) { /* No signature found yet. probably more data to come. Must handle split boundaries. */ data = mprGetBufStart(content); dataLen = pureData ? size : (size - (up->boundaryLen - 1)); if (dataLen > 0) { if (writeToFile(q, mprGetBufStart(content), dataLen) < 0) { return MPR_ERR_CANT_WRITE; } } mprAdjustBufStart(content, dataLen); return 0; /* Get more data */ } } data = mprGetBufStart(content); dataLen = (bp) ? (bp - data) : mprGetBufLength(content); if (dataLen > 0) { mprAdjustBufStart(content, dataLen); /* This is the CRLF before the boundary */ if (dataLen >= 2 && data[dataLen - 2] == '\r' && data[dataLen - 1] == '\n') { dataLen -= 2; } if (up->clientFilename) { /* Write the last bit of file data and add to the list of files and define environment variables */ if (writeToFile(q, data, dataLen) < 0) { return MPR_ERR_CANT_WRITE; } defineFileFields(q, up); } else { /* Normal string form data variables */ data[dataLen] = '\0'; #if KEEP httpTrace(conn, "request.upload.variables", "context", "'%s':'%s'", up->name, data); #endif key = mprUriDecode(up->name); data = mprUriDecode(data); httpSetParam(conn, key, data); if (packet == 0) { packet = httpCreatePacket(ME_MAX_BUFFER); } if (httpGetPacketLength(packet) > 0) { /* Need to add www-form-urlencoding separators */ mprPutCharToBuf(packet->content, '&'); } else { conn->rx->mimeType = sclone("application/x-www-form-urlencoded"); } mprPutToBuf(packet->content, "%s=%s", up->name, data); } } if (up->clientFilename) { /* Now have all the data (we've seen the boundary) */ mprCloseFile(up->file); up->file = 0; up->clientFilename = 0; } if (packet) { httpPutPacketToNext(q, packet); } up->contentState = HTTP_UPLOAD_BOUNDARY; return 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)); }