📄 attachmentservlet.java
字号:
* * @param ctx WikiContext; required to access the ServletContext of the request. * @param fileName The name to check for. * @return A valid mime type, or application/binary, if not recognized */ private static String getMimeType(WikiContext ctx, String fileName ) { String mimetype = null; HttpServletRequest req = ctx.getHttpRequest(); if( req != null ) { ServletContext s = req.getSession().getServletContext(); if( s != null ) { mimetype = s.getMimeType( fileName.toLowerCase() ); } } if( mimetype == null ) { mimetype = "application/binary"; } return mimetype; } /** * Grabs mime/multipart data and stores it into the temporary area. * Uses other parameters to determine which name to store as. * * <p>The input to this servlet is generated by an HTML FORM with * two parts. The first, named 'page', is the WikiName identifier * for the parent file. The second, named 'content', is the binary * content of the file. * * {@inheritDoc} */ public void doPost( HttpServletRequest req, HttpServletResponse res ) throws IOException, ServletException { try { String nextPage = upload( req ); req.getSession().removeAttribute("msg"); res.sendRedirect( nextPage ); } catch( RedirectException e ) { WikiSession session = WikiSession.getWikiSession( m_engine, req ); session.addMessage( e.getMessage() ); req.getSession().setAttribute("msg", e.getMessage()); res.sendRedirect( e.getRedirect() ); } } /** * {@inheritDoc} */ public void doPut( HttpServletRequest req, HttpServletResponse res ) throws IOException, ServletException { String errorPage = m_engine.getURL( WikiContext.ERROR, "", null, false ); // If something bad happened, Upload should be able to take care of most stuff String p = new String(req.getPathInfo().getBytes("ISO-8859-1"), "UTF-8"); DavPath path = new DavPath( p ); try { InputStream data = req.getInputStream(); WikiContext context = m_engine.createContext( req, WikiContext.UPLOAD ); String wikipage = path.get( 0 ); errorPage = context.getURL( WikiContext.UPLOAD, wikipage ); String changeNote = null; // FIXME: Does not quite work boolean created = executeUpload( context, data, path.getName(), errorPage, wikipage, changeNote, req.getContentLength() ); if( created ) res.sendError( HttpServletResponse.SC_CREATED ); else res.sendError( HttpServletResponse.SC_OK ); } catch( ProviderException e ) { res.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage() ); } catch( RedirectException e ) { res.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage() ); } } /** * Validates the next page to be on the same server as this webapp. * Fixes [JSPWIKI-46]. */ private String validateNextPage( String nextPage, String errorPage ) { if( nextPage.indexOf("://") != -1 ) { // It's an absolute link, so unless it starts with our address, we'll // log an error. if( !nextPage.startsWith( m_engine.getBaseURL() ) ) { log.warn("Detected phishing attempt by redirecting to an unsecure location: "+nextPage); nextPage = errorPage; } } return nextPage; } /** * Uploads a specific mime multipart input set, intercepts exceptions. * * @param req The servlet request * @return The page to which we should go next. * @throws RedirectException If there's an error and a redirection is needed * @throws IOException If upload fails * @throws FileUploadException */ @SuppressWarnings("unchecked") protected String upload( HttpServletRequest req ) throws RedirectException, IOException { String msg = ""; String attName = "(unknown)"; String errorPage = m_engine.getURL( WikiContext.ERROR, "", null, false ); // If something bad happened, Upload should be able to take care of most stuff String nextPage = errorPage; String progressId = req.getParameter( "progressid" ); // Check that we have a file upload request if( !ServletFileUpload.isMultipartContent(req) ) { throw new RedirectException( "Not a file upload", errorPage ); } try { FileItemFactory factory = new DiskFileItemFactory(); // Create the context _before_ Multipart operations, otherwise // strict servlet containers may fail when setting encoding. WikiContext context = m_engine.createContext( req, WikiContext.ATTACH ); UploadListener pl = new UploadListener(); m_engine.getProgressManager().startProgress( pl, progressId ); ServletFileUpload upload = new ServletFileUpload(factory); upload.setHeaderEncoding("UTF-8"); upload.setFileSizeMax( m_maxSize ); upload.setProgressListener( pl ); List<FileItem> items = upload.parseRequest( req ); String wikipage = null; String changeNote = null; FileItem actualFile = null; for( FileItem item : items ) { if( item.isFormField() ) { if( item.getFieldName().equals("page") ) { // // FIXME: Kludge alert. We must end up with the parent page name, // if this is an upload of a new revision // wikipage = item.getString("UTF-8"); int x = wikipage.indexOf("/"); if( x != -1 ) wikipage = wikipage.substring(0,x); } else if( item.getFieldName().equals("changenote") ) { changeNote = item.getString("UTF-8"); } else if( item.getFieldName().equals( "nextpage" ) ) { nextPage = validateNextPage( item.getString("UTF-8"), errorPage ); } } else { actualFile = item; } } if( actualFile == null ) throw new RedirectException( "Broken file upload", errorPage ); // // FIXME: Unfortunately, with Apache fileupload we will get the form fields in // order. This means that we have to gather all the metadata from the // request prior to actually touching the uploaded file itself. This // is because the changenote appears after the file upload box, and we // would not have this information when uploading. This also means // that with current structure we can only support a single file upload // at a time. // String filename = actualFile.getName(); long fileSize = actualFile.getSize(); InputStream in = actualFile.getInputStream(); try { executeUpload( context, in, filename, nextPage, wikipage, changeNote, fileSize ); } finally { in.close(); } } catch( ProviderException e ) { msg = "Upload failed because the provider failed: "+e.getMessage(); log.warn( msg + " (attachment: " + attName + ")", e ); throw new IOException(msg); } catch( IOException e ) { // Show the submit page again, but with a bit more // intimidating output. msg = "Upload failure: " + e.getMessage(); log.warn( msg + " (attachment: " + attName + ")", e ); throw e; } catch (FileUploadException e) { // Show the submit page again, but with a bit more // intimidating output. msg = "Upload failure: " + e.getMessage(); log.warn( msg + " (attachment: " + attName + ")", e ); throw new IOException( msg ); } finally { m_engine.getProgressManager().stopProgress( progressId ); // FIXME: In case of exceptions should absolutely // remove the uploaded file. } return nextPage; } /** * * @param context the wiki context * @param data the input stream data * @param filename the name of the file to upload * @param errorPage the place to which you want to get a redirection * @param parentPage the page to which the file should be attached * @param changenote The change note * @param contentLength The content length * @return <code>true</code> if upload results in the creation of a new page; * <code>false</code> otherwise * @throws RedirectException If the content needs to be redirected * @throws IOException If there is a problem in the upload. * @throws ProviderException If there is a problem in the backend. */ protected boolean executeUpload( WikiContext context, InputStream data, String filename, String errorPage, String parentPage, String changenote, long contentLength ) throws RedirectException, IOException, ProviderException { boolean created = false; try { filename = AttachmentManager.validateFileName( filename ); } catch( WikiException e ) { // this is a kludge, the exception that is caught here contains the i18n key // here we have the context available, so we can internationalize it properly : throw new RedirectException(context.getBundle( InternationalizationManager.CORE_BUNDLE ).getString( e.getMessage() ), errorPage ); } // // FIXME: This has the unfortunate side effect that it will receive the // contents. But we can't figure out the page to redirect to // before we receive the file, due to the stupid constructor of MultipartRequest. // if( !context.hasAdminPermissions() ) { if( contentLength > m_maxSize ) { // FIXME: Does not delete the received files. throw new RedirectException( "File exceeds maximum size ("+m_maxSize+" bytes)", errorPage ); } if( !isTypeAllowed(filename) ) { throw new RedirectException( "Files of this type may not be uploaded to this wiki", errorPage ); } } Principal user = context.getCurrentUser(); AttachmentManager mgr = m_engine.getAttachmentManager(); log.debug("file="+filename); if( data == null ) { log.error("File could not be opened."); throw new RedirectException("File could not be opened.", errorPage); } // // Check whether we already have this kind of a page. // If the "page" parameter already defines an attachment // name for an update, then we just use that file. // Otherwise we create a new attachment, and use the // filename given. Incidentally, this will also mean // that if the user uploads a file with the exact // same name than some other previous attachment, // then that attachment gains a new version. // Attachment att = mgr.getAttachmentInfo( context.getPage().getName() ); if( att == null ) { att = new Attachment( m_engine, parentPage, filename ); created = true; } att.setSize( contentLength ); // // Check if we're allowed to do this? // Permission permission = PermissionFactory.getPagePermission( att, "upload" ); if( m_engine.getAuthorizationManager().checkPermission( context.getWikiSession(), permission ) ) { if( user != null ) { att.setAuthor( user.getName() ); } if( changenote != null && changenote.length() > 0 ) { att.setAttribute( WikiPage.CHANGENOTE, changenote ); } try { m_engine.getAttachmentManager().storeAttachment( att, data ); } catch (ProviderException pe) { // this is a kludge, the exception that is caught here contains the i18n key // here we have the context available, so we can internationalize it properly : throw new ProviderException( context.getBundle( InternationalizationManager.CORE_BUNDLE ).getString( pe.getMessage() ) ); } log.info( "User " + user + " uploaded attachment to " + parentPage + " called "+filename+", size " + att.getSize() ); } else { throw new RedirectException("No permission to upload a file", errorPage); } return created; } /** * Provides tracking for upload progress. * * @author Janne Jalkanen */ private static class UploadListener extends ProgressItem implements ProgressListener { public long m_currentBytes; public long m_totalBytes; public String m_uid; public void update(long recvdBytes, long totalBytes, int item) { m_currentBytes = recvdBytes; m_totalBytes = totalBytes; } public int getProgress() { return (int) (((float)m_currentBytes / m_totalBytes) * 100 + 0.5); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -