private void writeHeaders(WriteStream os, long length)
    throws IOException
  {
    int version = version();
    boolean debug = log.isLoggable(Level.FINE);

    if (version < RequestHttp1.HTTP_1_0) {
      killKeepalive("http client version " + version);
      return;
    }
    
    long contentLength = contentLengthOut();

    int statusCode = status();
    
    if (statusCode == 200) {
      if (version < RequestHttp1.HTTP_1_1) {
        os.write(_http10ok, 0, _http10ok.length);
      }
      else {
        os.write(_http11ok, 0, _http11ok.length);
      }
    }
    else {
      if (version < RequestHttp1.HTTP_1_1) {
        os.printLatin1("HTTP/1.0 ");
      }
      else {
        os.printLatin1("HTTP/1.1 ");
      }

      os.write((statusCode / 100) % 10 + '0');
      os.write((statusCode / 10) % 10 + '0');
      os.write(statusCode % 10 + '0');
      os.write(' ');
      os.printLatin1(statusMessage());
    }

    //String contentType = contentType();

    if (debug) {
      log.fine("HTTP/1.1 " +
               statusCode + " " + statusMessage() + " (" + dbgId() + ")");
    }

    if (_isUpgrade) {
      String upgrade = headerOut("Upgrade");

      if (upgrade != null) {
        os.printLatin1("\r\nUpgrade: ");
        os.printLatin1NoLf(upgrade);
      }

      os.printLatin1("\r\nConnection: Upgrade");
      killKeepalive("duplex/upgrade");

      if (debug) {
        log.fine(dbgId() + "Connection: Upgrade");
      }
    }

    // asdf
    String serverHeader = serverHeader();
    if (serverHeader == null) {
      os.write(_serverHeaderBytes, 0, _serverHeaderBytes.length);
    }
    else {
      os.printLatin1("\r\nserver: ");
      os.printLatin1NoLf(serverHeader);
    }

    ArrayList<String> headerKeys = headerKeysOut();
    ArrayList<String> headerValues = headerValuesOut();
    int size = headerKeys.size();

    for (int i = 0; i < size; i++) {
      String key = headerKeys.get(i);

      if (_isUpgrade && "Upgrade".equalsIgnoreCase(key)) {
        continue;
      }

      os.write('\r');
      os.write('\n');
      os.printLatin1NoLf(key);
      os.write(':');
      os.write(' ');
      os.printLatin1NoLf(headerValues.get(i));

      if (debug) {
        log.fine(key + ": " + headerValues.get(i) + " (" + dbgId() + ")");
      }
    }
    
    String contentType = headerOutContentType();
    String contentEncoding = headerOutContentEncoding();
    
    if (contentType != null) {
      os.write(_contentTypeBytes);
      os.printLatin1NoLf(contentType);
      
      if (contentEncoding != null) {
        os.write(_charsetBytes);
        os.printLatin1NoLf(contentEncoding);
      }
    }

    writeCookies(os);

    if (hasFooter()) {
      contentLength = -1;
      length = -1;
    }

    if (contentLength >= 0) {
      os.write(_contentLengthBytes, 0, _contentLengthBytes.length);
      os.print(contentLength);
      //hasContentLength = true;

      if (debug) {
        log.fine("Content-Length: " + contentLength + " (" + dbgId() + ")");
      }
    }
    else if (statusCode == HttpConstants.SC_NOT_MODIFIED) {
      // #3089
      // In the HTTP spec, a 304 has no message body so the content-length
      // is not needed.  The content-length is not explicitly forbidden,
      // but does cause problems with certain clients.
      //hasContentLength = true;
      setHead();
    }
    else if (statusCode == HttpConstants.SC_NO_CONTENT) {
      //hasContentLength = true;
      os.write(_contentLengthBytes, 0, _contentLengthBytes.length);
      os.print(0);
      setHead();

      if (debug)
        log.fine("Content-Length: 0 (" + dbgId() + ")");
    }
    else if (length >= 0) {
      os.write(_contentLengthBytes, 0, _contentLengthBytes.length);
      os.print(length);
      //hasContentLength = true;

      if (debug) {
        log.fine("Content-Length: " + length + " (" + dbgId() + ")");
      }
    }

    if (version < RequestHttp1.HTTP_1_1) {
      killKeepalive("http response version: " + version);
    }
    else {
      if (isKeepalive()) {
      }
      else if (_isUpgrade) {
        killKeepalive("http response upgrade");
      }
      else {
        os.write(_connectionCloseBytes, 0, _connectionCloseBytes.length);

        if (debug)
          log.fine(dbgId() + "Connection: close");
      }
    }
    
    long now = CurrentTime.currentTime();
    byte []dateBuffer = fillDateBuffer(now);
    int dateBufferLength = getDateBufferLength();

    if (isChunked()) {
      if (debug) {
        log.fine(dbgId() + "Transfer-Encoding: chunked");
      }

      os.write(_transferChunkedBytes);
      os.write(dateBuffer, 0, dateBufferLength - 2);
    }
    else {
      os.write(dateBuffer, 0, dateBufferLength);
    }
  }
private void writeHeaders ( WriteStream os , long length ) throws IOException { int version = version ( ) ; boolean debug = log . isLoggable ( Level . FINE ) ; if ( version < RequestHttp1 . HTTP_1_0 ) { killKeepalive ( "http client version " + version ) ; return ; } long contentLength = contentLengthOut ( ) ; int statusCode = status ( ) ; if ( statusCode == 200 ) { if ( version < RequestHttp1 . HTTP_1_1 ) { os . write ( _http10ok , 0 , _http10ok . length ) ; } else { os . write ( _http11ok , 0 , _http11ok . length ) ; } } else { if ( version < RequestHttp1 . HTTP_1_1 ) { os . printLatin1 ( "HTTP/1.0 " ) ; } else { os . printLatin1 ( "HTTP/1.1 " ) ; } os . write ( ( statusCode / 100 ) % 10 + '0' ) ; os . write ( ( statusCode / 10 ) % 10 + '0' ) ; os . write ( statusCode % 10 + '0' ) ; os . write ( ' ' ) ; os . printLatin1 ( statusMessage ( ) ) ; } if ( debug ) { log . fine ( "HTTP/1.1 " + statusCode + " " + statusMessage ( ) + " (" + dbgId ( ) + ")" ) ; } if ( _isUpgrade ) { String upgrade = headerOut ( "Upgrade" ) ; if ( upgrade != null ) { os . printLatin1 ( "\r\nUpgrade: " ) ; os . printLatin1NoLf ( upgrade ) ; } os . printLatin1 ( "\r\nConnection: Upgrade" ) ; killKeepalive ( "duplex/upgrade" ) ; if ( debug ) { log . fine ( dbgId ( ) + "Connection: Upgrade" ) ; } } String serverHeader = serverHeader ( ) ; if ( serverHeader == null ) { os . write ( _serverHeaderBytes , 0 , _serverHeaderBytes . length ) ; } else { os . printLatin1 ( "\r\nserver: " ) ; os . printLatin1NoLf ( serverHeader ) ; } ArrayList < String > headerKeys = headerKeysOut ( ) ; ArrayList < String > headerValues = headerValuesOut ( ) ; int size = headerKeys . size ( ) ; for ( int i = 0 ; i < size ; i ++ ) { String key = headerKeys . get ( i ) ; if ( _isUpgrade && "Upgrade" . equalsIgnoreCase ( key ) ) { continue ; } os . write ( '\r' ) ; os . write ( '\n' ) ; os . printLatin1NoLf ( key ) ; os . write ( ':' ) ; os . write ( ' ' ) ; os . printLatin1NoLf ( headerValues . get ( i ) ) ; if ( debug ) { log . fine ( key + ": " + headerValues . get ( i ) + " (" + dbgId ( ) + ")" ) ; } } String contentType = headerOutContentType ( ) ; String contentEncoding = headerOutContentEncoding ( ) ; if ( contentType != null ) { os . write ( _contentTypeBytes ) ; os . printLatin1NoLf ( contentType ) ; if ( contentEncoding != null ) { os . write ( _charsetBytes ) ; os . printLatin1NoLf ( contentEncoding ) ; } } writeCookies ( os ) ; if ( hasFooter ( ) ) { contentLength = - 1 ; length = - 1 ; } if ( contentLength >= 0 ) { os . write ( _contentLengthBytes , 0 , _contentLengthBytes . length ) ; os . print ( contentLength ) ; if ( debug ) { log . fine ( "Content-Length: " + contentLength + " (" + dbgId ( ) + ")" ) ; } } else if ( statusCode == HttpConstants . SC_NOT_MODIFIED ) { setHead ( ) ; } else if ( statusCode == HttpConstants . SC_NO_CONTENT ) { os . write ( _contentLengthBytes , 0 , _contentLengthBytes . length ) ; os . print ( 0 ) ; setHead ( ) ; if ( debug ) log . fine ( "Content-Length: 0 (" + dbgId ( ) + ")" ) ; } else if ( length >= 0 ) { os . write ( _contentLengthBytes , 0 , _contentLengthBytes . length ) ; os . print ( length ) ; if ( debug ) { log . fine ( "Content-Length: " + length + " (" + dbgId ( ) + ")" ) ; } } if ( version < RequestHttp1 . HTTP_1_1 ) { killKeepalive ( "http response version: " + version ) ; } else { if ( isKeepalive ( ) ) { } else if ( _isUpgrade ) { killKeepalive ( "http response upgrade" ) ; } else { os . write ( _connectionCloseBytes , 0 , _connectionCloseBytes . length ) ; if ( debug ) log . fine ( dbgId ( ) + "Connection: close" ) ; } } long now = CurrentTime . currentTime ( ) ; byte [ ] dateBuffer = fillDateBuffer ( now ) ; int dateBufferLength = getDateBufferLength ( ) ; if ( isChunked ( ) ) { if ( debug ) { log . fine ( dbgId ( ) + "Transfer-Encoding: chunked" ) ; } os . write ( _transferChunkedBytes ) ; os . write ( dateBuffer , 0 , dateBufferLength - 2 ) ; } else { os . write ( dateBuffer , 0 , dateBufferLength ) ; } }
@Override