docs: public Iterable<MultiPart> parts() throws IOException {
          if (!isMultipart()) return emptyIterable;
          final String boundarystr = "--" + this.boundary;
          final Pattern fielnameReg = this.fielnamePattern;
          final String endboundary = boundarystr + "--";
          final byte[] boundarray = ("\n" + boundarystr).getBytes();
          final byte[] buffer = new byte[boundarray.length];
          final InputStream input = this.in;
          final DefaultAnyValue params = this.parameters;
          final AtomicBoolean finaled = new AtomicBoolean(false);
          return () -> new Iterator<MultiPart>() {
  
              private String boundaryline;
  
              private MultiPart lastentry;
  
              @Override
              public boolean hasNext() {
                  try {
                      if (lastentry != null) {
                          lastentry.skip();
                          if (finaled.get()) return false;
                      }
                      if (boundaryline == null) boundaryline = readBoundary();
                      //if (debug) System.out.print("boundaryline=" + boundaryline + "  ");
                      if (endboundary.equals(boundaryline) || !boundarystr.equals(boundaryline)) { //结尾或异常
                          lastentry = null;
                          return false;
                      }
                      final String disposition = readLine();
                      //if (debug) System.out.println("disposition=" + disposition);
                      if (disposition.contains("; filename=\"")) { //是上传文件
                          String contentType = "";
                          //读掉HTTP Header和空白行 通常情况下Content-Type后面就是内容，但是有些特殊情况下后面会跟其他如Content-Length: xxx等HTTP header，所以需要循环读取
                          String rl;
                          while (!(rl = readLine()).isEmpty()) {
                              if (rl.startsWith("Content-Type:")) contentType = rl.substring(rl.indexOf(':') + 1).trim();
                          }
                          //if (debug) System.out.println("file.contentType=" + contentType);
  
                          String name = parseValue(disposition, "name");
                          String filename = parseValue(disposition, "filename");
                          if (filename == null || filename.isEmpty()) { //没有上传
                              readLine(); //读掉空白行
                              this.boundaryline = null;
                              this.lastentry = null;
                              return this.hasNext();
                          } else {
                              int p1 = filename.lastIndexOf('/');
                              if (p1 < 0) p1 = filename.lastIndexOf('\\');
                              if (p1 >= 0) filename = filename.substring(p1 + 1);
                          }
                          final AtomicLong counter = new AtomicLong(0);
                          InputStream source = new InputStream() {
  
                              private int bufposition = buffer.length;
  
                              private boolean end;
  
                              @Override
                              public int read() throws IOException {
                                  if (end) return -1;
                                  final byte[] buf = buffer;
                                  int ch = (this.bufposition < buf.length) ? (buf[this.bufposition++] & 0xff) : input.read();
                                  if ((ch == '\r' && readBuffer())) return -1;
                                  counter.incrementAndGet();
                                  return ch;
                              }
  
                              private boolean readBuffer() throws IOException {
                                  final byte[] buf = buffer;
                                  final int pos = this.bufposition;
                                  int s = 0;
                                  for (int i = pos; i < buf.length; i++) {
                                      buf[s++] = buf[i];
                                  }
                                  int readed = 0;
                                  while ((readed += input.read(buf, s + readed, pos - readed)) != pos);
                                  this.bufposition = 0;
                                  if (Arrays.equals(boundarray, buf)) {
                                      this.end = true;
                                      int c1 = input.read();
                                      int c2 = input.read();
                                      finaled.set(c1 == '-' && c2 == '-');
                                      return true;
                                  }
                                  return false;
                              }
  
                              @Override
                              public long skip(long count) throws IOException {
                                  if (end) return -1;
                                  if (count <= 0) return 0;
                                  long s = 0;
                                  while (read() != -1) {
                                      s++;
                                      if (--count <= 0) break;
                                  }
                                  return s;
                              }
                          };
                          this.lastentry = new MultiPart(filename, name, contentType, counter, source);
                          if (fielnameReg != null && !fielnameReg.matcher(filename).matches()) {
                              return this.hasNext();
                          }
                          return true;
                      } else { //不是文件
                          readLine(); //读掉空白
                          params.addValue(parseValue(disposition, "name"), readLine());
                          this.boundaryline = null;
                          this.lastentry = null;
                          return this.hasNext();
                      }
                  } catch (IOException ex) {
                      logger.log(Level.FINER, "list multiparts abort", ex);
                      return false;
                  }
              }
  
              @Override
              public MultiPart next() {
                  return lastentry;
              }
  
          };
      }