UNPKG

waffle

Version:

シンプルなWEBアプリケーションフレームワークです。(ALL YOUR NODE ARE BELONG TO US)

161 lines (148 loc) 4.89 kB
/* * Copyright 2012 Katsunori Koyanagi * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ /** * @overview 外部から不可視であるファイルをダウンロードされるためのレンダラです。 */ "use strict"; var lang = require("../utils/Lang"); var mime = require("mime"); var fs = require("fs"); var Stream = require("stream"); /** * 外部から不可視であるファイルをダウンロードされるためのレンダラです。 * <p> * このレンダラをコントローラで指定する場合のフォーマットは&lt;prefix&gt;となります。 * データにはファイル情報を指定してください。ダウンロードさせる内容が不確定の場合は、404エラーとなります。 * ファイル情報は以下のメンバーを持つオブジェクトである必要があります。 * </p> * <table> * <tr> * <th>メンバ名</th> * <th>型</th> * <th>必須</th> * <th>説明</th> * </tr> * <tr> * <td>data</td> * <td>Node.jsのReadableStreamもしくは、Node.jsのBufferもしくはString</td> * <td>true</td> * <td>Stringが指定された場合は絶対パスのファイル名とみなし、そのファイルをダウンロードの対象とします。</td> * </tr> * <tr> * <td>contentType</td> * <td>String</td> * <td>false</td> * <td>dataでファイル名が指定されている場合、fileNameが指定されている場合は、自動的にそのファイル名に基づきContent-Typeが解決されますが、 * オーバーライドしたい場合、ファイル名を解決するパラメータが存在しない場合は、指定する必要があります。省略時は、"application/octet-stream"になります。</td> * </tr> * <tr> * <td>fileName</td> * <td>String</td> * <td>false</td> * <td>ブラウザがファイルを保存する際に使用されるファイル名です。省略した場合はdataにファイル名が指定されている場合のみ自動で解決されます。</td> * </tr> * </table> * * @example <code> * var waffle = require("waffle"); * config.renderer.register("file", waffle.renderers.file); * </code> * * @name Renderers#file */ exports.render = function(context, param, data, callback) { if (!data) { context.error(404); return; } var content = data.data; if (content == null || content == undefined) { context.error(404); return; } var onStat = function(error, stat) { if (error) { context.error(500, error); return; } if (stat != null && !stat.isFile()) { context.error(404); return; } var len = stat == null ? -1 : stat.size; var fileName = null; if (lang.isString(content)) { fileName = content; } if (data.fileName) { fileName = data.fileName; } if (fileName == null) { fileName = ""; } var contentType = null; if (data.contentType) { contentType = data.contentType; } if (!contentType) { contentType = mime.lookup(fileName); } var stream = null; if (lang.isString(content)) { stream = new fs.ReadStream(content); } else if (lang.isNumber(content)) { stream = new fs.ReadStream(null, { fd : content }); } else if (content instanceof Stream) { stream = content; } fileName = fileName ? ("attachment; filename=\"" + fs.basename(fileName) + "\"") : ("attachment"); context.res.statusCode = 200; context.res.setHeader("Content-Type", contentType); context.res.setHeader("Content-Disposition", fileName); if (len > -1) { context.res.setHeader("Content-Length", len); } var len0 = 0; var handler = function(obj) { if (obj instanceof Buffer) { context.res.write(obj); } else if (lang.isError(obj)) { stream.removeAllListeners(); context.error(500, error); } else { stream.removeAllListeners(); console.log(fs.fstatSync(stream.fd)); callback(); } }; stream.on("end", handler); stream.on("data", handler); stream.on("error", handler); }; if (lang.isString(content)) { fs.stat(content, onStat); } else if (lang.isNumber(content)) { fs.fstat(content, onStat); } else if (content instanceof Stream) { onStat(null, null); } else { context.error(404); return; } };