⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httpresponse.java

📁 这是linux下ssl vpn的实现程序
💻 JAVA
字号:
/*
 *  SSL-Explorer
 *
 *  Copyright (C) 2003-2006 3SP LTD. All Rights Reserved
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2 of
 *  the License, or (at your option) any later version.
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public
 *  License along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
			
package com.maverick.http;

import java.io.IOException;
import java.io.InputStream;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
/* DEBUG */import org.apache.commons.logging.LogFactory;
/* DEBUG */import org.apache.commons.logging.Log;
import java.io.EOFException;
import java.util.Hashtable;

public class HttpResponse
    extends HttpHeader {

  /* DEBUG */static Log log = LogFactory.getLog(HttpResponse.class);

  protected ByteArrayOutputStream chunked;
  protected String begin;

  private String version = "";
  private int status;
  private String reason = "";

  boolean closeConnection = false;
  int contentLength = 0;

  boolean foundContinue = false;
  boolean release = true;

  InputStream in = new ByteArrayInputStream(new byte[] {} );

  HttpConnection con;
  HttpContinue cont;

  public HttpResponse(HttpConnection con) throws IOException {
      this(con, false);
  }

  public HttpResponse(HttpConnection con, HttpContinue cont) throws IOException {
      this.con = con;
      this.cont = cont;
      doResponse(false);
  }

  public HttpResponse(HttpConnection con, boolean headerOnly) throws IOException {
    this.con = con;
    doResponse(headerOnly);
  }

  private void doResponse(boolean headerOnly) throws IOException {

    do {

        begin = readLine(con.getInputStream());

        while (begin.trim().length() == 0) {
            begin = readLine(con.getInputStream());
        }

        /* DEBUG */log.debug("Received start line: " + begin);
        processResponse();

        if(status==100) {
            if(cont!=null)
                cont.continueRequest(con);
            foundContinue = true;

            String tmp;
            while(true) {
                
                /**
                 * Fix for IIS web servers, they are sending additional headers
                 * with the 100 Continue response.
                 */
                tmp = readLine(con.getInputStream());
                
                /* DEBUG */log.debug("Received 100-Continue header: " + tmp);
                
                if(tmp.equals(""))
                    break;
            }
            
        }
    } while(status>=100 && status < 200);

    processHeaderFields(con.getInputStream());

    if(!headerOnly) {

        /**
         * LDP - Moved transfer encoding check to here, seems the 
         * more logical place to have it, plus I needed to work around
         * the stream being overidden by the Connection: close header.
         */
        if (getHeaderField("transfer-encoding") != null) {
            if (getHeaderField("transfer-encoding").equalsIgnoreCase(
                    "chunked")) {
                in = new ChunkedInputStream(con.getInputStream());
                // Remove the transfer-encoding header
                fields.remove("transfer-encoding");
            }
        } else if (getHeaderField("Content-Length") != null) {
            contentLength = Integer.parseInt(getHeaderField("Content-Length"));
            in = new ContentInputStream(contentLength);
        } else if(getHeaderField("Connection")!=null &&
            getHeaderField("Connection").equalsIgnoreCase("close")) {
    
           // Set the connection as unusable by others
           con.canReuse = false;
           
           /**
            * LDP - Since the connection is being closed we could have some content
            * and no content-length header so just make this responses inputstream
            * the connections inputstream, it will go EOF once drained.
            */
            in = con.getInputStream();
        } else if(getHeaderField("Proxy-Connection")!=null &&
                        getHeaderField("Proxy-Connection").equalsIgnoreCase("close")) {
            
            // Set the connection as unusable by others
            con.canReuse = false;
            
            /**
             * LDP - Since the connection is being closed we could have some content
             * and no content-length header so just make this responses inputstream
             * the connections inputstream, it will go EOF once drained.
             */
             in = con.getInputStream();
         } else {
            /**
             * No data to read so return an empty stream.
             */
            in = new ByteArrayInputStream(new byte[] {} );
        }
    }
    
    /**
     * Finally check the connection close status again to set the canReuse flag on
     * the HttpConnection.
     */
    if(getHeaderField("Connection")!=null &&
        getHeaderField("Connection").equalsIgnoreCase("close")) {
            
       // Set the connection as unusable by others
       con.canReuse = false;
       
    } else if(getHeaderField("Proxy-Connection")!=null &&
                    getHeaderField("Proxy-Connection").equalsIgnoreCase("close")) {
        
        // Set the connection as unusable by others
        con.canReuse = false;
     }
    
  }
  public void close() {
      close(true);
  }

  public boolean hasContinue() {
      return foundContinue;
  }

  public synchronized void close(boolean release) {

      /**
       * LDP - I've added this release flag because the doAuthentication
       * method of HttpClient was calling close to drain the connection so that
       * it could be reused. This was correct but the connection was prematurely
       * being put back into the connection manager, and was being reused by other
       * threads. Since we want to keep hold of the existing connection, in case
       * of NTLM authentication we want to drain but not release.
       */
       if(con==null)
          return;

      try {
          if(in instanceof ChunkedInputStream) {
              ((ChunkedInputStream)in).drain();
          } else if(in instanceof ContentInputStream) {
              ((ContentInputStream)in).drain();
          }
      } catch(IOException ex) {
          // Exception during skip better close this connection
          con.canReuse = false;
      } finally {
          if(release) {
              con.release();
              con = null;
          }
      }
  }
  
  protected String readLine(InputStream in) throws IOException {
      StringBuffer lineBuf = new StringBuffer();
      int c;

      while (true) {
        c = in.read();

        if (c == -1) {
          if(lineBuf.length()==0)
              throw new EOFException("Unexpected EOF in HTTP header");

          break;
        }

        if (c != '\n') {
          lineBuf.append( (char) c);
        }
        else {
          break;
        }
      }

      return lineBuf.toString().trim();
    }

    public String getStartLine() {
      return begin;
    }

    protected void processHeaderFields(InputStream in) throws IOException {
        fields = new Hashtable();

        StringBuffer lineBuf = new StringBuffer();
        String lastHeaderName = null;
        int c;

        while (true) {
          c = in.read();

          if (c == -1) {
            throw new IOException("The HTTP header is corrupt");
          }

          if (c != '\n') {
            lineBuf.append( (char) c);
          }
          else {
            String line = lineBuf.toString().trim();
            lineBuf.setLength(0);
            if (line.length() != 0) {
              lastHeaderName = processNextLine(line, lastHeaderName);
            }
            else {
                break;
            }
          }
        }
      }

      private String processNextLine(String line, String lastHeaderName) throws
          IOException {
        String name;
        String value;
        char c = line.charAt(0);

        if ( (c == ' ') || (c == '\t')) {
          name = lastHeaderName;
          value = getHeaderField(lastHeaderName) + " " + line.trim();
        }
        else {
          int n = line.indexOf(':');

          if (n == -1) {
            throw new IOException(
                "HTTP Header encoutered a corrupt field: '" + line + "'");
          }

          name = line.substring(0, n);
          value = line.substring(n + 1).trim();
        }

        /* DEBUG */log.debug("Received header: " + name + ": " + value);
        setHeaderField(name, value);

        return name;
  }
  public InputStream getInputStream() {
    return in;
  }

  public HttpConnection getConnection() {
    return con;
  }

  public String getVersion() {
    return version;
  }

  public int getStatus() {
    return status;
  }

  public String getReason() {
    return reason;
  }

  private void processResponse() throws IOException {
    StringTokenizer tokens = new StringTokenizer(begin, WHITE_SPACE, false);
    reason = "";
    try {
      version = tokens.nextToken();
      status = Integer.parseInt(tokens.nextToken());
      while(tokens.hasMoreTokens()) {
        reason += tokens.nextToken() + " ";
      }
      reason = reason.trim();
    }
    catch (NoSuchElementException e) {
      throw new IOException("Failed to read HTTP repsonse header");
    }
    catch (NumberFormatException e) {
      throw new IOException("Failed to read HTTP resposne header");
    }
  }


  /**
   * We will use this stream to return data that is encoded using the
   * "Transfer-Encoding: chunked" header.
   */
  class ChunkedInputStream extends InputStream {


     long chunkLength;
     InputStream in;

     ChunkedInputStream(InputStream in) throws IOException {

       this.in = in;
       // Read from the InputStream until we receive chunk size of zero
       chunkLength = Long.parseLong(readLine(in), 16);
     }

     public int read() throws IOException {
         byte[] b = new byte[1];
         int read = read(b, 0, 1);
         if(read==-1)
             return -1;
         else
             return b[0] & 0xFF;
     }

     public void drain() throws IOException {
         long len;
         byte[] buf = new byte[65535];
         while(contentLength > 0) {
             len = con.getInputStream().read(buf, 0, buf.length);

             if(contentLength > 0)
                 contentLength -= len;
             else
                 break;
         }
      }

     public synchronized int read(byte[] buf, int off, int len) throws IOException {

         if(chunkLength==0 || con==null) {
             return -1;
         }
         int read;
         int count = 0;
         while(len > 0 && chunkLength > 0) {

             read = in.read(buf, off, (int) (len > chunkLength ? chunkLength : len));

             if(read==-1)
                 throw new EOFException("Unexpected EOF during chunked transfer encoded read");

             chunkLength -= read;
             len -= read;
             off += read;
             count += read;

             if(chunkLength == 0) {
                 readLine(in);
                 chunkLength = Long.parseLong(readLine(in), 16);
                 if(chunkLength==0)
                     close();
             }
        }

        return count;
     }

     public synchronized void close() throws IOException {

         if(con!=null) {
             readLine(in);
             HttpResponse.this.close(true);
         }
     }
  }

  /**
   * We will use this to return standard content
   */
  class ContentInputStream extends InputStream {

      long contentLength;

      ContentInputStream(long contentLength) {
          this.contentLength = contentLength;
      }

      public synchronized int available() {
          return (int) contentLength;
      }

      public synchronized long skip(long length) throws IOException {
          return con.getInputStream().skip(length);
      }

      public void drain() throws IOException {
          long len;

          while(contentLength > 0) {
              len = con.getInputStream().skip(contentLength);

              if(contentLength > 0)
                  contentLength -= len;
              else
                  break;
          }
      }

      public synchronized int read() throws IOException {

          if(contentLength==0 || con==null) {
              return -1;
          }
          else {
             int b = con.getInputStream().read();
             if(b==-1)
                 throw new EOFException("Unexpected EOF in Http response, expected " + contentLength + " more bytes");
             contentLength--;

             if(contentLength==0)
                 close();

             return b;
          }
      }

      public synchronized int read(byte[] buf, int off, int len) throws IOException {
          if(contentLength==0 || con==null) {
              return -1;
          }
          else {
              int read = con.getInputStream().read(buf, off, (contentLength > len ? len : (int)contentLength));
              if(read==-1)
                  throw new EOFException("Unexpected EOF in HTTP response, expected " + contentLength + " more bytes");
              contentLength -= read;

              if(contentLength==0)
                  close();

              return read;
          }

      }

      public synchronized void close() {
          // Release the connection back to the client pool
          if(con!=null)
              HttpResponse.this.close(true);
      }
  }


}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -