示例#1
0
/*  
    Populate a packet with file data. Return the number of bytes read or a negative error code. Will not return with
    a short read.
 */
static ssize readFileData(HttpQueue *q, HttpPacket *packet, MprOff pos, ssize size)
{
    HttpConn    *conn;
    HttpTx      *tx;
    ssize       nbytes;
//	int btint = 0;
    conn = q->conn;
    tx = conn->tx;

    if (packet->content == 0 && (packet->content = mprCreateBuf(size, -1)) == 0) {
        return MPR_ERR_MEMORY;
    }
    assure(size <= mprGetBufSpace(packet->content));    
    mprLog(7, "readFileData size %d, pos %Ld", size, pos);

    if (pos >= 0) {
        mprSeekFile(tx->file, SEEK_SET, pos);
    }
    if ((nbytes = mprReadFile(tx->file, mprGetBufStart(packet->content), size)) != size) {
        /*  
            As we may have sent some data already to the client, the only thing we can do is abort and hope the client 
            notices the short data.
         */
        httpError(conn, HTTP_CODE_SERVICE_UNAVAILABLE, "Can't read file %s", tx->filename);
        return MPR_ERR_CANT_READ;
    }
    mprAdjustBufEnd(packet->content, nbytes);
    packet->esize -= nbytes;
    assure(packet->esize == 0);
    return nbytes;
}
示例#2
0
文件: client.c 项目: BIDXOM/http-2
static int blockingFileCopy(HttpConn *conn, cchar *path)
{
    MprFile     *file;
    char        buf[ME_MAX_BUFFER];
    ssize       bytes, nbytes, offset;

    file = mprOpenFile(path, O_RDONLY | O_BINARY, 0);
    if (file == 0) {
        mprLog("error http client", 0, "Cannot open %s", path);
        return MPR_ERR_CANT_OPEN;
    }
    mprAddRoot(file);
    while ((bytes = mprReadFile(file, buf, sizeof(buf))) > 0) {
        offset = 0;
        while (bytes > 0) {
            if ((nbytes = httpWriteBlock(conn->writeq, &buf[offset], bytes, HTTP_BLOCK)) < 0) {
                mprCloseFile(file);
                mprRemoveRoot(file);
                return MPR_ERR_CANT_WRITE;
            }
            bytes -= nbytes;
            offset += nbytes;
            assert(bytes >= 0);
        }
    }
    httpFlushQueue(conn->writeq, HTTP_BLOCK);
    mprCloseFile(file);
    mprRemoveRoot(file);
    return 0;
}
示例#3
0
文件: ecLex.c 项目: liexusong/ejs-2
PUBLIC int ecOpenFileStream(EcCompiler *cp, cchar *path)
{
    EcFileStream    *fs;
    MprPath         info;
    char            *contents;

    if ((fs = ecCreateStream(cp, sizeof(EcFileStream), path, manageFileStream)) == 0) {
        return MPR_ERR_MEMORY;
    }
    if ((fs->file = mprOpenFile(path, O_RDONLY | O_BINARY, 0666)) == 0) {
        return MPR_ERR_CANT_OPEN;
    }
    if (mprGetPathInfo(path, &info) < 0 || info.size < 0) {
        mprCloseFile(fs->file);
        return MPR_ERR_CANT_ACCESS;
    }
    if ((contents = mprAlloc((int) info.size + 1)) == 0) {
        mprCloseFile(fs->file);
        return MPR_ERR_MEMORY;
    }
    if (mprReadFile(fs->file, contents, (int) info.size) != (int) info.size) {
        mprCloseFile(fs->file);
        return MPR_ERR_CANT_READ;
    }
    contents[info.size] = '\0';
    ecSetStreamBuf((EcStream*) fs, contents, (ssize) info.size);
    mprCloseFile(fs->file);
    fs->file = 0;
    return 0;
}
示例#4
0
文件: client.c 项目: ni-webtech/http
static int blockingFileCopy(HttpConn *conn, cchar *path)
{
    MprFile     *file;
    char        buf[MPR_BUFSIZE];
    ssize       bytes, nbytes, offset;
    int         oldMode;

    file = mprOpenFile(path, O_RDONLY | O_BINARY, 0);
    if (file == 0) {
        mprError("Can't open %s", path);
        return MPR_ERR_CANT_OPEN;
    }
    mprAddRoot(file);
    oldMode = mprSetSocketBlockingMode(conn->sock, 1);
    while ((bytes = mprReadFile(file, buf, sizeof(buf))) > 0) {
        offset = 0;
        while (bytes > 0) {
            if ((nbytes = httpWriteBlock(conn->writeq, &buf[offset], bytes)) < 0) {
                mprCloseFile(file);
                mprRemoveRoot(file);
                return MPR_ERR_CANT_WRITE;
            }
            bytes -= nbytes;
            offset += nbytes;
            mprAssert(bytes >= 0);
        }
        mprYield(0);
    }
    httpFlushQueue(conn->writeq, 1);
    mprSetSocketBlockingMode(conn->sock, oldMode);
    mprCloseFile(file);
    mprRemoveRoot(file);
    return 0;
}
示例#5
0
static ssize readFileData(MprXml *xp, void *data, char *buf, ssize size)
{
    assert(xp);
    assert(data);
    assert(buf);
    assert(size > 0);

    return mprReadFile((MprFile*) data, buf, size);
}
示例#6
0
文件: output.c 项目: WeiY/appweb-4
/*
    Event callback. Invoked for incoming web socket messages and other events of interest.
    We're interested in the WRITABLE event.
 */
static void output_callback(HttpConn *conn, int event, int arg)
{
    Output      *output;
    ssize       len, wrote;
    int         flags, type;
    char        buf[MPR_BUFSIZE];

    /*
        Get a writable event when the socket can absorb more data
     */
    if (event == HTTP_EVENT_WRITABLE) {
        output = getData();
        do {
            if ((len = mprReadFile(output->file, buf, sizeof(buf))) > 0) {

                /*
                    Set the HTTP_MORE flag on every write except the last. This means each write is sent as
                    a separate frame. The first frame has the type of WS_MSG_TEXT, all others must be 
                    continuation frames.
                 */
                flags = HTTP_NON_BLOCK;
                if ((output->written + len) < output->info.size) {
                    flags |= HTTP_MORE;
                }
                type = output->written == 0 ? WS_MSG_TEXT : WS_MSG_CONT;
                /*
                    Send the next chunk as a WebSockets frame using a non-blocking write. 
                    This may return having written only a portion of the requested data.
                 */
                if ((wrote = httpSendBlock(conn, type, buf, len, flags)) < 0) {
                    httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot send message of %d bytes", len);
                    return;
                }
                output->written += wrote;
                if (wrote < len) {
                    /* Reposition if the send returned having written less than requested */
                    mprSeekFile(output->file, SEEK_CUR, wrote - len);
                    break;
                }
            } else {
                httpSendClose(conn, WS_STATUS_OK, "OK");
                break;
            }
        } while (len > 0);

    } else if (event == HTTP_EVENT_APP_CLOSE) {
        mprLog(0, "output.c: close event. Status status %d, orderly closed %d, reason %s", arg,
        httpWebSocketOrderlyClosed(conn), httpGetWebSocketCloseReason(conn));

    } else if (event == HTTP_EVENT_ERROR) {
        mprLog(0, "output.c: error event");
    }
}
示例#7
0
文件: ejsFile.c 项目: coordcn/ejs
/*  
    Read data as a string
    function readString(count: Number = -1): String
 */
static EjsString *readFileString(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv)
{
    EjsString       *result;
    MprPath         info;
    ssize           totalRead;
    int             count;

    if (argc == 0) {
        count = -1;
    } else if (argc != 1) {
        count = 0;
        ejsThrowArgError(ejs, "Bad args");
        return 0;
    } else {
        assert(argc == 1 && ejsIs(ejs, argv[0], Number));
        count = ejsGetInt(ejs, argv[0]);
    }
    if (fp->file == 0) {
        ejsThrowStateError(ejs, "File not open");
        return 0;
    }
    if (!(fp->mode & EJS_FILE_READ)) {
        ejsThrowStateError(ejs, "File not opened for reading");
        return 0;
    }
    if (count < 0) {
        //  TODO OPT could this be cached in fp->info 
        if (mprGetPathInfo(fp->path, &info) == 0) {
            count = (int) info.size;
            count -= (int) mprGetFilePosition(fp->file);
        } else {
            count = ME_MAX_BUFFER;
        }
        assert(count >= 0);
    }
    if ((result = ejsCreateBareString(ejs, count)) == NULL) {
        ejsThrowMemoryError(ejs);
        return 0;
    }
    totalRead = mprReadFile(fp->file, result->value, count);
    if (totalRead != count) {
        ejsThrowIOError(ejs, "Cannot read from file: %s", fp->path);
        return 0;
    }
    return ejsInternString(result);
}
示例#8
0
ssize espRenderFile(HttpConn *conn, cchar *path)
{
    MprFile     *from;
    ssize       count, written, nbytes;
    char        buf[MPR_BUFSIZE];

    if ((from = mprOpenFile(path, O_RDONLY | O_BINARY, 0)) == 0) {
        return MPR_ERR_CANT_OPEN;
    }
    written = 0;
    while ((count = mprReadFile(from, buf, sizeof(buf))) > 0) {
        if ((nbytes = espRenderBlock(conn, buf, count)) < 0) {
            return nbytes;
        }
        written += nbytes;
    }
    mprCloseFile(from);
    return written;
}
示例#9
0
文件: ejsFile.c 项目: coordcn/ejs
/*  
    Read the specified count of bytes into the byte array. Grow the array if required and growable
 */
static ssize readData(Ejs *ejs, EjsFile *fp, EjsByteArray *ap, ssize offset, ssize count)
{
    ssize   room, bytes;

    if (count <= 0) {
        return 0;
    }
    room = ap->size - offset;
    if (room < count) {
        if (ap->resizable) {
            ejsGrowByteArray(ejs, ap, ap->size + (count - room));
        } else {
            count = min(room, count);
        }
    }
    bytes = mprReadFile(fp->file, &ap->value[offset], count);
    if (bytes < 0) {
        ejsThrowIOError(ejs, "Error reading from %s", fp->path);
    }
    return bytes;
}
示例#10
0
文件: ejsZlib.c 项目: monmarzia/ejs-2
/*
    compress(src: Path, dest: Path = null)
 */
static EjsObj *zlib_compress(Ejs *ejs, EjsObj *unused, int argc, EjsObj **argv)
{
    MprFile     *in;
    gzFile      out;
    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 = mprOpenFile(src, O_RDONLY | O_BINARY, 0)) == 0) {
        ejsThrowIOError(ejs, "Cannot open from %s", src);
        return 0;
    }
    if ((out = gzopen(dest, "wb")) == 0) {
        ejsThrowIOError(ejs, "Cannot open destination %s", dest);
        return 0;
    }
    while (1) {
        if ((nbytes = mprReadFile(in, inbuf, sizeof(inbuf))) < 0) {
            ejsThrowIOError(ejs, "Cannot read from %s", src);
            return 0;
        } else if (nbytes == 0) {
            break;
        }
        if (gzwrite(out, inbuf, (int) nbytes) != nbytes) {
            ejsThrowIOError(ejs, "Cannot write to %s", dest);
            return 0;
        }
    }
    mprCloseFile(in);
    gzclose(out);
    return 0;
}
示例#11
0
文件: cmd.c 项目: embedthis/mpr
/*
    Determine the windows program to invoke.
    Support UNIX style "#!/program" bang directives on windows.
    Also supports ".cmd" and ".bat" alternatives.
 */
static void prepWinProgram(MprCmd *cmd)
{
#if ME_WIN_LIKE
    MprFile     *file;
    cchar       *bat, *ext, *shell, *cp, *start;
    char        bang[ME_MAX_FNAME + 1], *path, *pp;

    /*
        Map separators, convert carriage-returns and newlines to spaces and remove quotes on the command
     */
    path = mprAlloc(slen(cmd->argv[0]) * 2 + 1);
    strcpy(path, cmd->argv[0]);
    for (pp = path; *pp; pp++) {
        if (*pp == '/') {
            *pp = '\\';
        } else if (*pp == '\r' || *pp == '\n') {
            *pp = ' ';
        }
    }
    if (*path == '\"') {
        if ((pp = strrchr(++path, '"')) != 0) {
            *pp = '\0';
        }
        path = sclone(path);
    }
    cmd->argv[0] = path;

    /*
        Support ".cmd" and ".bat" files that take precedence
     */
    if ((ext = mprGetPathExt(path)) == 0) {
        if ((bat = mprSearchPath(mprJoinPathExt(path, ".cmd"), MPR_SEARCH_EXE, cmd->searchPath, NULL)) == 0) {
            bat = mprSearchPath(mprJoinPathExt(path, ".bat"), MPR_SEARCH_EXE, cmd->searchPath, NULL);
        }
        if (bat) {
            if ((shell = getenv("COMSPEC")) == 0) {
                shell = "cmd.exe";
            }
            cmd->argv = mprRealloc((void*) cmd->argv, (cmd->argc + 4) * sizeof(char*));
            memmove((void*) &cmd->argv[3], (void*) cmd->argv, sizeof(char*) * (cmd->argc + 1));
            cmd->argv[0] = sclone(shell);
            cmd->argv[1] = sclone("/Q");
            cmd->argv[2] = sclone("/C");
            cmd->argv[3] = bat;
            cmd->argc += 3;
            cmd->argv[cmd->argc] = 0;
            return;
        }
    }
    if ((file = mprOpenFile(path, O_RDONLY, 0)) != 0) {
        if (mprReadFile(file, bang, ME_MAX_FNAME) > 0) {
            mprCloseFile(file);
            bang[ME_MAX_FNAME] = '\0';
            if (bang[0] == '#' && bang[1] == '!') {
                cp = start = &bang[2];
                shell = ssplit(&bang[2], "\r\n", NULL);
                if (!mprIsPathAbs(shell)) {
                    /*
                        If we cannot access the command shell and the command is not an absolute path,
                        look in the same directory as the script.
                     */
                    if (mprPathExists(shell, X_OK)) {
                        shell = mprJoinPath(mprGetPathDir(path), shell);
                    }
                }
                /*
                    Get length of argv with NULL and add one
                 */
                assert(cmd->argv[cmd->argc] == 0);
                cmd->argv = mprRealloc((void*) cmd->argv, (cmd->argc + 2) * sizeof(char*));
                cmd->argv[cmd->argc + 1] = 0;

                /*
                    Copy up to make room to insert the shell argument. This copies the original NULL
                 */
                memmove((void*) &cmd->argv[1], (void*) cmd->argv, sizeof(char*) * cmd->argc);
                cmd->argv[0] = sclone(shell);
                cmd->argv[1] = path;
                cmd->argc += 1;
                assert(cmd->argv[cmd->argc] == 0);
            }
        } else {
            mprCloseFile(file);
        }
    }
#endif
}
示例#12
0
文件: http.c 项目: varphone/ejs-2
static ssize writeBody(HttpConn *conn, MprList *files)
{
    MprFile     *file;
    char        buf[HTTP_BUFSIZE], *path, *pair;
    ssize       bytes, len, count, nbytes, sofar;
    int         next, oldMode;

    if (app->upload) {
        if (httpWriteUploadData(conn, app->files, app->formData) < 0) {
            mprError("Can't write upload data %s", httpGetError(conn));
            return MPR_ERR_CANT_WRITE;
        }
    } else {
        if (app->formData) {
            count = mprGetListLength(app->formData);
            for (next = 0; (pair = mprGetNextItem(app->formData, &next)) != 0; ) {
                len = strlen(pair);
                if (next < count) {
                    len = slen(pair);
                    if (httpWrite(conn->writeq, pair, len) != len || httpWrite(conn->writeq, "&", 1) != 1) {
                        return MPR_ERR_CANT_WRITE;
                    }
                } else {
                    if (httpWrite(conn->writeq, pair, len) != len) {
                        return MPR_ERR_CANT_WRITE;
                    }
                }
            }
        }
        if (files) {
            mprAssert(mprGetListLength(files) == 1);
            for (next = 0; (path = mprGetNextItem(files, &next)) != 0; ) {
                if (strcmp(path, "-") == 0) {
                    file = mprAttachFileFd(0, "stdin", O_RDONLY | O_BINARY);
                } else {
                    file = mprOpenFile(path, O_RDONLY | O_BINARY, 0);
                }
                if (file == 0) {
                    mprError("Can't open \"%s\"", path);
                    return MPR_ERR_CANT_OPEN;
                }
                app->inFile = file;
                if (app->verbose) {
                    mprPrintf("uploading: %s\n", path);
                }
                oldMode = mprSetSocketBlockingMode(conn->sock, 1);
                while ((bytes = mprReadFile(file, buf, sizeof(buf))) > 0) {
                    sofar = 0;
                    while (bytes > 0) {
                        if ((nbytes = httpWriteBlock(conn->writeq, &buf[sofar], bytes)) < 0) {
                            mprCloseFile(file);
                            return MPR_ERR_CANT_WRITE;
                        }
                        bytes -= nbytes;
                        sofar += nbytes;
                        mprAssert(bytes >= 0);
                    }
                    mprYield(0);
                }
                httpFlushQueue(conn->writeq, 1);
                mprSetSocketBlockingMode(conn->sock, oldMode);
                mprCloseFile(file);
                app->inFile = 0;
            }
        }
        if (app->bodyData) {
            mprAddNullToBuf(app->bodyData);
            len = mprGetBufLength(app->bodyData);
            if (httpWriteBlock(conn->writeq, mprGetBufStart(app->bodyData), len) != len) {
                return MPR_ERR_CANT_WRITE;
            }
        }
    }
    return 0;
}
示例#13
0
/*
    If the program has a UNIX style "#!/program" string at the start of the file that program will be selected 
    and the original program will be passed as the first arg to that program with argv[] appended after that. If 
    the program is not found, this routine supports a safe intelligent search for the command. If all else fails, 
    we just return in program the fileName we were passed in. script will be set if we are modifying the program 
    to run and we have extracted the name of the file to run as a script.
 */
