Package com.davfx.ninio.http

Source Code of com.davfx.ninio.http.HttpResponseReader$RecyclingHandler

package com.davfx.ninio.http;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

import com.davfx.ninio.common.Address;
import com.davfx.ninio.common.ByteBufferHandler;

final class HttpResponseReader {

  interface RecyclingHandler {
    void recycle();
    void close();
  }
 
  private final LineReader lineReader = new LineReader();
  private boolean headersRead = false;
  private boolean responseLineRead = false;
  private boolean chunked;
  private GzipReader gzipReader;
  private boolean keepAlive;
  private boolean chunkHeaderRead = false;
  private boolean chunkFooterRead = true;
  private long contentLength;
  private int chunkLength;
  private int chunkCountRead = 0;
  private int countRead = 0;
//  private String responseVersion;
  private int responseCode;
  private String responseReason;
  private final Map<String, String> headers = new HashMap<String, String>();
  private boolean failClose = false;
  private boolean closed = false;
  private boolean ended = false;
  private boolean http11;
 
  private final HttpClientHandler handler;
 
  public HttpResponseReader(HttpClientHandler handler) {
    this.handler = handler;
  }
 
  private void addHeader(String headerLine) throws IOException {
    int i = headerLine.indexOf(Http.HEADER_KEY_VALUE_SEPARATOR);
    if (i < 0) {
      throw new IOException("Invalid header: " + headerLine);
    }
    String key = headerLine.substring(0, i);
    String value = headerLine.substring(i + 1).trim();
    headers.put(key, value);
  }
  private void setResponseLine(String responseLine) throws IOException {
    int i = responseLine.indexOf(Http.START_LINE_SEPARATOR);
    if (i < 0) {
      throw new IOException("Invalid response: " + responseLine);
    }
    int j = responseLine.indexOf(Http.START_LINE_SEPARATOR, i + 1);
    if (j < 0) {
      throw new IOException("Invalid response: " + responseLine);
    }
    String responseVersion = responseLine.substring(0, i);
    if (responseVersion.equals(Http.HTTP10)) {
      http11 = false;
    } else if (responseVersion.equals(Http.HTTP11)) {
      http11 = true;
    } else {
      throw new IOException("Unsupported version");
    }
    String code = responseLine.substring(i + 1, j);
    try {
      responseCode = Integer.parseInt(code);
    } catch (NumberFormatException e) {
      throw new IOException("Invalid status code: " + code);
    }
    responseReason = responseLine.substring(j + 1);
  }
 
  public void close() {
    if (failClose) {
      if (!closed) {
        closed = true;
        handler.failed(new IOException("Connection reset by peer"));
      }
    } else {
      if (!closed) {
        closed = true;
        handler.finished();
      }
    }
  }
 
  public void failed(IOException e) {
    if (!closed) {
      closed = true;
      handler.failed(e);
    }
  }
 
  public void handle(ByteBuffer buffer, RecyclingHandler recyclingHandler) {
    if (!buffer.hasRemaining()) {
      return;
    }
    try {
     
      if (ended || closed) {
        throw new IOException("Too much data");
      }
     
      failClose = true;
      while (!responseLineRead) {
        String line = lineReader.handle(buffer);
        if (line == null) {
          return;
        }
        setResponseLine(line);
        responseLineRead = true;
      }
      while (!headersRead) {
        String line = lineReader.handle(buffer);
        if (line == null) {
          return;
        }
        if (line.isEmpty()) {
          headersRead = true;
          String contentLengthValue = headers.get(Http.CONTENT_LENGTH);
          if (contentLengthValue != null) {
            try {
              contentLength = Long.parseLong(contentLengthValue);
            } catch (NumberFormatException e) {
              throw new IOException("Invalid Content-Length: " + contentLengthValue);
            }
          } else {
            contentLength = -1;
          }
          if (Http.GZIP.equalsIgnoreCase(headers.get(Http.CONTENT_ENCODING))) {
            gzipReader = new GzipReader(new ByteBufferHandler() {
              @Override
              public void handle(Address address, ByteBuffer buffer) {
                handler.received(buffer);
              }
            });
          } else {
            gzipReader = null;
          }
          chunked = Http.CHUNKED.equalsIgnoreCase(headers.get(Http.TRANSFER_ENCODING));
          keepAlive = http11 && !Http.CLOSE.equalsIgnoreCase(headers.get(Http.CONNECTION));
          handler.received(new HttpResponse(responseCode, responseReason, headers));
        } else {
          addHeader(line);
        }
      }
     
      if (chunked) {
       
        while (true) {
       
          while (!chunkFooterRead) {
            String line = lineReader.handle(buffer);
            if (line == null) {
              return;
            }
            if (!line.isEmpty()) {
              throw new IOException("Invalid chunk footer");
            }
            chunkFooterRead = true;
            chunkHeaderRead = false;
            failClose = false;
            if (chunkLength == 0) {
              if (keepAlive) {
                recyclingHandler.recycle();
              } else {
                recyclingHandler.close();
              }
              if (!closed) {
                closed = true;
                ended = true;
                handler.finished();
              }
            }
          }

          while (!chunkHeaderRead) {
            String line = lineReader.handle(buffer);
            if (line == null) {
              return;
            }
            failClose = true;
            int i = line.indexOf(Http.EXTENSION_SEPARATOR);
            if (i > 0) { // extensions ignored
              line = line.substring(0, i);
            }
            try {
              chunkLength = Integer.parseInt(line, 16);
            } catch (NumberFormatException e) {
              throw new IOException("Invalid chunk size: " + line);
            }
            chunkHeaderRead = true;
          }
         
          if (!buffer.hasRemaining()) {
            return;
          }
           
          if (chunkHeaderRead && (chunkCountRead < chunkLength)) {
            long totalToRead = contentLength - countRead;
            long toRead = chunkLength - chunkCountRead;
            handleContent(buffer, toRead, totalToRead);
          }
         
          if (chunkCountRead == chunkLength) {
            chunkFooterRead = false;
            chunkCountRead = 0;
          }
       
        }
 
      } else {
     
        if (contentLength >= 0) {
          if (countRead < contentLength) {
            long toRead = contentLength - countRead;
            handleContent(buffer, toRead, toRead);
          }
          if (countRead == contentLength) {
            failClose = false;
            if (keepAlive) {
              recyclingHandler.recycle();
            } else {
              recyclingHandler.close();
            }
            ended = true;
            if (!closed) {
              closed = true;
              handler.finished();
            }
          }
        } else {
          failClose = false;
          handleContent(buffer, -1, -1);
        }

      }
     
    } catch (IOException e) {
      if (!closed) {
        closed = true;
        handler.failed(e);
      }
    }
  }
 
    private void handleContent(ByteBuffer buffer, long toRead, long totalRemainingToRead) throws IOException {
      ByteBuffer deflated = buffer.duplicate(); // We must duplicated this buffer because it can be used later by the user, but must be continued in the handle loop
      if (toRead >= 0) {
      if (deflated.remaining() > toRead) {
        deflated.limit((int) (buffer.position() + toRead));
      }
      }
     
      chunkCountRead += deflated.remaining();
    countRead += deflated.remaining();
    buffer.position((int) (buffer.position() + deflated.remaining()));

    if (gzipReader == null) {
      handler.received(deflated);
      return;
    }
   
    gzipReader.handle(deflated, totalRemainingToRead);
    }
}
TOP

Related Classes of com.davfx.ninio.http.HttpResponseReader$RecyclingHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.