private void checkFieldRead(FieldDescriptor fd, boolean expectRepeated) {
    if (expectRepeated) {
      if (!fd.isRepeated()) {
        throw new IllegalArgumentException(
            "This field is not repeated and cannot be read with the methods intended for collections or arrays: "
                + fd.getFullName());
      }
    } else {
      if (fd.isRepeated()) {
        throw new IllegalArgumentException(
            "A repeated field should be read with one of the methods intended for collections or arrays: "
                + fd.getFullName());
      }
    }

    if (!messageContext.markField(fd.getNumber())) {
      throw new IllegalStateException("A field cannot be read twice : " + fd.getFullName());
    }

    if (ctx.getConfiguration().logOutOfSequenceReads()
        && log.isEnabled(Logger.Level.WARN)
        && messageContext.getMaxSeenFieldNumber() > fd.getNumber()) {
      log.fieldReadOutOfSequence(fd.getFullName());
    }
  }
  private void handleCookie(String set_cookie, boolean cookie2, RoRequest req, Response resp)
      throws ProtocolException {
    Cookie[] cookies;
    if (cookie2) cookies = Cookie2.parse(set_cookie, req);
    else cookies = Cookie.parse(set_cookie, req);

    if (Log.isEnabled(Log.COOKI)) {
      Log.write(Log.COOKI, "CookM: Received and parsed " + cookies.length + " cookies:");
      for (int idx = 0; idx < cookies.length; idx++)
        Log.write(Log.COOKI, "CookM: Cookie " + idx + ": " + cookies[idx]);
    }

    Hashtable cookie_list = Util.getList(cookie_cntxt_list, req.getConnection().getContext());
    synchronized (cookie_list) {
      for (int idx = 0; idx < cookies.length; idx++) {
        Cookie cookie = (Cookie) cookie_list.get(cookies[idx]);
        if (cookie != null && cookies[idx].hasExpired()) {
          Log.write(Log.COOKI, "CookM: cookie has expired and is " + "being removed: " + cookie);
          cookie_list.remove(cookie); // expired, so remove
        } else if (!cookies[idx].hasExpired()) // new or replaced
        {
          if (cookie_handler == null || cookie_handler.acceptCookie(cookies[idx], req, resp))
            cookie_list.put(cookies[idx], cookies[idx]);
        }
      }
    }
  }
  /**
   * Closes the stream and causes the data to be sent if it has not already been done so. This
   * method <strong>must</strong> be invoked when all data has been written.
   *
   * @exception IOException if any exception is thrown by the underlying socket, or if too few bytes
   *     were written.
   * @exception IllegalAccessError if this stream has not been associated with a request yet.
   */
  public synchronized void close() throws IOException, IllegalAccessError {
    if (req == null) throw new IllegalAccessError("Stream not associated with a request");

    if (ignore) return;

    if (bos != null) {
      req.setData(bos.toByteArray());
      req.setStream(null);

      if (trailers.length > 0) {
        NVPair[] hdrs = req.getHeaders();

        // remove any Trailer header field

        int len = hdrs.length;
        for (int idx = 0; idx < len; idx++) {
          if (hdrs[idx].getName().equalsIgnoreCase("Trailer")) {
            System.arraycopy(hdrs, idx + 1, hdrs, idx, len - idx - 1);
            len--;
          }
        }

        // add the trailers to the headers

        hdrs = Util.resizeArray(hdrs, len + trailers.length);
        System.arraycopy(trailers, 0, hdrs, len, trailers.length);

        req.setHeaders(hdrs);
      }

      Log.write(Log.CONN, "OutS:  Sending request");

      try {
        resp = req.getConnection().sendRequest(req, con_to);
      } catch (ModuleException me) {
        throw new IOException(me.toString());
      }
      notify();
    } else {
      if (rcvd < length) {
        IOException ioe =
            new IOException(
                "Premature close: only "
                    + rcvd
                    + " bytes written instead of the "
                    + "expected "
                    + length);
        req.getConnection().closeDemux(ioe, false);
        req.getConnection().outputFinished();
        throw ioe;
      }

      try {
        if (length == -1) {
          if (Log.isEnabled(Log.CONN) && trailers.length > 0) {
            Log.write(Log.CONN, "OutS:  Sending trailers:");
            for (int idx = 0; idx < trailers.length; idx++)
              Log.write(
                  Log.CONN, "       " + trailers[idx].getName() + ": " + trailers[idx].getValue());
          }

          os.write(Codecs.chunkedEncode(null, 0, 0, trailers, true));
        }

        os.flush();

        Log.write(Log.CONN, "OutS:  All data sent");
      } catch (IOException ioe) {
        req.getConnection().closeDemux(ioe, true);
        throw ioe;
      } finally {
        req.getConnection().outputFinished();
      }
    }
  }