static void findExecutable(HttpConn *conn, char **program, char **script, char **bangScript, cchar *fileName)
{
    HttpRx      *rx;
    HttpTx      *tx;
    HttpRoute   *route;
    MprKey      *kp;
    MprFile     *file;
    cchar       *actionProgram, *ext, *cmdShell, *cp, *start, *path;
    char        buf[ME_MAX_FNAME + 1];

    rx = conn->rx;
    tx = conn->tx;
    route = rx->route;

    *bangScript = 0;
    *script = 0;
    *program = 0;
    path = 0;

    actionProgram = mprGetMimeProgram(rx->route->mimeTypes, rx->mimeType);
    ext = tx->ext;

    /*
        If not found, go looking for the fileName with the extensions defined in appweb.conf. 
        NOTE: we don't use PATH deliberately!!!
     */
    if (access(fileName, X_OK) < 0) {
        for (kp = 0; (kp = mprGetNextKey(route->extensions, kp)) != 0; ) {
            path = sjoin(fileName, ".", kp->key, NULL);
            if (access(path, X_OK) == 0) {
                break;
            }
            path = 0;
        }
        if (kp) {
            ext = kp->key;
        } else {
            path = fileName;
        }

    } else {
        path = fileName;
    }
    assert(path && *path);

#if ME_WIN_LIKE
    if (ext && (strcmp(ext, ".bat") == 0 || strcmp(ext, ".cmd") == 0)) {
        /*
            Let a mime action override COMSPEC
         */
        if (actionProgram) {
            cmdShell = actionProgram;
        } else {
            cmdShell = getenv("COMSPEC");
        }
        if (cmdShell == 0) {
            cmdShell = "cmd.exe";
        }
        *script = sclone(path);
        *program = sclone(cmdShell);
        return;
    }
#endif

    if (actionProgram) {
        *program = sclone(actionProgram);

    } else if ((file = mprOpenFile(path, O_RDONLY, 0)) != 0) {
        if (mprReadFile(file, buf, ME_MAX_FNAME) > 0) {
            mprCloseFile(file);
            buf[ME_MAX_FNAME] = '\0';
            if (buf[0] == '#' && buf[1] == '!') {
                cp = start = &buf[2];
                cmdShell = ssplit(&buf[2], "\r\n", NULL);
                if (!mprIsPathAbs(cmdShell)) {
                    /*
                        If we cannot access the command shell and the command is not an absolute path, 
                        look in the same directory as the script.
                     */
                    if (mprPathExists(cmdShell, X_OK)) {
                        cmdShell = mprJoinPath(mprGetPathDir(path), cmdShell);
                    }
                }
                *program = sclone(cmdShell);
                *bangScript = sclone(path);
                return;
            }
        } else {
            mprCloseFile(file);
        }
    }

    if (actionProgram) {
        *program = sclone(actionProgram);
        *bangScript = sclone(path);
    } else {
        *program = sclone(path);
    }
    return;
}
示例#14
0
文件: makerom.c 项目: varphone/ejs-2
/* 
    Encode the files as C code
 */
static int binToC(MprList *files, char *romName, char *prefix)
{
    MprPath         info;
    MprFile         *file;
    char            buf[512];
    char            *filename, *cp, *sl, *p;
    ssize           len;
    int             next, i, j;

    mprPrintf("/*\n    %s -- Compiled Files\n */\n", romName);

    mprPrintf("#include \"mpr.h\"\n\n");
    mprPrintf("#if BIT_FEATURE_ROMFS\n");

    /*
        Open each input file and compile
     */
    for (next = 0; (filename = mprGetNextItem(files, &next)) != 0; ) {
        if (mprGetPathInfo(filename, &info) == 0 && info.isDir) {
            continue;
        } 
        if ((file = mprOpenFile(filename, O_RDONLY | O_BINARY, 0666)) < 0) {
            mprError("Can't open file %s\n", filename);
            return -1;
        }
        mprPrintf("static uchar _file_%d[] = {\n", next);

        while ((len = mprReadFile(file, buf, sizeof(buf))) > 0) {
            p = buf;
            for (i = 0; i < len; ) {
                mprPrintf("    ");
                for (j = 0; p < &buf[len] && j < 16; j++, p++) {
                    mprPrintf("%3d,", (unsigned char) *p);
                }
                i += j;
                mprPrintf("\n");
            }
        }
        mprPrintf("    0 };\n\n");
        mprCloseFile(file);
    }

    /*
        Now output the page index
     */ 
    mprPrintf("MprRomInode %s[] = {\n", romName);

    for (next = 0; (filename = mprGetNextItem(files, &next)) != 0; ) {
        /*
            Replace the prefix with a leading "/"
         */ 
        if (strncmp(filename, prefix, strlen(prefix)) == 0) {
            cp = &filename[strlen(prefix)];
        } else {
            cp = filename;
        }
        while((sl = strchr(filename, '\\')) != NULL) {
            *sl = '/';
        }
        if (*cp == '/') {
            cp++;
        }
        if (*cp == '.' && cp[1] == '\0') {
            cp++;
        }
        if (mprGetPathInfo(filename, &info) == 0 && info.isDir) {
            mprPrintf("    { \"%s\", 0, 0, 0 },\n", cp);
            continue;
        }
        mprPrintf("    { \"%s\", _file_%d, %d, %d },\n", cp, next, (int) info.size, next);
    }
    
    mprPrintf("    { 0, 0, 0, 0 },\n");
    mprPrintf("};\n");
    mprPrintf("#endif /* BIT_FEATURE_ROMFS */\n");
    return 0;
}
示例#15
0
文件: http.c 项目: gitorup/appweb
static ssize writeBody(HttpConn *conn, MprList *files)
{
    MprFile     *file;
    char        buf[ME_MAX_BUFFER], *path, *pair;
    ssize       bytes, len, count, nbytes, sofar;
    int         next;

    if (app->upload) {
        if (httpWriteUploadData(conn, app->files, app->formData) < 0) {
            return MPR_ERR_CANT_WRITE;
        }
    } else {
        if (app->formData) {
            count = mprGetListLength(app->formData);
            for (next = 0; (pair = mprGetNextItem(app->formData, &next)) != 0; ) {
                len = strlen(pair);
                if (next < count) {
                    len = slen(pair);
                    if (httpWriteString(conn->writeq, pair) != len || httpWriteString(conn->writeq, "&") != 1) {
                        return MPR_ERR_CANT_WRITE;
                    }
                } else {
                    if (httpWrite(conn->writeq, pair, len) != len) {
                        return MPR_ERR_CANT_WRITE;
                    }
                }
            }
        }
        if (files) {
            assert(mprGetListLength(files) == 1);
            for (next = 0; (path = mprGetNextItem(files, &next)) != 0; ) {
                if (strcmp(path, "-") == 0) {
                    file = mprAttachFileFd(0, "stdin", O_RDONLY | O_BINARY);
                } else {
                    file = mprOpenFile(path, O_RDONLY | O_BINARY, 0);
                }
                if (file == 0) {
                    mprLog("error http", 0, "Cannot open \"%s\"", path);
                    return MPR_ERR_CANT_OPEN;
                }
                app->inFile = file;
                if (app->verbose) {
                    mprPrintf("uploading: %s\n", path);
                }
                while ((bytes = mprReadFile(file, buf, sizeof(buf))) > 0) {
                    sofar = 0;
                    while (bytes > 0) {
                        if ((nbytes = httpWriteBlock(conn->writeq, &buf[sofar], bytes, HTTP_BLOCK)) < 0) {
                            mprCloseFile(file);
                            return MPR_ERR_CANT_WRITE;
                        }
                        bytes -= nbytes;
                        sofar += nbytes;
                        assert(bytes >= 0);
                    }
                }
                httpFlushQueue(conn->writeq, HTTP_BLOCK);
                mprCloseFile(file);
                app->inFile = 0;
            }
        }
        if (app->bodyData) {
            len = mprGetBufLength(app->bodyData);
            if (httpWriteBlock(conn->writeq, mprGetBufStart(app->bodyData), len, HTTP_BLOCK) != len) {
                return MPR_ERR_CANT_WRITE;
            }
        }
    }
    return 0;
}