static void readBody(HttpConn *conn, MprFile *outFile) { char buf[BIT_MAX_BUFFER]; cchar *result; ssize bytes; while (!conn->error && conn->sock && (bytes = httpRead(conn, buf, sizeof(buf))) > 0) { if (!app->noout) { result = formatOutput(conn, buf, &bytes); if (result) { mprWriteFile(outFile, result, bytes); } } #if FUTURE // This should be pushed into a range filter. // Buffer all output and then parsing can work type = httpGetHeader(conn, "Content-Type"); if (scontains(type, "multipart/byteranges")) { if ((boundary = scontains(type, "boundary=")) != 0) { boundary += 9; if (*boundary) { boundary = sfmt("--%s\r\n", boundary); } } } #endif } }
static void showOutput(HttpConn *conn, cchar *buf, ssize count) { HttpRx *rx; int i, c; rx = conn->rx; if (app->noout) { return; } if (rx->status == 401 || (conn->followRedirects && (301 <= rx->status && rx->status <= 302))) { return; } if (app->outFile == 0) { if (app->outFilename) { if ((app->outFile = mprOpenFile(app->outFilename, O_CREAT | O_WRONLY | O_TRUNC | O_TEXT, 0664)) == 0) { mprError("Can't open %s", app->outFile); return; } } else { app->outFile = mprGetStdout(); } } if (!app->printable) { mprWriteFile(app->outFile, buf, count); return; } for (i = 0; i < count; i++) { if (!isprint((uchar) buf[i]) && buf[i] != '\n' && buf[i] != '\r' && buf[i] != '\t') { app->isBinary = 1; break; } } if (!app->isBinary) { mprWriteFile(app->outFile, buf, count); return; } for (i = 0; i < count; i++) { c = (uchar) buf[i]; if (app->printable && app->isBinary) { mprFprintf(app->outFile, "%02x ", c & 0xff); } else { mprFprintf(app->outFile, "%c", (uchar) buf[i]); } } }
PUBLIC void maWriteAccessLogEntry(HttpRoute *route, cchar *buf, int len) { static int once = 0; if (mprWriteFile(route->log, (char*) buf, len) != len && once++ == 0) { mprError("Cannot write to access log %s", route->logPath); } }
/* Write data to the file function write(data: Object): Number */ PUBLIC EjsObj *writeFile(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv) { EjsArray *args; EjsByteArray *ap; EjsObj *vp; EjsString *str; cchar *buf; ssize len, written; int i; assert(argc == 1 && ejsIs(ejs, argv[0], Array)); args = (EjsArray*) argv[0]; if (!(fp->mode & EJS_FILE_WRITE)) { ejsThrowStateError(ejs, "File not opened for writing"); return 0; } written = 0; for (i = 0; i < args->length; i++) { vp = ejsGetProperty(ejs, (EjsObj*) args, i); assert(vp); switch (TYPE(vp)->sid) { case S_ByteArray: ap = (EjsByteArray*) vp; // TODO UNICODE ENCODING buf = (cchar*) &ap->value[ap->readPosition]; len = ap->writePosition - ap->readPosition; break; case S_String: // UNICODE #if UNICODE && FUTURE buf = awtom(((EjsString*) vp)->value, &len); #else buf = ((EjsString*) vp)->value; len = ((EjsString*) vp)->length; #endif break; default: str = ejsToString(ejs, vp); buf = awtom(((EjsString*) str)->value, &len); break; } if (mprWriteFile(fp->file, buf, len) != len) { ejsThrowIOError(ejs, "Cannot write to %s", fp->path); return 0; } written += len; /* Use GC to free buf as it may not be allocated */ } return (EjsObj*) ejsCreateNumber(ejs, (MprNumber) written); }
static EjsObj *saveXml(Ejs *ejs, EjsXML *xml, int argc, EjsObj **argv) { MprBuf *buf; MprFile *file; char *filename; ssize bytes, len; if (argc != 1 || !ejsIs(ejs, argv[0], String)) { ejsThrowArgError(ejs, "Bad args. Usage: save(filename);"); return 0; } filename = awtom(((EjsString*) argv[0])->value, NULL); /* Create a buffer to hold the output. All in memory. */ buf = mprCreateBuf(ME_MAX_BUFFER, -1); mprPutStringToBuf(buf, "<?xml version=\"1.0\"?>\n"); if (ejsXMLToBuf(ejs, buf, xml, 0) < 0) { return 0; } file = mprOpenFile(filename, O_CREAT | O_TRUNC | O_WRONLY | O_TEXT, 0664); if (file == 0) { ejsThrowIOError(ejs, "Cannot open: %s, %d", filename, mprGetOsError(ejs)); return 0; } len = mprGetBufLength(buf); bytes = mprWriteFile(file, buf->start, len); if (bytes != len) { ejsThrowIOError(ejs, "Cannot write to: %s", filename); mprCloseFile(file); return 0; } mprWriteFile(file, "\n", 1); mprCloseFile(file); return 0; }
static void readBody(HttpConn *conn, MprFile *outFile) { char buf[ME_MAX_BUFFER]; cchar *result; ssize bytes; while (!conn->error && (bytes = httpRead(conn, buf, sizeof(buf))) > 0) { if (!app->noout) { result = formatOutput(conn, buf, &bytes); if (result) { mprWriteFile(outFile, result, bytes); } } } }
/* Put a character to the file. This will put the file into buffered mode. */ PUBLIC ssize mprPutFileChar(MprFile *file, int c) { assert(file); if (file == 0) { return -1; } if (file->buf) { if (mprPutCharToBuf(file->buf, c) != 1) { return MPR_ERR_CANT_WRITE; } file->pos++; return 1; } return mprWriteFile(file, &c, 1); }
/* The incoming callback is invoked to receive body data */ static void incomingFile(HttpQueue *q, HttpPacket *packet) { HttpConn *conn; HttpTx *tx; HttpRx *rx; HttpRange *range; MprBuf *buf; MprFile *file; ssize len; conn = q->conn; tx = conn->tx; rx = conn->rx; file = (MprFile*) q->queueData; if (file == 0) { /* Not a PUT so just ignore the incoming data. */ return; } if (httpGetPacketLength(packet) == 0) { /* End of input */ if (file) { mprCloseFile(file); } q->queueData = 0; if (!tx->etag) { /* Set the etag for caching in the client */ mprGetPathInfo(tx->filename, &tx->fileInfo); tx->etag = sfmt("\"%llx-%llx-%llx\"", tx->fileInfo.inode, tx->fileInfo.size, tx->fileInfo.mtime); } return; } buf = packet->content; len = mprGetBufLength(buf); assert(len > 0); range = rx->inputRange; if (range && mprSeekFile(file, SEEK_SET, range->start) != range->start) { httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot seek to range start to %lld", range->start); } else if (mprWriteFile(file, mprGetBufStart(buf), len) != len) { httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot PUT to %s", tx->filename); } }
/* uncompress(src: Path, dest: Path = null) */ static EjsObj *zlib_uncompress(Ejs *ejs, EjsObj *unused, int argc, EjsObj **argv) { MprFile *out; gzFile in; cchar *src, *dest; uchar inbuf[MPR_BUFSIZE]; ssize nbytes; src = ((EjsPath*) argv[0])->value; dest = (argc >= 2) ? ejsToMulti(ejs, argv[1]) : 0; if (!dest) { dest = sjoin(src, ".gz", NULL); } if ((in = gzopen(src, "rb")) == 0) { ejsThrowIOError(ejs, "Cannot open from %s", src); return 0; } if ((out = mprOpenFile(dest, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644)) == 0) { ejsThrowIOError(ejs, "Cannot open destination %s", dest); return 0; } while (1) { if ((nbytes = gzread(in, inbuf, sizeof(inbuf))) < 0) { ejsThrowIOError(ejs, "Cannot read from %s", src); return 0; } else if (nbytes == 0) { break; } if (mprWriteFile(out, inbuf, (int) nbytes) != nbytes) { ejsThrowIOError(ejs, "Cannot write to %s", dest); return 0; } } mprCloseFile(out); gzclose(in); return 0; }
static int writeToFile(HttpQueue *q, char *data, ssize len) { HttpConn *conn; HttpUploadFile *file; HttpLimits *limits; Upload *up; ssize rc; conn = q->conn; limits = conn->limits; up = q->queueData; file = up->currentFile; if ((file->size + len) > limits->uploadSize) { /* Abort the connection as we don't want the load of receiving the entire body */ httpLimitError(conn, HTTP_ABORT | HTTP_CODE_REQUEST_TOO_LARGE, "Uploaded file exceeds maximum %lld", limits->uploadSize); return MPR_ERR_CANT_WRITE; } if (len > 0) { /* File upload. Write the file data. */ rc = mprWriteFile(up->file, data, len); if (rc != len) { httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot write to upload temp file %s, rc %zd, errno %d", up->tmpPath, rc, mprGetOsError()); return MPR_ERR_CANT_WRITE; } file->size += len; conn->rx->bytesUploaded += len; } 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)); }
/* Compile a view or controller cacheName MD5 cache name (not a full path) source ESP source file name module Module file name */ bool espCompile(HttpConn *conn, cchar *source, cchar *module, cchar *cacheName, int isView) { MprFile *fp; HttpRx *rx; HttpRoute *route; EspRoute *eroute; cchar *csource; char *layout, *script, *page, *err; ssize len; rx = conn->rx; route = rx->route; eroute = route->eroute; layout = 0; if (isView) { if ((page = mprReadPathContents(source, &len)) == 0) { httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR, "Can't read %s", source); return 0; } /* Use layouts iff there is a source defined on the route. Only MVC/controllers based apps do this. */ if (eroute->layoutsDir) { #if UNUSED layout = mprSamePath(eroute->layoutsDir, route->dir) ? 0 : mprJoinPath(eroute->layoutsDir, "default.esp"); #else layout = mprJoinPath(eroute->layoutsDir, "default.esp"); #endif } if ((script = espBuildScript(route, page, source, cacheName, layout, &err)) == 0) { httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR, "Can't build %s, error %s", source, err); return 0; } csource = mprJoinPathExt(mprTrimPathExt(module), ".c"); if ((fp = mprOpenFile(csource, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0664)) == 0) { httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR, "Can't open compiled script file %s", csource); return 0; } len = slen(script); if (mprWriteFile(fp, script, len) != len) { httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR, "Can't write compiled script file %s", csource); mprCloseFile(fp); return 0; } mprCloseFile(fp); } else { csource = source; } mprMakeDir(eroute->cacheDir, 0775, -1, -1, 1); /* WARNING: GC yield here */ if (runCommand(conn, eroute->compile, csource, module) < 0) { return 0; } if (eroute->link) { /* WARNING: GC yield here */ if (runCommand(conn, eroute->link, csource, module) < 0) { return 0; } #if !(BLD_DEBUG && MACOSX) /* MAC needs the object for debug information */ mprDeletePath(mprJoinPathExt(mprTrimPathExt(module), BLD_OBJ)); #endif } #if BLD_WIN_LIKE { /* Windows leaves intermediate object in the current directory */ cchar *obj; obj = mprReplacePathExt(mprGetPathBase(csource), BLD_OBJ); if (mprPathExists(obj, F_OK)) { mprDeletePath(obj); } } #endif if (!eroute->keepSource && isView) { mprDeletePath(csource); } return 1; }
PUBLIC ssize mprWriteFileString(MprFile *file, cchar *str) { return mprWriteFile(file, str, slen(str)); }