1 module hunt.http.codec.http.model.MultiPartContentProvider;
2
3 // import hunt.util.Common;
4 // import hunt.http.utils.exception.CommonRuntimeException;
5 import hunt.logging;
6
7 import hunt.io.ByteBuffer;
8
9 // import java.io.ByteArrayOutputStream;
10 // import java.io.Closeable;
11 // module hunt.Exceptions;
12 // import java.nio.charset.StandardCharsets;
13 // import java.util;
14 // import hunt.concurrency.atomic.AtomicBoolean;
15
16 /**
17 *
18 */
19 // class MultiPartContentProvider :AbstractTypedContentProvider : AsyncContentProvider, Closeable {
20
21
22 // private static byte[] COLON_SPACE_BYTES = new byte[]{':', ' '};
23 // private static byte[] CR_LF_BYTES = new byte[]{'\r', '\n'};
24
25 // private List<Part> parts = new ArrayList<>();
26 // private ByteBuffer firstBoundary;
27 // private ByteBuffer middleBoundary;
28 // private ByteBuffer onlyBoundary;
29 // private ByteBuffer lastBoundary;
30 // private AtomicBoolean closed = new AtomicBoolean();
31 // private Listener listener;
32 // private long length = -1;
33
34 // MultiPartContentProvider() {
35 // this(makeBoundary());
36 // }
37
38 // MultiPartContentProvider(string boundary) {
39 // super("multipart/form-data; boundary=" + boundary);
40 // string firstBoundaryLine = "--" + boundary + "\r\n";
41 // this.firstBoundary = BufferUtils.toBuffer(firstBoundaryLine.getBytes(StandardCharsets.US_ASCII));
42 // string middleBoundaryLine = "\r\n" + firstBoundaryLine;
43 // this.middleBoundary = BufferUtils.toBuffer(middleBoundaryLine.getBytes(StandardCharsets.US_ASCII));
44 // string onlyBoundaryLine = "--" + boundary + "--\r\n";
45 // this.onlyBoundary = BufferUtils.toBuffer(onlyBoundaryLine.getBytes(StandardCharsets.US_ASCII));
46 // string lastBoundaryLine = "\r\n" + onlyBoundaryLine;
47 // this.lastBoundary = BufferUtils.toBuffer(lastBoundaryLine.getBytes(StandardCharsets.US_ASCII));
48 // }
49
50 // private static string makeBoundary() {
51 // Random random = new Random();
52 // StringBuilder builder = new StringBuilder("HuntHttpClientBoundary");
53 // int length = builder.length();
54 // while (builder.length() < length + 16) {
55 // long rnd = random.nextLong();
56 // builder.append(to!long(rnd < 0 ? -rnd : rnd, 36));
57 // }
58 // builder.setLength(length + 16);
59 // return builder.toString();
60 // }
61
62 // /**
63 // * <p>Adds a field part with the given {@code name} as field name, and the given
64 // * {@code content} as part content.</p>
65 // *
66 // * @param name the part name
67 // * @param content the part content
68 // * @param fields the headers associated with this part
69 // */
70 // void addFieldPart(string name, ContentProvider content, HttpFields fields) {
71 // addPart(new Part(name, null, "text/plain", content, fields));
72 // }
73
74 // /**
75 // * <p>Adds a file part with the given {@code name} as field name, the given
76 // * {@code fileName} as file name, and the given {@code content} as part content.</p>
77 // *
78 // * @param name the part name
79 // * @param fileName the file name associated to this part
80 // * @param content the part content
81 // * @param fields the headers associated with this part
82 // */
83 // void addFilePart(string name, string fileName, ContentProvider content, HttpFields fields) {
84 // addPart(new Part(name, fileName, "application/octet-stream", content, fields));
85 // }
86
87 // private void addPart(Part part) {
88 // parts.add(part);
89 // version(HUNT_DEBUG)
90 // tracef("Added %s", part);
91 // }
92
93 // override
94 // void setListener(Listener listener) {
95 // this.listener = listener;
96 // if (closed.get())
97 // this.length = calculateLength();
98 // }
99
100 // private long calculateLength() {
101 // // Compute the length, if possible.
102 // if (parts.isEmpty()) {
103 // return onlyBoundary.remaining();
104 // } else {
105 // long result = 0;
106 // for (int i = 0; i < parts.size(); ++i) {
107 // result += (i == 0) ? firstBoundary.remaining() : middleBoundary.remaining();
108 // Part part = parts.get(i);
109 // long partLength = part.length;
110 // result += partLength;
111 // if (partLength < 0) {
112 // result = -1;
113 // break;
114 // }
115 // }
116 // if (result > 0)
117 // result += lastBoundary.remaining();
118 // return result;
119 // }
120 // }
121
122 // override
123 // long getLength() {
124 // return length;
125 // }
126
127 // override
128 // Iterator!ByteBuffer iterator() {
129 // return new MultiPartIterator();
130 // }
131
132 // override
133 // void close() {
134 // closed.compareAndSet(false, true);
135 // }
136
137 // private static class Part {
138 // private string name;
139 // private string fileName;
140 // private string contentType;
141 // private ContentProvider content;
142 // private HttpFields fields;
143 // private ByteBuffer headers;
144 // private long length;
145
146 // private Part(string name, string fileName, string contentType, ContentProvider content, HttpFields fields) {
147 // this.name = name;
148 // this.fileName = fileName;
149 // this.contentType = contentType;
150 // this.content = content;
151 // this.fields = fields;
152 // this.headers = headers();
153 // this.length = content.getLength() < 0 ? -1 : headers.remaining() + content.getLength();
154 // }
155
156 // private ByteBuffer headers() {
157 // try {
158 // // Compute the Content-Disposition.
159 // string contentDisposition = "Content-Disposition: form-data; name=\"" + name + "\"";
160 // if (fileName != null)
161 // contentDisposition += "; filename=\"" + fileName + "\"";
162 // contentDisposition += "\r\n";
163
164 // // Compute the Content-Type.
165 // string contentType = fields == null ? null : fields.get(HttpHeader.CONTENT_TYPE);
166 // if (contentType == null) {
167 // if (content instanceof Typed)
168 // contentType = ((Typed) content).getContentType();
169 // else
170 // contentType = this.contentType;
171 // }
172 // contentType = "Content-Type: " + contentType + "\r\n";
173
174 // if (fields == null || fields.size() == 0) {
175 // string headers = contentDisposition;
176 // headers += contentType;
177 // headers += "\r\n";
178 // return BufferUtils.toBuffer(headers.getBytes(StandardCharsets.UTF_8));
179 // }
180
181 // ByteArrayOutputStream buffer = new ByteArrayOutputStream((fields.size() + 1) * contentDisposition.length());
182 // buffer.write(contentDisposition.getBytes(StandardCharsets.UTF_8));
183 // buffer.write(contentType.getBytes(StandardCharsets.UTF_8));
184 // for (HttpField field : fields) {
185 // if (HttpHeader.CONTENT_TYPE.equals(field.getHeader()))
186 // continue;
187 // buffer.write(field.getName().getBytes(StandardCharsets.US_ASCII));
188 // buffer.write(COLON_SPACE_BYTES);
189 // string value = field.getValue();
190 // if (value != null)
191 // buffer.write(value.getBytes(StandardCharsets.UTF_8));
192 // buffer.write(CR_LF_BYTES);
193 // }
194 // buffer.write(CR_LF_BYTES);
195 // return BufferUtils.toBuffer(buffer.toByteArray());
196 // } catch (IOException x) {
197 // throw new CommonRuntimeException(x);
198 // }
199 // }
200
201 // override
202 // string toString() {
203 // return format("%s@%x[name=%s,fileName=%s,length=%d,headers=%s]",
204 // typeof(this).stringof,
205 // toHash(),
206 // name,
207 // fileName,
208 // content.getLength(),
209 // fields);
210 // }
211 // }
212
213 // private class MultiPartIterator : Iterator!ByteBuffer, Synchronizable, Callback, Closeable {
214 // private Iterator!ByteBuffer iterator;
215 // private int index;
216 // private State state = State.FIRST_BOUNDARY;
217
218 // override
219 // bool hasNext() {
220 // return state != State.COMPLETE;
221 // }
222
223 // override
224 // ByteBuffer next() {
225 // while (true) {
226 // switch (state) {
227 // case FIRST_BOUNDARY: {
228 // if (parts.isEmpty()) {
229 // state = State.COMPLETE;
230 // return onlyBoundary.slice();
231 // } else {
232 // state = State.HEADERS;
233 // return firstBoundary.slice();
234 // }
235 // }
236 // case HEADERS: {
237 // Part part = parts.get(index);
238 // ContentProvider content = part.content;
239 // if (content instanceof AsyncContentProvider)
240 // ((AsyncContentProvider) content).setListener(listener);
241 // iterator = content.iterator();
242 // state = State.CONTENT;
243 // return part.headers.slice();
244 // }
245 // case CONTENT: {
246 // if (iterator.hasNext())
247 // return iterator.next();
248 // ++index;
249 // if (index == parts.size())
250 // state = State.LAST_BOUNDARY;
251 // else
252 // state = State.MIDDLE_BOUNDARY;
253 // break;
254 // }
255 // case MIDDLE_BOUNDARY: {
256 // state = State.HEADERS;
257 // return middleBoundary.slice();
258 // }
259 // case LAST_BOUNDARY: {
260 // state = State.COMPLETE;
261 // return lastBoundary.slice();
262 // }
263 // case COMPLETE: {
264 // throw new NoSuchElementException();
265 // }
266 // }
267 // }
268 // }
269
270 // override
271 // Object getLock() {
272 // if (iterator instanceof Synchronizable)
273 // return ((Synchronizable) iterator).getLock();
274 // return this;
275 // }
276
277 // override
278 // void succeeded() {
279 // if (iterator instanceof Callback)
280 // ((Callback) iterator).succeeded();
281 // }
282
283 // override
284 // void failed(Exception x) {
285 // if (iterator instanceof Callback)
286 // ((Callback) iterator).failed(x);
287 // }
288
289 // override
290 // void close() throws IOException {
291 // if (iterator instanceof Closeable)
292 // ((Closeable) iterator).close();
293 // }
294 // }
295
296 // private enum State {
297 // FIRST_BOUNDARY, HEADERS, CONTENT, MIDDLE_BOUNDARY, LAST_BOUNDARY, COMPLETE
298 // }
299 // }