9910

          單飛

             :: 首頁 :: 聯系 :: 聚合  :: 管理
          rfc2616

          對于返回是chunked格式的字節流的處理

          import java.io.IOException;
          import java.io.InputStream;
          import java.util.HashMap;
          import java.util.Map;
          import java.util.Set;
          /**
           * http response chunked transfer type input stream
           * 
          @author jeffrey.ship
           *
           
          */
          public class ChunkedInputStream {

              
          public static final int CR = 13// <US-ASCII CR, carriage return (13)>

              
          public static final int LF = 10// <US-ASCII LF, linefeed (10)>

              
          public static final int SP = 32// <US-ASCII SP, space (32)>

              
          public static final int HT = 9// <US-ASCII HT, horizontal-tab (9)>

              
          private InputStream is;

              
          private StringBuffer stringbuffer;// share buffer

              
          private Map<String, String> headerFields;

              
          private int responseCode;

              
          private String responseMsg;

              
          private int bytesleft; // Number of bytes left in current chunk

              
          private int bytesread; // Number of bytes read since the stream was opened

              
          private boolean chunked; // True if Transfer-Encoding: chunked

              
          private boolean eof; // True if EOF seen

              
          public ChunkedInputStream(InputStream is) {
                  
          this.is = is;
                  headerFields 
          = new HashMap<String, String>();
                  stringbuffer 
          = new StringBuffer(32);
              }

              
          public void init() throws Exception {
                  readResponseMessage(is);
                  readHeaders(is);

                  
          // Determine if this is a chunked datatransfer and setup
                  String te = (String) headerFields.get("transfer-encoding");
                  
          if (te != null && te.equals("chunked")) {
                      chunked 
          = true;
                      bytesleft 
          = readChunkSize();
                      eof 
          = (bytesleft == 0);
                  }
              }

              
          private void readResponseMessage(InputStream in) throws IOException {
                  String line 
          = readLine(in);
                  
          int httpEnd, codeEnd;

                  responseCode 
          = -1;
                  responseMsg 
          = null;

                  malformed: {
                      
          if (line == null)
                          
          break malformed;

                      httpEnd 
          = line.indexOf(' ');

                      
          if (httpEnd < 0)
                          
          break malformed;

                      String httpVer 
          = line.substring(0, httpEnd);

                      
          if (!httpVer.startsWith("HTTP"))
                          
          break malformed;

                      
          if (line.length() <= httpEnd)
                          
          break malformed;

                      codeEnd 
          = line.substring(httpEnd + 1).indexOf(' ');

                      
          if (codeEnd < 0)
                          
          break malformed;

                      codeEnd 
          += (httpEnd + 1);

                      
          if (line.length() <= codeEnd)
                          
          break malformed;

                      
          try {
                          responseCode 
          = Integer.parseInt(line.substring(httpEnd + 1, codeEnd));
                      } 
          catch (NumberFormatException nfe) {
                          
          break malformed;
                      }

                      responseMsg 
          = line.substring(codeEnd + 1);
                      
          return;
                  }

                  
          throw new IOException("malformed response message");
              }
              
              

              
          public int getResponseCode() {
                  
          return responseCode;
              }

              
          public String getResponseMsg() {
                  
          return responseMsg;
              }

              
          private void readHeaders(InputStream in) throws IOException {
                  String line, key, value;
                  
          int index;

                  
          for (;;) {
                      line 
          = readLine(in);

                      
          if (line == null || line.equals(""))
                          
          return;

                      index 
          = line.indexOf(':');

                      
          if (index < 0)
                          
          throw new IOException("malformed header field");

                      key 
          = line.substring(0, index);

                      
          if (key.length() == 0)
                          
          throw new IOException("malformed header field");

                      
          if (line.length() <= index + 2) {
                          value 
          = "";
                      } 
          else {
                          value 
          = line.substring(index + 2);
                      }

                      headerFields.put(toLowerCase(key), value);
                  }
              }

              
          public String getResponseHeaders() {
                  Set
          <String> keys = headerFields.keySet();
                  StringBuffer headers 
          = new StringBuffer();
                  
          for (String key : keys) {
                      String value 
          = headerFields.get(key);
                      headers.append(key 
          + ":" + value + "\r\n");
                  }
                  
          return headers.toString();
              }

              
          public String getHeaderField(String name) {
                  
          return (String) headerFields.get(toLowerCase(name));
              }

              
          /** */
              
          /**
               * Reads the next byte of data from the input stream. The value byte is
               * returned as an <code>int</code> in the range <code>0</code> to
               * <code>255</code>. If no byte is available because the end of the
               * stream has been reached, the value <code>-1</code> is returned. This
               * method blocks until input data is available, the end of the stream is
               * detected, or an exception is thrown.
               * 
               * <p>
               * A subclass must provide an implementation of this method.
               * 
               * 
          @return the next byte of data, or <code>-1</code> if the end of the
               *         stream is reached.
               * 
          @exception IOException
               *                if an I/O error occurs.
               
          */
              
          public int read() throws IOException {

                  
          // Be consistent about returning EOF once encountered.
                  if (eof) {
                      
          return -1;
                  }

                  
          /**//*
                       * If all the current chunk has been read and this is a chunked
                       * transfer then read the next chunk length.
                       
          */
                  
          if (bytesleft <= 0 && chunked) {
                      readCRLF(); 
          // Skip trailing

                      bytesleft 
          = readChunkSize();
                      
          if (bytesleft == 0) {
                          eof 
          = true;
                          
          return -1;
                      }
                  }

                  
          int ch = is.read();
                  eof 
          = (ch == -1);
                  bytesleft
          --;
                  bytesread
          ++;
                  
          return ch;
              }

              
          /** */
              
          /**
               * Reads some number of bytes from the input stream and stores them into the
               * buffer array <code>b</code>. The number of bytes actually read is
               * returned as an integer. This method blocks until input data is available,
               * end of file is detected, or an exception is thrown. (For HTTP requests
               * where the content length has been specified in the response headers, the
               * size of the read may be reduced if there are fewer bytes left than the
               * size of the supplied input buffer.)
               * 
               * 
          @param b
               *            the buffer into which the data is read.
               * 
          @return the total number of bytes read into the buffer, or
               *         <code>-1</code> is there is no more data because the end of the
               *         stream has been reached.
               * 
          @exception IOException
               *                if an I/O error occurs.
               * 
          @see java.io.InputStream#read(byte[])
               
          */
              
          public int read(byte[] b) throws IOException {
                  
          long len = getLength();

                  
          if (len != -1) {
                      
          // More bytes are expected
                      len -= bytesread;
                  } 
          else {
                      
          // Buffered reading in chunks
                      len = b.length;
                  }

                  
          if (len == 0) {
                      eof 
          = true;
                      
          // All expected bytes have been read
                      return -1;
                  }

                  
          return read(b, 0, (int) (len < b.length ? len : b.length));
              }

              
          public int read(byte b[], int off, int len) throws IOException {
                  
          if (b == null) {
                      
          throw new NullPointerException();
                  } 
          else if (off < 0 || len < 0 || len > b.length - off) {
                      
          throw new IndexOutOfBoundsException();
                  } 
          else if (len == 0) {
                      
          return 0;
                  }

                  
          int c = read();
                  
          if (c == -1) {
                      
          return -1;
                  }
                  b[off] 
          = (byte) c;

                  
          int i = 1;
                  
          try {
                      
          for (; i < len; i++) {
                          c 
          = read();
                          
          if (c == -1) {
                              
          break;
                          }
                          b[off 
          + i] = (byte) c;
                      }
                  } 
          catch (IOException ee) {
                  }
                  
          return i;
              }

              
          public long getLength() {
                  
          return getHeaderFieldInt("content-length"-1);
              }

              
          public int getHeaderFieldInt(String name, int def) {
                  
          try {
                      
          return Integer.parseInt(getHeaderField(name));
                  } 
          catch (Throwable t) {
                  }

                  
          return def;
              }

              
          /**
               * Returns the number of bytes that can be read (or skipped over) from this
               * input stream without blocking by the next caller of a method for this
               * input stream.
               * 
               * This method simply returns the number of bytes left from a chunked
               * response from an HTTP 1.1 server.
               
          */
              
          public int available() throws IOException {
                  
          return bytesleft;
              }

              
          /**//*
                   * Read <cr><lf> from the InputStream. 
          @exception IOException is thrown
                   * if either <CR> or <LF> is missing.
                   
          */
              
          private void readCRLF() throws IOException {
                  
          int ch;

                  ch 
          = is.read();
                  
          if (ch != CR) {
                      
          throw new IOException("missing CRLF");
                  }

                  ch 
          = is.read();
                  
          if (ch != LF) {
                      
          throw new IOException("missing CRLF");
                  }
              }

              
          public void close() throws IOException {
                  is.close();
              }

              
          private String toLowerCase(String string) {

                  
          // Uses the shared stringbuffer to create a lower case string.
                  stringbuffer.setLength(0);

                  
          for (int i = 0; i < string.length(); i++) {
                      stringbuffer.append(Character.toLowerCase(string.charAt(i)));
                  }

                  
          return stringbuffer.toString();
              }

              
          /**//*
                   * Uses the shared stringbuffer to read a line terminated by <cr><lf>
                   * and return it as string.
                   
          */
              
          private String readLine(InputStream in) {
                  
          int c;
                  StringBuffer stringbuffer 
          = new StringBuffer();
                  stringbuffer.setLength(
          0);

                  
          for (;;) {
                      
          try {
                          c 
          = in.read();
                          
          if (c < 0) {
                              
          return null;
                          }
                      } 
          catch (IOException ioe) {
                          
          return null;
                      }

                      
          if (isEnd(c)) {
                          
          try {
                              
          // LF
                              in.read();
                          } 
          catch (IOException e) {
                              e.printStackTrace();
                          }
                          
          break;
                      }
                      stringbuffer.append((
          char) c);

                  }

                  
          return stringbuffer.toString();
              }

              
          public static boolean isEnd(int ch) {
                  
          return ch == CR || ch == LF;
              }

              
          /**//*
                   * Read the chunk size from the input. It is a hex length followed by
                   * optional headers (ignored) and terminated with <cr><lf>.
                   
          */
              
          private int readChunkSize() throws IOException {
                  
          int size = -1;
                  
          try {
                      String chunk 
          = readLine(is);
                      
          if (chunk == null) {
                          
          throw new IOException("No Chunk Size");
                      }

                      
          int i;
                      
          for (i = 0; i < chunk.length(); i++) {
                          
          char ch = chunk.charAt(i);
                          
          if (Character.digit(ch, 16== -1)
                              
          break;
                      }

                      
          /**//* look at extensions?. */
                      size 
          = Integer.parseInt(chunk.substring(0, i), 16);

                  } 
          catch (NumberFormatException e) {
                      
          throw new IOException("Bogus chunk size");
                  }

                  
          return size;
              }
          }

          posted on 2009-11-05 14:45 單飛 閱讀(374) 評論(0)  編輯  收藏 所屬分類: java
          主站蜘蛛池模板: 新绛县| 白玉县| 泰顺县| 浮梁县| 通化县| 伊川县| 张家界市| 新津县| 神木县| 凌源市| 长治市| 多伦县| 怀安县| 滦南县| 德江县| 峡江县| 孝义市| 正安县| 莱阳市| 合作市| 镇江市| 平江县| 晋城| 铜山县| 庆阳市| 牙克石市| 攀枝花市| 南陵县| 长沙市| 昌宁县| 红河县| 正定县| 奇台县| 克什克腾旗| 阜新市| 洪洞县| 中卫市| 台江县| 孝感市| 宁国市| 阿鲁科尔沁旗|