View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.util;
20  
21  import java.io.FilterOutputStream;
22  import java.io.IOException;
23  import java.io.OutputStream;
24  import java.nio.charset.StandardCharsets;
25  
26  
27  /** Handle a multipart MIME response.
28   *
29   * 
30   * 
31  */
32  public class MultiPartOutputStream extends FilterOutputStream
33  {
34      /* ------------------------------------------------------------ */
35      private static final byte[] __CRLF={'\r','\n'};
36      private static final byte[] __DASHDASH={'-','-'};
37      
38      public static final String MULTIPART_MIXED="multipart/mixed";
39      public static final String MULTIPART_X_MIXED_REPLACE="multipart/x-mixed-replace";
40      
41      /* ------------------------------------------------------------ */
42      private final String boundary;
43      private final byte[] boundaryBytes;
44  
45      /* ------------------------------------------------------------ */
46      private boolean inPart=false;    
47      
48      /* ------------------------------------------------------------ */
49      public MultiPartOutputStream(OutputStream out)
50      throws IOException
51      {
52          super(out);
53  
54          boundary = "jetty"+System.identityHashCode(this)+
55          Long.toString(System.currentTimeMillis(),36);
56          boundaryBytes=boundary.getBytes(StandardCharsets.ISO_8859_1);
57      }
58  
59      public MultiPartOutputStream(OutputStream out, String boundary)
60           throws IOException
61      {
62          super(out);
63  
64          this.boundary = boundary;
65          boundaryBytes=boundary.getBytes(StandardCharsets.ISO_8859_1);
66      }
67  
68      /* ------------------------------------------------------------ */
69      /** End the current part.
70       * @exception IOException IOException
71       */
72      @Override
73      public void close()
74           throws IOException
75      {
76          try
77          {
78              if (inPart)
79                  out.write(__CRLF);
80              out.write(__DASHDASH);
81              out.write(boundaryBytes);
82              out.write(__DASHDASH);
83              out.write(__CRLF);
84              inPart=false;
85          }
86          finally
87          {
88              super.close();
89          }
90      }
91      
92      /* ------------------------------------------------------------ */
93      public String getBoundary()
94      {
95          return boundary;
96      }
97  
98      public OutputStream getOut() {return out;}
99      
100     /* ------------------------------------------------------------ */
101     /** Start creation of the next Content.
102      * @param contentType the content type of the part
103      * @throws IOException if unable to write the part
104      */
105     public void startPart(String contentType)
106          throws IOException
107     {
108         if (inPart)
109             out.write(__CRLF);
110         inPart=true;
111         out.write(__DASHDASH);
112         out.write(boundaryBytes);
113         out.write(__CRLF);
114         if (contentType != null)
115             out.write(("Content-Type: "+contentType).getBytes(StandardCharsets.ISO_8859_1));
116         out.write(__CRLF);
117         out.write(__CRLF);
118     }
119         
120     /* ------------------------------------------------------------ */
121     /** Start creation of the next Content.
122      * @param contentType the content type of the part
123      * @param headers the part headers
124      * @throws IOException if unable to write the part
125      */
126     public void startPart(String contentType, String[] headers)
127          throws IOException
128     {
129         if (inPart)
130             out.write(__CRLF);
131         inPart=true;
132         out.write(__DASHDASH);
133         out.write(boundaryBytes);
134         out.write(__CRLF);
135         if (contentType != null)
136             out.write(("Content-Type: "+contentType).getBytes(StandardCharsets.ISO_8859_1));
137         out.write(__CRLF);
138         for (int i=0;headers!=null && i<headers.length;i++)
139         {
140             out.write(headers[i].getBytes(StandardCharsets.ISO_8859_1));
141             out.write(__CRLF);
142         }
143         out.write(__CRLF);
144     }
145 
146     /* ------------------------------------------------------------ */
147     @Override
148     public void write(byte[] b, int off, int len) throws IOException
149     {
150         out.write(b,off,len);
151     }
152 }
153 
154 
155 
156