2013-08-06 78 views
5

Struts 2.3.15.1の使用struts2ファイルアップロードの緩和パラメータ

struts2でのファイルアップロードの実装。これは何度も何度もやったことですが、いくつかのサニティチェック(主に最大ファイルサイズ)を含めるようにしています。 fileUploadインターセプタがスタック内の最後のインターセプタ(すなわち、struts.xml)に配置されています。私のスタックには、いくつかの社内インターセプタと、validationWorkflowStackが含まれています。私は私の形でいくつかの他のparamsを渡している、ファイルのアップロードに加えて

struts.multipart.maxSize = 2000000 

:私は私のstruts.propertiesファイルに次のプロパティを設定しました。フォームは次のように定義されています。私は、我々はすべて知っていると確信しているとして

<s:form action="addResource" method="post" enctype="multipart/form-data"> 
    <s:hidden name="rfqId" value='%{rfq.id}' /> 
    <s:file name="uploadFile" id="uploadFile" label="File" size="40" value=""/> 
    .... 
</s:form> 

validationWorkflowStackは、アクションにリクエストパラメータを設定しますのparamsインターセプタを、含まれています。アップロードするファイルがmaxSizeを超えると、のパラメータインターセプタを設定するパラメータがありません。私はステップインしており、actionContextには何もありません。これは結果的に起こるINPUTエラーを処理するためにこれらのパラメータが必要なので、これは良くありません。

は、私は何かが足りないのですか?

+0

あなたのスタック内の最後のインターセプタとして 'fileUpload'インターセプタを含むように任意の理由は? –

+0

別の場所とは対照的に、またはまったく同じではありませんか?今はデフォルトのスタックなどになっていますか?それが価値あるものであれば、私はインターセプターの最初/中/最後/ etcを無駄にすることを試みました。 – fmpdmb

+0

「defaultStack」のように、最初のものや中間のものとは対照的です。インターセプタの順序は重要です。 'fileUpload'は' defaultStack'にありますが 'basicStack'にはありません。 –

答えて

5

問題が解決しました。 updated documentationから

は、今の問題は、新しいJakartaStreamMultiPartRequestを使用することによって解決することができます。MultiPartRequest の新しい実装が追加された

Strutsのバージョン2.3.18 からのよう - JakartaStreamMultiPartRequest。 大きなファイルを扱う詳細はWW-3025を確認するために使用することができますが、簡単なセットstruts.xmlで

<constant name="struts.multipart.parser" value="jakarta-stream" /> 

は、それを使用して起動することができます。

連結JIRA本体から:任意のサイズ制限を超えた場合

、直ちに FileUploadBase.SizeLimitExceededException又は FileUploadBase.FileSizeLimitExceededExceptionがスローと の解析は、マルチパートリクエストは、リクエストパラメータを提供せずに終了する さらなる処理のために。

これは、基本的にどのWebアプリケーションでも のサイズ制限を上回って処理することを不可能にします。

私の提案では、リクエストの解析は常に リクエストパラメータを送信するように完了する必要があります。サイズ制限を超えたケース/例外は、後で取得するために が収集される可能性があります。 はFileItemにマップされ、 アプリケーションレベルのFileItemで検証されます。これにより、アップロードされたファイルが大きすぎる場合に、アップロード入力フィールドを と誤ってマークすることができます。

実際に私はそのためのパッチを作成しました(添付ファイルを参照)。このパッチを使用すると、 commons-fileuploadは、サイズが の場合には常に解析を完了し、完全な解析後には、検出された場合には 例外がスローされます。

とクリスクランフォードさんのコメント:私はStruts2のための新しいマルチパートパーサに取り組んでいます

私は JakartaStreamMultiPartRequestを呼び出しています。

このマルチパートパーサが、それはコモンズのFileUploadストリーミング APIを使用してではなく、ファイル アップロードAPIへのリクエストの最大サイズチェックを委任することを除いて、既存のジャカルタ マルチパートパーサと同じ振る舞い、それを避けるために内部的に行われます アップロードAPIの既存の問題は、ループの反復を破り、パラメータが失われています。

素晴らしい、おかげでみんな:)


旧答え

私はそれが

  • 単一のファイル(または複数のファイルの異なる振る舞いが原因だと思います)が定義された最大サイズを超えている場合、INPUT rを使用して通常のプロセスの最後にリダイレクトされます
  • 要求全体の最大サイズの違反は、セキュリティメカニズムであり、ファイルサイズのチェックのような機能ではないため、他の要素の解析を中断します(おそらく?)。

ファイルが最初に解析されたファイルがマルチパート要求サイズの制限を破る場合(it should depend on their order in the page)、他のフィールド(フォームフィールド)が読み出せなく、したがって入力結果と戻さないとき。 MultiPartRequestWrapperため

Struts2 uses the Jakarta implementation

struts.multipart.parser - このプロパティはMultiPartRequestを拡張するクラスに設定する必要があります。現在、フレームワークには、Jakarta FileUploadの実装が付属しています。

ソースコードは、Struts2公式サイトor here(Googleより高速)で見つけることができます。これは、マルチパートフォームを投稿するときに呼ばれているものです。

