001 /* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016 package org.opengion.hayabusa.servlet; 017 018 import java.io.FileInputStream; 019 import java.io.IOException; 020 021 import javax.mail.internet.MimeUtility; 022 import javax.servlet.ServletException; 023 import javax.servlet.ServletOutputStream; 024 import javax.servlet.http.HttpServlet; 025 import javax.servlet.http.HttpServletRequest; 026 import javax.servlet.http.HttpServletResponse; 027 028 import org.opengion.fukurou.security.HybsCryptography; 029 import org.opengion.fukurou.util.Closer; 030 import org.opengion.fukurou.util.KanaFilter; 031 import org.opengion.fukurou.util.StringUtil; 032 import org.opengion.hayabusa.common.HybsSystem; 033 import org.opengion.hayabusa.common.HybsSystemException; 034 035 /** 036 * サーãƒã?管ç?ƒ•ァイルをダウンãƒãƒ¼ãƒ‰ã™ã‚‹å?åˆã«ä½¿ç”¨ã™ã‚‹ã€ã‚µãƒ¼ãƒ–レãƒ?ƒˆã§ã™ã? 037 * 038 * 引数(URL)ã«æŒ?®šã?ファイルをサーãƒã?ã‹ã‚‰ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã«ãƒ?‚¦ãƒ³ãƒãƒ¼ãƒ‰ã•ã›ã¾ã™ã? 039 * file ã«ã¯ã€ã‚µãƒ¼ãƒã?ファイルã®ç‰©ç?‚¢ãƒ‰ãƒ¬ã‚¹ã‚’指定ã—ã¾ã™ã?相対パスを使用ã™ã‚‹å ´åˆã?ã€? 040 * コンãƒ?‚ストルーãƒ?通常ã€Tomcatã§ã¯ã€G:\webapps\dbdef2\ ãªã©)ã‹ã‚‰ã®ãƒ‘スã¨åˆ¤æ–ã—ã¾ã™ã? 041 * name ã«ã¯ã€ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã«é€ä¿¡ã™ã‚‹ãƒ•ァイルåã‚’æŒ?®šã—ã¾ã™ã?ファイルåã‚’æŒ?®šã—ãªã??åˆã?ã€? 042 * サーãƒã?ã®ç‰©ç?ƒ•ァイルã®ãƒ•ァイルåãŒä»£ã‚りã«ä½¿ç”¨ã•れã¾ã™ã? 043 * 日本語ファイルåã?ã€ã™ã¹ã¦ UTF-8化ã—ã¦å‡¦ç?—ã¾ã™ã?æŒ?®šã™ã‚‹ãƒ•ã‚¡ã‚¤ãƒ«ã«æ—¥æœ¬èªžãŒå«ã¾ã‚Œã‚‹ 044 * å ´åˆã?ã€URLエンコードを行ã£ã¦ãã ã•ã„ã€? 045 * 基本çš?«ã¯Content-disposition属æ?ã¨ã—ã¦"attachment"ãŒæŒ‡å®šã•れã¾ã™ã? 046 * ä½?—ã€å¼•æ•°ã« inline=true を指定ã™ã‚‹ã“ã¨ã§ã€Content-disposition属æ?ã«"inline"ãŒæŒ‡å®šã•れã¾ã™ã? 047 * ã¾ãŸã?シスãƒ?ƒ リソースã®USE_FILEDOWNLOAD_CHECKKEYã‚’trueã«æŒ?®šã™ã‚‹ã“ã¨ã§ã€ç°¡æ˜“çš„ãªãƒã‚§ãƒ?‚¯ã‚? 048 * 行ã†ã“ã¨ãŒã§ãã¾ã™ã? 049 * 具体的ã«ã¯ã€ã“れを有効ã«ã™ã‚‹ã¨ã€file属æ?ã®å€¤ã‹ã‚‰è¨ˆç®—ã•れるMD5ãƒã‚§ãƒ?‚¯ã‚µãƒ?¨ã€?key"ã¨ã?† 050 * ãƒ‘ãƒ©ãƒ¡ãƒ¼ã‚¿ãƒ¼ã«æŒ?®šã•れãŸå€¤ãŒä¸??ã—ãŸå ´åˆã?ã¿ãƒ?‚¦ãƒ³ãƒãƒ¼ãƒ‰ãŒè¨±å¯ã•れã€keyãŒæŒ‡å®šã•れã¦ã?ªã?? 051 * ã¾ãŸã?値ãŒç•°ãªã‚‹å?åˆã?ãƒ?‚¦ãƒ³ãƒãƒ¼ãƒ‰ã‚¨ãƒ©ãƒ¼ã¨ãªã‚Šã¾ã™ã? 052 * 053 * ä¸?ˆ¬çš?ªã‚µãƒ¼ãƒ–レãƒ?ƒˆã¨åŒæ§˜ã«ã€ãƒ‡ãƒ—ãƒã‚¤ãƒ¡ãƒ³ãƒˆã?ãƒ?‚£ã‚¹ã‚¯ãƒªãƒ—ã‚¿ WEB-INF/web.xml ã«ã€? 054 * servlet è¦ç´?¨ ãã?マッピング(servlet-mapping)を定義ã™ã‚‹å¿?¦ãŒã‚りã¾ã™ã? 055 * 056 * <servlet> 057 * <servlet-name>fileDownload</servlet-name> 058 * <servlet-class>org.opengion.hayabusa.servlet.FileDownload</servlet-class> 059 * </servlet> 060 * 061 * <servlet-mapping> 062 * <servlet-name>fileDownload</servlet-name> 063 * <url-pattern>/jsp/fileDownload</url-pattern> 064 * </servlet-mapping> 065 * 066 * ä¸?ˆ¬ã«ã¯ã€http://:ãƒã?ãƒ?シスãƒ?ƒ ID/jsp/fileDownload?file=サーãƒã?物ç?ƒ•ァイル&name=ファイルå? 067 * å½¢å¼ã?URL ã§ã‚¢ã‚¯ã‚»ã‚¹ã—ã¾ã™ã? 068 * 069 * forwardã§ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹å ´åˆã?ファイルåã?æ–?—コード変æ›ãŒä¸è¦ãªãŸã‚ã€useStrincConvert=falseã® 070 * 引数を与ãˆã¦ãã ã•ã„。ï¼?alseã¨ã—ãªã??åˆã?日本語ファイルåç‰ã§ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã™ï¼? 071 * 072 * @og.rev 3.8.1.1 (2005/11/21) æ–°è¦è¿½åŠ? 073 * @og.group ãã?他機è? 074 * 075 * @version 0.9.0 2000/10/17 076 * @author Kazuhiko Hasegawa 077 * @since JDK1.1, 078 */ 079 public class FileDownload extends HttpServlet { 080 private static final long serialVersionUID = 539020110901L ; 081 082 // æ‹¡å¼µåcontentType対応テーブル 083 private static final String CONTENT_TYPE_TABLE[][] = { 084 {"jpg", "image/pjpeg" }, 085 {"gif", "image/gif" }, 086 {"txt", "text/plain" }, 087 // {"xls", "application/vnd.ms-excel"} 088 // OpenDocument追åŠ? 089 {"xls", "application/vnd.ms-excel"}, 090 {"odp", "application/vnd.oasis.opendocument.presentation"}, // 4.3.5.5 (2008/03/08) 091 {"ods", "application/vnd.oasis.opendocument.spreadsheet"}, // 4.3.5.5 (2008/03/08) 092 {"odt", "application/vnd.oasis.opendocument.text"} // 4.3.5.5 (2008/03/08) 093 }; 094 private static final int EXTENTION = 0; 095 private static final int CONTENT_TYPE= 1; 096 097 /** 098 * GET メソãƒ?ƒ‰ãŒå‘¼ã°ã‚ŒãŸã¨ãã«å®Ÿè¡Œã—ã¾ã™ã? 099 * 100 * 処ç??ã€doPost ã¸æŒ¯ã‚ŠãªãŠã—ã¦ã?¾ã™ã? 101 * 102 * @param request HttpServletRequestオブジェクãƒ? 103 * @param response HttpServletResponseオブジェクãƒ? 104 * 105 * @og.rev 3.8.1.2 (2005/12/19) åŠè§’ã‚«ãƒ?å…¨è§’ã‚«ãƒŠå¤‰æ›æ©Ÿè?ã®è¿½åŠ? 106 * 107 * @throws ServletException サーブレãƒ?ƒˆé–¢ä¿‚ã?エラーãŒç™ºç”Ÿã—ãŸå?åˆã?throw ã•れã¾ã™ã? 108 * @throws IOException 入出力エラーãŒç™ºç”Ÿã—ãŸã¨ã? 109 */ 110 @Override 111 public void doGet( final HttpServletRequest request, final HttpServletResponse response ) 112 throws ServletException, IOException { 113 doPost( request,response ); 114 } 115 116 /** 117 * POST メソãƒ?ƒ‰ãŒå‘¼ã°ã‚ŒãŸã¨ãã«å®Ÿè¡Œã—ã¾ã™ã? 118 * 119 * file 引数㮠サーãƒã?物ç?ƒ•ァイルをã?クライアントã«ã‚¹ãƒˆãƒªãƒ¼ãƒ?Œ–ã—ã¦è¿”ã—ã¾ã™ã? 120 * name 引数ãŒã‚れã?ã€ãã®åå‰ã®ãƒ•ァイルåã§ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆãŒãƒ•ァイルセーブã§ãるよã†ã« 121 * ã—ã¾ã™ã?name 引数ãŒãªã‘れã°ã€ãã®ã¾ã¾ç‰©ç?ƒ•ァイルåãŒä½¿ç”¨ã•れã¾ã™ã? 122 * サーãƒã?物ç?ƒ•ァイルåãŒã€ç›¸å¯¾ãƒ‘スã®å ´åˆã?コンãƒ?‚ストルートã«å¯¾ã™ã‚‹ç›¸å¯¾ãƒ‘スã«ãªã‚Šã¾ã™ã? 123 * (例:G:\webapps\dbdef2\ ãªã©) 124 * 125 * @og.rev 5.3.2.0 (2011/02/01) 日本語ファイルåãŒæ£ã—ã処ç?§ããªã?ƒã‚°ã‚’ä¿®æ£ 126 * @og.rev 5.3.4.0 (2011/04/01) IEã§ãƒ•ã‚¡ã‚¤ãƒ«ãŒæ£ã—ããƒ?‚¦ãƒ³ãƒãƒ¼ãƒ‰ã§ããªã?ƒã‚°ã‚’ä¿®æ£ 127 * @og.rev 5.3.5.0 (2011/05/01) ファイルãƒ?‚¦ãƒ³ãƒãƒ¼ãƒ‰ãƒã‚§ãƒ?‚¯ã‚ー対å¿? 128 * @og.rev 5.3.6.0 (2011/06/01) ファイルãƒ?‚¦ãƒ³ãƒãƒ¼ãƒ‰ã?attachmentã«å¤‰æ›´(ãƒ?‚¦ãƒ³ãƒãƒ¼ãƒ‰ãƒ€ã‚¤ã‚¢ãƒã‚°ã‚’å?ã? 129 * @og.rev 5.3.8.0 (2011/08/01) ãƒ•ã‚¡ã‚¤ãƒ«åæŒ‡å®šã§IEã®å ´åˆã?URLエンコードã™ã‚‹ã¨é€”ä¸ã§åˆ?‚Œã‚‹ãŸã‚?IE7ã®ãƒã‚°)ã€Shift_JIS(WIndows-31J)ã§ç›´æŽ¥æŒ?®šã™ã‚‹ã? 130 * @og.rev 5.3.9.0 (2011/09/01) 引数ã«inline=trueを指定ã™ã‚‹ã“ã¨ã§ã€ã‚¤ãƒ³ãƒ©ã‚¤ãƒ³è¡¨ç¤ºãŒå?æ¥ã‚‹ã‚ˆã?«å¯¾å¿? 131 * @og.rev 5.7.1.2 (2013/12/20) 日本語ファイルã®IE11対応ï¼?A変更??msg â‡?errMsg 変更 132 * @og.rev 5.8.1.0 (2014/11/07) forward時ã?æ–?—コード変æ›ä¸è¦å¯¾å¿? 133 * 134 * @param request HttpServletRequestオブジェクãƒ? 135 * @param response HttpServletResponseオブジェクãƒ? 136 * 137 * @throws ServletException サーブレãƒ?ƒˆé–¢ä¿‚ã?エラーãŒç™ºç”Ÿã—ãŸå?åˆã?throw ã•れã¾ã™ã? 138 * @throws IOException 入出力エラーãŒç™ºç”Ÿã—ãŸã¨ã? 139 */ 140 @Override 141 public void doPost( final HttpServletRequest request, final HttpServletResponse response ) 142 throws ServletException, IOException { 143 144 // 3.8.1.2 (2005/12/19) åŠè§’ã‚«ãƒ?å…¨è§’ã‚«ãƒŠå¤‰æ›æ©Ÿè?ã®è¿½åŠ? 145 boolean hanzenFlag = HybsSystem.sysBool( "USE_FILEDOWNLOAD_HAN_ZEN" ); 146 147 String reqFilename = request.getParameter( "file" ); 148 String newFilename = request.getParameter( "name" ); 149 150 // 5.3.9.0 (2011/09/01) 引数ã«inline=trueを指定ã™ã‚‹ã“ã¨ã§ã€ã‚¤ãƒ³ãƒ©ã‚¤ãƒ³è¡¨ç¤ºãŒå?æ¥ã‚‹ã‚ˆã?«å¯¾å¿? 151 boolean inline = StringUtil.nval( request.getParameter( "inline" ), false ); 152 String dipositionType = inline ? "inline" : "attachment"; 153 154 // 5.8.1.0 (2014/11/07) エンコード変æ›å¯¾å¿? 155 boolean useStrCnv = StringUtil.nval( request.getParameter( "useStringConvert" ), true ); 156 157 // クライアントå?ã®æ–?—エンコーãƒ?‚£ãƒ³ã‚°ã‚’UTF-8ã«å¤‰æ› 158 // 5.8.1.0 (2014/11/07) æ¡ä»¶è¿½åŠ? 159 if( useStrCnv ){ 160 reqFilename = new String( reqFilename.getBytes("ISO-8859-1"), "UTF-8" ); 161 } 162 163 // 5.3.5.0 (2011/05/01) ファイルãƒ?‚¦ãƒ³ãƒãƒ¼ãƒ‰ãƒã‚§ãƒ?‚¯ã‚ー対å¿? 164 boolean useCheck = HybsSystem.sysBool( "USE_FILEDOWNLOAD_CHECKKEY" ); 165 if( useCheck ) { 166 String checkKey = request.getParameter( "key" ); 167 if( checkKey == null || !checkKey.equals( HybsCryptography.getMD5( reqFilename ) ) ) { 168 // String msg = "ã‚¢ã‚¯ã‚»ã‚¹ãŒæ‹’å¦ã•れã¾ã—ãŸã€?URLãƒã‚§ãƒ?‚¯)"; 169 // throw new HybsSystemException( msg ); 170 String errMsg = "ã‚¢ã‚¯ã‚»ã‚¹ãŒæ‹’å¦ã•れã¾ã—ãŸã€?URLãƒã‚§ãƒ?‚¯)"; 171 throw new HybsSystemException( errMsg ); // 5.7.1.2 (2013/12/20) msg â‡?errMsg 変更 172 } 173 } 174 175 // 相対パスを絶対パスã«å¤‰æ›ã€‚ファイルセパレータもæ£è¦åŒ–ã•れã¦ã?¾ã™ã? 176 reqFilename = HybsSystem.url2dir( reqFilename ); 177 178 // æ‹¡å¼µåã‹ã‚‰contentTypeã‚’ç²å¾? 179 String contentType = getContentType( reqFilename ); 180 // contentTypeã‚’å?åŠ? 181 response.setContentType( contentType ); 182 183 // 表示ファイルåã?æŒ?®? 184 if( newFilename == null || newFilename.length() == 0 ) { 185 newFilename = getFileName( reqFilename ); 186 } 187 // else { 188 else if( useStrCnv ){ // 5.8.1.0 (2014/11/07) æ¡ä»¶è¿½åŠ? 189 newFilename = new String( newFilename.getBytes("ISO-8859-1"), "UTF-8" ); 190 } 191 192 // 3.8.1.2 (2005/12/19) åŠè§’カナを全角カナã«ç½®ãæ›ãˆã¾ã™ã?ファイルãƒ?‚¤ã‚¢ãƒã‚°ã®æ–?—化ã‘仮対å¿? 193 if( hanzenFlag ) { 194 newFilename = KanaFilter.han2zen( newFilename ); 195 } 196 197 // 5.3.2.0 (2011/02/01) 日本語ファイルåãŒæ£ã—ã処ç?§ããªã?ƒã‚°ã‚’ä¿®æ£ 198 //// newFilename = StringUtil.urlEncode( newFilename ); 199 // if( request.getHeader( "User-Agent" ).indexOf( "MSIE" ) == -1 ) { 200 // newFilename = MimeUtility.encodeWord( newFilename, "UTF-8", "B" ); 201 // } 202 // else { 203 // // 5.3.8.0 (2011/08/01) IEã®å ´åˆã?URLエンコードã™ã‚‹ã¨é€”ä¸ã§åˆ?‚Œã‚‹ãŸã‚?IE7ã®ãƒã‚°)ã€Shift_JIS(WIndows-31J)ã§ç›´æŽ¥æŒ?®šã™ã‚‹ã? 204 //// newFilename = StringUtil.urlEncode( newFilename ); 205 // newFilename = new String( newFilename.getBytes("Windows-31J"), "ISO-8859-1" ); 206 // } 207 208 // 5.7.1.2 (2013/12/20) æ¡ä»¶ã‚’å転ã•ã›ãŸä¸Šã§IE11対応を行ㆠ209 if( request.getHeader( "User-Agent" ).indexOf( "MSIE" ) >= 0 || request.getHeader( "User-Agent" ).indexOf( "Trident" ) >= 0 ) { 210 newFilename = new String( newFilename.getBytes("Windows-31J"), "ISO-8859-1" ); 211 } 212 else { 213 newFilename = MimeUtility.encodeWord( newFilename, "UTF-8", "B" ); 214 } 215 216 // ファイルåã?é€ä¿¡( attachment部åˆ?‚’inlineã«å¤‰æ›´ã™ã‚Œã°ã‚¤ãƒ³ãƒ©ã‚¤ãƒ³è¡¨ç¤º ) 217 // 5.3.9.0 (2011/09/01) 引数ã«inline=trueを指定ã™ã‚‹ã“ã¨ã§ã€ã‚¤ãƒ³ãƒ©ã‚¤ãƒ³è¡¨ç¤ºãŒå?æ¥ã‚‹ã‚ˆã?«å¯¾å¿? 218 // response.setHeader( "Content-disposition", "inline; filename=\"" + newFilename + "\"" ); 219 // response.setHeader( "Content-disposition", "attachment; filename=\"" + newFilename + "\"" ); 220 response.setHeader( "Content-disposition", dipositionType + "; filename=\"" + newFilename + "\"" ); 221 222 // 5.3.4.0 (2011/04/01) IEã§ãƒ•ã‚¡ã‚¤ãƒ«ãŒæ£ã—ããƒ?‚¦ãƒ³ãƒãƒ¼ãƒ‰ã§ããªã?ƒã‚°ã‚’ä¿®æ£ 223 response.setHeader( "Cache-Control", "public" ); 224 225 // ファイルå†?®¹ã®å‡ºåŠ? 226 FileInputStream fin = null; 227 ServletOutputStream out = null; 228 try { 229 fin = new FileInputStream( reqFilename ); 230 out = response.getOutputStream(); 231 232 // ファイルèªã¿è¾¼ã¿ç”¨ãƒãƒƒãƒ•ã‚¡ 233 byte buffer[] = new byte[4096]; 234 int size; 235 while((size = fin.read(buffer))!=-1) { 236 out.write(buffer,0, size); 237 out.flush(); 238 } 239 } 240 finally { 241 Closer.ioClose( fin ); // 4.0.0 (2006/01/31) close 処ç?™‚ã® IOException ã‚’ç„¡è¦? 242 Closer.ioClose( out ); // 4.0.0 (2006/01/31) close 処ç?™‚ã® IOException ã‚’ç„¡è¦? 243 } 244 } 245 246 /** 247 * アドレスåã‹ã‚‰æ‹¡å¼µåã‚’å–り出ã—ã¾ã™ã? 248 * 249 * アドレスåã?後ã‚ã‹ã‚‰ã€?." 以é™ã‚’æ‹¡å¼µåã¨ã—ã¦åˆ?‚Šå–りã¾ã™ã? 250 * æ‹¡å¼µåãŒå˜åœ¨ã—ãªã??å?æŒ?®šã?ファイルåã« "." ãŒå«ã¾ã‚Œãªã??å?㯠251 * ã‚¼ãƒæ–?—å?("")ã‚’è¿”ã—ã¾ã™ã? 252 * 253 * @param fileAddress アドレスå? 254 * 255 * @return æ‹¡å¼µå? 256 */ 257 private String getExtention( final String fileAddress ) { 258 int idx = fileAddress.lastIndexOf('.'); 259 if( idx!=-1 ) { return fileAddress.substring( idx+1 ); } 260 return ""; 261 } 262 263 /** 264 * アドレスåã‹ã‚‰ãƒ•ァイルåã‚’å–り出ã—ã¾ã™ã? 265 * 266 * アドレスåã?後ã‚ã‹ã‚‰ã€ãƒ•ァイルセパレータ以é™ã‚’ファイルåã¨ã—ã¦åˆ?‚Šå–りã¾ã™ã? 267 * ファイルセパレータãŒå˜åœ¨ã—ãªã??åˆã?アドレスåã‚’ãã?ã¾ã¾è¿”ã—ã¾ã™ã? 268 * ã“ã“ã§ã¯ã€OS毎ã«ç•°ãªã‚‹ãƒ•ァイルセパレータを統ä¸?¾Œã«å‡¦ç?—ã¦ãã ã•ã„ã€? 269 * 270 * @param fileAddress アドレスå? 271 * 272 * @return ファイルå? 273 */ 274 private String getFileName( final String fileAddress ) { 275 int idx = fileAddress.lastIndexOf( HybsSystem.FS ); 276 if( idx!=-1 ) { return fileAddress.substring( idx+1 ); } 277 return fileAddress; 278 } 279 280 /** 281 * アドレスåã‹ã‚‰å¯¾å¿œã™ã‚‹ã‚³ãƒ³ãƒ?ƒ³ãƒ?‚¿ã‚¤ãƒ—ã‚’å–り出ã—ã¾ã™ã? 282 * 283 * アドレスåã‹ã‚‰ã?ファイル拡張åã‚’å–り出ã—ã?対応ã™ã‚‹ã‚³ãƒ³ãƒ?ƒ³ãƒ?‚¿ã‚¤ãƒ—ã‚’è¿”ã—ã¾ã™ã? 284 * コンãƒ?ƒ³ãƒ?‚¿ã‚¤ãƒ—ã?ã€CONTENT_TYPE_TABLE é…å?ã«å®šç¾©ã—ã¦ã?‚‹ä¸ã‹ã‚‰æ¤œç´¢ã—ã¦è¿”ã—ã¾ã™ã? 285 * å˜åœ¨ã—ãªã??åˆã?ã€?application/octet-stream" ã‚’è¿”ã—ã¾ã™ã? 286 * 287 * @param fileAddress アドレスå? 288 * 289 * @return コンãƒ?ƒ³ãƒ?‚¿ã‚¤ãƒ? 290 */ 291 private String getContentType( final String fileAddress ) { 292 String extention = getExtention( fileAddress ); 293 for( int j=0; j<CONTENT_TYPE_TABLE.length; j++ ) { 294 if( CONTENT_TYPE_TABLE[j][EXTENTION].equalsIgnoreCase( extention ) ) { 295 return CONTENT_TYPE_TABLE[j][CONTENT_TYPE]; 296 } 297 } 298 return "application/octet-stream"; 299 } 300 }