static void openFileHandler(HttpQueue *q) { HttpRx *rx; HttpTx *tx; HttpRoute *route; HttpConn *conn; MprPath *info; char *date; conn = q->conn; tx = conn->tx; rx = conn->rx; route = rx->route; info = &tx->fileInfo; if (rx->flags & (HTTP_PUT | HTTP_DELETE)) { if (!(route->flags & HTTP_ROUTE_PUT_DELETE_METHODS)) { httpError(q->conn, HTTP_CODE_BAD_METHOD, "The \"%s\" method is not supported by file handler", rx->method); } } else { if (rx->flags & (HTTP_GET | HTTP_HEAD | HTTP_POST)) { if (!(info->valid || info->isDir)) { if (rx->referrer) { mprLog(2, "fileHandler: Cannot find filename %s from referrer %s", tx->filename, rx->referrer); } else { mprLog(2, "fileHandler: Cannot find filename %s", tx->filename); } httpError(conn, HTTP_CODE_NOT_FOUND, "Cannot find %s", rx->uri); } else if (info->valid) { if (!tx->etag) { /* Set the etag for caching in the client */ tx->etag = sfmt("\"%Lx-%Lx-%Lx\"", (int64) info->inode, (int64) info->size, (int64) info->mtime); } } } if (rx->flags & (HTTP_GET | HTTP_HEAD | HTTP_POST) && !conn->error) { if (tx->fileInfo.valid && tx->fileInfo.mtime) { // TODO - OPT could cache this date = httpGetDateString(&tx->fileInfo); httpSetHeader(conn, "Last-Modified", date); } if (httpContentNotModified(conn)) { httpSetStatus(conn, HTTP_CODE_NOT_MODIFIED); httpOmitBody(conn); tx->length = -1; } if (!tx->fileInfo.isReg && !tx->fileInfo.isLink) { httpError(conn, HTTP_CODE_NOT_FOUND, "Cannot locate document: %s", rx->uri); } else if (tx->fileInfo.size > conn->limits->transmissionBodySize) { httpError(conn, HTTP_ABORT | HTTP_CODE_REQUEST_TOO_LARGE, "Http transmission aborted. File size exceeds max body of %,Ld bytes", conn->limits->transmissionBodySize); } else if (!(tx->connector == conn->http->sendConnector)) { /* If using the net connector, open the file if a body must be sent with the response. The file will be automatically closed when the request completes. */ if (!(tx->flags & HTTP_TX_NO_BODY)) { tx->file = mprOpenFile(tx->filename, O_RDONLY | O_BINARY, 0); if (tx->file == 0) { if (rx->referrer) { httpError(conn, HTTP_CODE_NOT_FOUND, "Cannot open document: %s from %s", tx->filename, rx->referrer); } else { httpError(conn, HTTP_CODE_NOT_FOUND, "Cannot open document: %s from %s", tx->filename); } } } } } else if (rx->flags & (HTTP_OPTIONS | HTTP_TRACE)) { if (route->flags & HTTP_ROUTE_PUT_DELETE_METHODS) { httpHandleOptionsTrace(q->conn, "DELETE,GET,HEAD,POST,PUT"); } else { httpHandleOptionsTrace(q->conn, "GET,HEAD,POST"); } } } }
static int openFileHandler(HttpQueue *q) { HttpRx *rx; HttpTx *tx; HttpConn *conn; MprPath *info; char *date, dbuf[16]; MprHash *dateCache; conn = q->conn; tx = conn->tx; rx = conn->rx; info = &tx->fileInfo; if (conn->error) { return MPR_ERR_CANT_OPEN; } if (rx->flags & (HTTP_GET | HTTP_HEAD | HTTP_POST)) { if (!(info->valid || info->isDir)) { httpError(conn, HTTP_CODE_NOT_FOUND, "Cannot find document"); return 0; } if (!tx->etag) { /* Set the etag for caching in the client */ tx->etag = sfmt("\"%llx-%llx-%llx\"", (int64) info->inode, (int64) info->size, (int64) info->mtime); } if (info->mtime) { dateCache = conn->http->dateCache; if ((date = mprLookupKey(dateCache, itosbuf(dbuf, sizeof(dbuf), (int64) info->mtime, 10))) == 0) { if (!dateCache || mprGetHashLength(dateCache) > 128) { conn->http->dateCache = dateCache = mprCreateHash(0, 0); } date = httpGetDateString(&tx->fileInfo); mprAddKey(dateCache, itosbuf(dbuf, sizeof(dbuf), (int64) info->mtime, 10), date); } httpSetHeaderString(conn, "Last-Modified", date); } if (httpContentNotModified(conn)) { httpSetStatus(conn, HTTP_CODE_NOT_MODIFIED); httpOmitBody(conn); tx->length = -1; } if (!tx->fileInfo.isReg && !tx->fileInfo.isLink) { httpTrace(conn, "request.document.error", "error", "msg: 'Document is not a regular file', filename: '%s'", tx->filename); httpError(conn, HTTP_CODE_NOT_FOUND, "Cannot serve document"); } else if (tx->fileInfo.size > conn->limits->transmissionBodySize) { httpError(conn, HTTP_ABORT | HTTP_CODE_REQUEST_TOO_LARGE, "Http transmission aborted. File size exceeds max body of %'lld bytes", conn->limits->transmissionBodySize); } else if (!(tx->connector == conn->http->sendConnector)) { /* If using the net connector, open the file if a body must be sent with the response. The file will be automatically closed when the request completes. */ if (!(tx->flags & HTTP_TX_NO_BODY)) { tx->file = mprOpenFile(tx->filename, O_RDONLY | O_BINARY, 0); if (tx->file == 0) { if (rx->referrer && *rx->referrer) { httpTrace(conn, "request.document.error", "error", "msg: 'Cannot open document', filename: '%s', referrer: '%s'", tx->filename, rx->referrer); } else { httpTrace(conn, "request.document.error", "error", "msg: 'Cannot open document', filename: '%s'", tx->filename); } httpError(conn, HTTP_CODE_NOT_FOUND, "Cannot open document"); } } } } else if (rx->flags & (HTTP_DELETE | HTTP_OPTIONS | HTTP_PUT)) { ; } else { httpError(conn, HTTP_CODE_BAD_METHOD, "Unsupported method"); } return 0; }