public void parse(HttpServletRequest request, String saveDir) throws IOException { 
     try { 
      setLocale(request); 
      processUpload(request, saveDir); 
     } catch (FileUploadBase.SizeLimitExceededException e) { 
      if (LOG.isWarnEnabled()) { 
       LOG.warn("Request exceeded size limit!", e); 
      } 
      String errorMessage = buildErrorMessage(e, new Object[]{e.getPermittedSize(), e.getActualSize()}); 
      if (!errors.contains(errorMessage)) { 
       errors.add(errorMessage); 
      } 
     } catch (Exception e) { 
      if (LOG.isWarnEnabled()) { 
       LOG.warn("Unable to parse request", e); 
      } 
      String errorMessage = buildErrorMessage(e, new Object[]{}); 
      if (!errors.contains(errorMessage)) { 
       errors.add(errorMessage); 
      } 
     } 
    } 

ところ、それはサイクルマルチアイテム、ファイルやフォームフィールドの両方そして、これは次のとおりです。終了します

private void processUpload(HttpServletRequest request, String saveDir) throws FileUploadException, UnsupportedEncodingException { 
     for (FileItem item : parseRequest(request, saveDir)) { 
      if (LOG.isDebugEnabled()) { 
       LOG.debug("Found item " + item.getFieldName()); 
      } 
      if (item.isFormField()) { 
       processNormalFormField(item, request.getCharacterEncoding()); 
      } else { 
       processFileField(item); 
      } 
     } 
    } 

FileUploadBaseに、各項目のこの実装では:

FileItemStreamImpl(String pName, String pFieldName, 
        String pContentType, boolean pFormField, 
        long pContentLength) throws IOException { 
       name = pName; 
       fieldName = pFieldName; 
       contentType = pContentType; 
       formField = pFormField; 
       final ItemInputStream itemStream = multi.newInputStream(); 
       InputStream istream = itemStream; 
       if (fileSizeMax != -1) { 
        if (pContentLength != -1 
          && pContentLength > fileSizeMax) { 
         FileSizeLimitExceededException e = 
          new FileSizeLimitExceededException(
           format("The field %s exceeds its maximum permitted size of %s bytes.", 
             fieldName, fileSizeMax), 
           pContentLength, fileSizeMax); 
         e.setFileName(pName); 
         e.setFieldName(pFieldName); 
         throw new FileUploadIOException(e); 
        } 
        istream = new LimitedInputStream(istream, fileSizeMax) { 
         @Override 
         protected void raiseError(long pSizeMax, long pCount) 
           throws IOException { 
          itemStream.close(true); 
          FileSizeLimitExceededException e = 
           new FileSizeLimitExceededException(
            format("The field %s exceeds its maximum permitted size of %s bytes.", 
              fieldName, pSizeMax), 
            pCount, pSizeMax); 
          e.setFieldName(fieldName); 
          e.setFileName(name); 
          throw new FileUploadIOException(e); 
         } 
        }; 
       } 
       stream = istream; 
      } 

ご覧のとおり、ファイルサイズの上限と要求サイズの上限はかなり異なっています。

私は楽しいソースを見てきましたが、実際に何が起こっているのかを確認するためにMultiPartRequestWrapperをデバッグしようとすると、この仮定を確認(または修正)することができます。楽しい

+2

私は知っていたことについての説明ではなく、ここに提案は表示されません。 MultiPartRequestの実装では、アクションエラーが追加され、他のフォーム変数を処理する前に救済されています。フローはインターセプタスタックを続けて行き、問題を引き起こします。私の試みた解決策は、ファイルのアップロードを最初に行い、エラーが存在する場合にはワークフローインターセプタによってそれをフォローし、ユニークな結果のタイプを持つことで、リクエストパラメタを失ってしまったため、 – fmpdmb

+0

** IF **これは何が起こっているのか(セキュリティ上の理由によりリクエストが切断されている)** THEN **あなたができることは何もありません。一度ヒットすると、制限を設定しなくてもリクエストがカットされます(これはデフォルトの制限になります)。そうでない場合は、理由と方法を説明します。私はそれがそうであることを100%確信しているわけではなく、ソースコードを見ることによってそれがそうであると確信しているだけです。すべての質問が「提案」で答えられるわけではありませんが、それがそうであれば、これは正しい答えです。唯一の提案は、HTML5の方法でクライアント側のファイルサイズを確認することです。 –

+0

私が思いついた解決策は、この時点でうまくいくようです。 – fmpdmb

1

この問題を回避する方法は次のとおりです。私はこれを解決策と呼んでいません。

enter image description here

0

早い段階でのJavaScriptのチェックを入れてみてください:

<!DOCTYPE html> 
<html> 

    <head> 
    <script type="text/javascript"> 
    function checkSize(max_img_size) 
    { 
     var input = document.getElementById("upload"); 
     // check for browser support (may need to be modified) 
     if(input.files && input.files.length == 1) 
     {   
      if (input.files[0].size > max_img_size) 
      { 
       alert("The file must be less than " + (max_img_size/1024/1024) + "MB"); 
       return false; 
      } 
     } 

     return true; 
    } 
    </script> 
    </head> 
    <body> 
    <form action="demo_post_enctype.asp" method="post" enctype="multipart/form-data" 
    onsubmit="return checkSize(2097152)">  
    <input type="file" id="upload" /> 
    <input type="submit" /> 

    </body> 
    </html> 
関連する問題