Package com.firefly.server.http

Source Code of com.firefly.server.http.HttpServletRequestImpl

package com.firefly.server.http;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;

import javax.servlet.AsyncContext;
import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.Part;

import com.firefly.net.Session;
import com.firefly.server.exception.HttpServerException;
import com.firefly.server.io.PipedStream;
import com.firefly.server.utils.StringParser;
import com.firefly.utils.StringUtils;
import com.firefly.utils.VerifyUtils;
import com.firefly.utils.log.Log;
import com.firefly.utils.log.LogFactory;
import com.firefly.utils.time.Millisecond100Clock;

public class HttpServletRequestImpl implements HttpServletRequest {
 
  int status, headLength, offset;
  String method, requestURI, queryString;
  String protocol = "HTTP/1.1";

  PipedStream bodyPipedStream;
  Cookie[] cookies;
  Map<String, String> headMap = new HashMap<String, String>();
  HttpServletResponseImpl response;
  Config config;
  Session session;
  boolean systemReq = false;

  private static Log log = LogFactory.getInstance().getLog("firefly-system");
  private StringParser parser = new StringParser();
  private static final String[] EMPTY_STR_ARR = new String[0];
  private static final Cookie[] EMPTY_COOKIE_ARR = new Cookie[0];
 
  private String characterEncoding, requestedSessionId;
  private boolean requestedSessionIdFromCookie, requestedSessionIdFromURL;
  private boolean decodeFinish = false;
  private HttpSession httpSession;
  private Map<String, List<String>> parameterMap = new HashMap<String, List<String>>();
  private Map<String, String[]> _parameterMap = null;
  private Map<String, Object> attributeMap = new HashMap<String, Object>();
  private BufferedReader bufferedReader;
  private ServletInputStream servletInputStream;
  private RequestDispatcherImpl requestDispatcher = new RequestDispatcherImpl();
  private MultipartFormData multipartFormData;
  private AsyncContextImpl asyncContext = null;
 

  protected static Locale DEFAULT_LOCALE = Locale.getDefault();
  protected ArrayList<Locale> locales = new ArrayList<Locale>();
  private boolean loadParam, localesParsed;
  private final long createdTime = Millisecond100Clock.currentTimeMillis();

  public HttpServletRequestImpl(Session session, Config config) {
    this.characterEncoding = config.getEncoding();
    this.session = session;
    this.config = config;
    response = new HttpServletResponseImpl(session, this, characterEncoding, config.getWriteBufferSize());
  }
 
  public long getCreatedTime() {
    return createdTime;
  }
 
  public long getTimeDifference() {
    return Millisecond100Clock.currentTimeMillis() - createdTime;
  }
 
  //======================= IO stream process =======================
 
  @Override
  public BufferedReader getReader() throws IOException {
    if (bufferedReader == null) {
      bufferedReader = new BufferedReader(new InputStreamReader(bodyPipedStream.getInputStream(), characterEncoding));
    }
    return bufferedReader;
  }

  @Override
  public ServletInputStream getInputStream() throws IOException {
    if(servletInputStream == null) {
      final InputStream in = bodyPipedStream.getInputStream();
      servletInputStream = new ServletInputStream() {

        @Override
        public int read() throws IOException {
          return in.read();
        }

        @Override
        public int available() throws IOException {
          return in.available();
        }

        @Override
        public void close() throws IOException {
          in.close();
        }

        @Override
        public int read(byte[] b, int off, int len) throws IOException {
          return in.read(b, off, len);
        }
      };
    }
    return servletInputStream;
  }
 
  private void loadParam() {
    if (!loadParam) {
      try {
        loadParam(queryString);
       
        String contentType = getContentType();
        if (method.equals("POST") && contentType != null && contentType.startsWith("application/x-www-form-urlencoded")) {
          int contentLength = getContentLength();
          byte[] data = new byte[contentLength];
          byte[] buf = new byte[1024];
          ServletInputStream input = getInputStream();
          try {
            int readBytes = 0;
            for (int len = 0; (len = input.read(buf)) != -1;) {
              System.arraycopy(buf, 0, data, readBytes, len);
              readBytes += len;
              if (readBytes >= contentLength)
                break;
            }
            loadParam(new String(data, characterEncoding));
          } finally {
            input.close();
          }
        }
      } catch (Throwable t) {
        log.error("load param error", t);
      }
      loadParam = true;
    }
  }

  private void loadParam(String str) throws UnsupportedEncodingException {
    if (VerifyUtils.isNotEmpty(str)) {
      String[] p = StringUtils.split(str, '&');
      for (String kv : p) {
        int i = kv.indexOf('=');
        if (i > 0) {
          String name = kv.substring(0, i);
          String value = kv.substring(i + 1);

          List<String> list = parameterMap.get(name);
          if (list == null) {
            list = new ArrayList<String>();
            parameterMap.put(name, list);

          }
          list.add(URLDecoder.decode(value, characterEncoding));
        }

      }
    }
  }
 
  /**
   * if http method is POST or PUT, when the business process finish, it must close piped stream
   */
  void releaseInputStreamData() {
    try {
      if(getContentLength() > 0) {
        if(bodyPipedStream != null) {
          bodyPipedStream.close();
        }
        if(multipartFormData != null) {
          multipartFormData.close();
        }
      }
    } catch(Throwable t) {
      log.error("release input stream error", t);
    }
  }
 
 
  //======================= HTTP decode need following method =======================

  boolean isKeepAlive() {
    return !systemReq
        && config.isKeepAlive()
        && ("keep-alive".equalsIgnoreCase(getHeader("Connection"))
          || (!getProtocol().equals("HTTP/1.0") && !"close".equalsIgnoreCase(getHeader("Connection"))));
  }

  boolean isChunked() {
    return !systemReq && !getProtocol().equals("HTTP/1.0");
  }
 
  /**
   * decode finish, then enter into business process
   */
  void decodeFinish() {
    if(!decodeFinish) {
      session.fireReceiveMessage(this);
      decodeFinish = true;
    }
  }
 
 
  //======================= set and get request attribute =======================
 
  @Override
  public void setAttribute(String name, Object o) {
    attributeMap.put(name, o);
  }

  @Override
  public void removeAttribute(String name) {
    attributeMap.remove(name);
  }

  @Override
  public Object getAttribute(String name) {
    return attributeMap.get(name);
  }

  @Override
  public Enumeration<String> getAttributeNames() {
    return new Enumeration<String>() {
      private Iterator<String> iterator = attributeMap.keySet()
          .iterator();

      @Override
      public boolean hasMoreElements() {
        return iterator.hasNext();
      }

      @Override
      public String nextElement() {
        return iterator.next();
      }
    };
  }
 
 
  //======================= get HTTP head and parameter =======================
 
  @Override
  public long getDateHeader(String name) {
    String v = getHeader(name);
    return v != null ? Long.parseLong(v) : 0;
  }

  @Override
  public String getHeader(String name) {
    return headMap.get(name.toLowerCase());
  }

  @Override
  public Enumeration<String> getHeaders(String name) {
    String value = getHeader(name);
    final String[] values = StringUtils.split(value, ',');
    return new Enumeration<String>() {
      private int i = 0;

      @Override
      public boolean hasMoreElements() {
        return i < values.length;
      }

      @Override
      public String nextElement() {
        return values[i++];
      }
    };
  }

  @Override
  public Enumeration<String> getHeaderNames() {
    return new Enumeration<String>() {
      private Iterator<String> iterator = headMap.keySet().iterator();

      @Override
      public boolean hasMoreElements() {
        return iterator.hasNext();
      }

      @Override
      public String nextElement() {
        return iterator.next();
      }
    };
  }

  @Override
  public int getIntHeader(String name) {
    String v = getHeader(name);
    return v != null ? Integer.parseInt(v) : 0;
  }

  @Override
  public String getMethod() {
    return method;
  }

  @Override
  public String getQueryString() {
    return queryString;
  }

  @Override
  public String getRequestURI() {
    return requestURI;
  }

  @Override
  public StringBuffer getRequestURL() {
    StringBuffer url = new StringBuffer();
    String scheme = getScheme();
    int port = getServerPort();
    if (port < 0)
      port = 80; // Work around java.net.URL bug

    url.append(scheme);
    url.append("://");
    url.append(getServerName());
    if ((scheme.equals("http") && (port != 80))
        || (scheme.equals("https") && (port != 443))) {
      url.append(':');
      url.append(port);
    }
    url.append(getRequestURI());
    return url;
  }

  @Override
  public String getCharacterEncoding() {
    return characterEncoding;
  }

  @Override
  public void setCharacterEncoding(String characterEncoding)
      throws UnsupportedEncodingException {
    this.characterEncoding = characterEncoding;
  }

  @Override
  public int getContentLength() {
    return getIntHeader("Content-Length");
  }

  @Override
  public String getContentType() {
    return getHeader("Content-Type");
  }

  @Override
  public String getParameter(String name) {
    loadParam();
    List<String> list = parameterMap.get(name);
    return list != null && list.size() > 0 ? list.get(0) : null;
  }

  @Override
  public Enumeration<String> getParameterNames() {
    loadParam();
    return new Enumeration<String>() {
      private Iterator<String> iterator = parameterMap.keySet()
          .iterator();

      @Override
      public boolean hasMoreElements() {
        return iterator.hasNext();
      }

      @Override
      public String nextElement() {
        return iterator.next();
      }
    };
  }

  @Override
  public String[] getParameterValues(String name) {
    loadParam();
    return parameterMap.get(name).toArray(EMPTY_STR_ARR);
  }

  @Override
  public Map<String, String[]> getParameterMap() {
    loadParam();
    if(_parameterMap == null) {
      _parameterMap = new HashMap<String, String[]>();
      for(Map.Entry<String, List<String>> entry : parameterMap.entrySet()) {
        _parameterMap.put(entry.getKey(), entry.getValue().toArray(EMPTY_STR_ARR));
      }
    }
    return _parameterMap;
  }
 
  @Override
  public Cookie[] getCookies() {
    if (cookies == null) {
      List<Cookie> list = new ArrayList<Cookie>();
      String cookieStr = getHeader("Cookie");
      if (VerifyUtils.isEmpty(cookieStr)) {
        cookies = EMPTY_COOKIE_ARR;
      } else {
        String[] c = StringUtils.split(cookieStr, ';');
        for (String t : c) {
          int j = 0;
          for (int i = 0; i < t.length(); i++) {
            if (t.charAt(i) == '=') {
              j = i;
              break;
            }
          }
          if (j > 1) {
            String name = t.substring(0, j).trim();
            String value = t.substring(j + 1).trim();
            Cookie cookie = new Cookie(name, value);
            list.add(cookie);
          } else
            continue;
        }
        cookies = list.toArray(EMPTY_COOKIE_ARR);
      }
    }
    return cookies;
  }

  @Override
  public String getProtocol() {
    return protocol;
  }

  @Override
  public String getScheme() {
    return "http";
  }
 
  @Override
  public Locale getLocale() {
    if (!localesParsed)
      parseLocales();

    if (locales.size() > 0) {
      return (locales.get(0));
    } else {
      return (DEFAULT_LOCALE);
    }
  }

  @Override
  public Enumeration<Locale> getLocales() {
    if (!localesParsed)
      parseLocales();

    if (locales.size() == 0)
      locales.add(DEFAULT_LOCALE);

    return new Enumeration<Locale>() {
      private int i = 0;

      @Override
      public boolean hasMoreElements() {
        return i < locales.size();
      }

      @Override
      public Locale nextElement() {
        return locales.get(i++);
      }
    };
  }
 
  protected void parseLocales() {
    localesParsed = true;
    Enumeration<String> values = getHeaders("accept-language");
    while (values.hasMoreElements()) {
      String value = values.nextElement().toString();
      parseLocalesHeader(value);
    }
  }

  /**
   * Parse accept-language header value.
   * @param value The head string
   */
  protected void parseLocalesHeader(String value) {

    // Store the accumulated languages that have been requested in
    // a local collection, sorted by the quality value (so we can
    // add Locales in descending order). The values will be ArrayLists
    // containing the corresponding Locales to be added
    TreeMap<Double, ArrayList<Locale>> locales = new TreeMap<Double, ArrayList<Locale>>();

    // Preprocess the value to remove all whitespace
    int white = value.indexOf(' ');
    if (white < 0)
      white = value.indexOf('\t');
    if (white >= 0) {
      StringBuilder sb = new StringBuilder();
      int len = value.length();
      for (int i = 0; i < len; i++) {
        char ch = value.charAt(i);
        if ((ch != ' ') && (ch != '\t'))
          sb.append(ch);
      }
      value = sb.toString();
    }

    // Process each comma-delimited language specification
    parser.setString(value); // ASSERT: parser is available to us
    int length = parser.getLength();
    while (true) {

      // Extract the next comma-delimited entry
      int start = parser.getIndex();
      if (start >= length)
        break;
      int end = parser.findChar(',');
      String entry = parser.extract(start, end).trim();
      parser.advance(); // For the following entry

      // Extract the quality factor for this entry
      double quality = 1.0;
      int semi = entry.indexOf(";q=");
      if (semi >= 0) {
        try {
          String strQuality = entry.substring(semi + 3);
          if (strQuality.length() <= 5) {
            quality = Double.parseDouble(strQuality);
          } else {
            quality = 0.0;
          }
        } catch (NumberFormatException e) {
          quality = 0.0;
        }
        entry = entry.substring(0, semi);
      }

      // Skip entries we are not going to keep track of
      if (quality < 0.00005)
        continue; // Zero (or effectively zero) quality factors
      if ("*".equals(entry))
        continue; // FIXME - "*" entries are not handled

      // Extract the language and country for this entry
      String language = null;
      String country = null;
      String variant = null;
      int dash = entry.indexOf('-');
      if (dash < 0) {
        language = entry;
        country = "";
        variant = "";
      } else {
        language = entry.substring(0, dash);
        country = entry.substring(dash + 1);
        int vDash = country.indexOf('-');
        if (vDash > 0) {
          String cTemp = country.substring(0, vDash);
          variant = country.substring(vDash + 1);
          country = cTemp;
        } else {
          variant = "";
        }
      }
      if (!isAlpha(language) || !isAlpha(country) || !isAlpha(variant)) {
        continue;
      }

      // Add a new Locale to the list of Locales for this quality level
      Locale locale = new Locale(language, country, variant);
      Double key = new Double(-quality); // Reverse the order
      ArrayList<Locale> values = locales.get(key);
      if (values == null) {
        values = new ArrayList<Locale>();
        locales.put(key, values);
      }
      values.add(locale);

    }

    // Process the quality values in highest->lowest order (due to
    // negating the Double value when creating the key)
    Iterator<Double> keys = locales.keySet().iterator();
    while (keys.hasNext()) {
      Double key = keys.next();
      ArrayList<Locale> list = locales.get(key);
      Iterator<Locale> values = list.iterator();
      while (values.hasNext()) {
        Locale locale = values.next();
        addLocale(locale);
      }
    }

  }

  protected static final boolean isAlpha(String value) {
    for (int i = 0; i < value.length(); i++) {
      char c = value.charAt(i);
      if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) {
        return false;
      }
    }
    return true;
  }

  protected void addLocale(Locale locale) {
    locales.add(locale);
  }
 
 
  //======================= get socket info =======================

  /**
   * @return server binding ip or host name
   */
  @Override
  public String getServerName() {
    return session.getLocalAddress().getHostName();
  }

  /**
   * @return server port
   */
  @Override
  public int getServerPort() {
    return session.getLocalAddress().getPort();
  }

  @Override
  public String getRemoteAddr() {
    return session.getRemoteAddress().toString();
  }

  @Override
  public String getRemoteHost() {
    return session.getRemoteAddress().getHostName();
  }
 
  @Override
  public int getRemotePort() {
    return session.getRemoteAddress().getPort();
  }


  @Override
  public String getLocalName() {
    return session.getLocalAddress().getHostName();
  }

  @Override
  public String getLocalAddr() {
    return session.getLocalAddress().toString();
  }

  @Override
  public int getLocalPort() {
    return session.getLocalAddress().getPort();
  }

 
  //======================= get servlet info =======================

  @Override
  public String getServletPath() {
    return config.getServletPath();
  }
 
  @Override
  public String getContextPath() {
    return config.getContextPath();
  }
 
  @Override
  public RequestDispatcher getRequestDispatcher(String path) {
    requestDispatcher.path = path;
    return requestDispatcher;
  }
 
  @Override
  public ServletContext getServletContext() {
    throw new HttpServerException("no implements this method!");
  }
 
  @Override
  public DispatcherType getDispatcherType() {
    // TODO need implement
    throw new HttpServerException("no implements this method!");
  }
 
  @Override
  public String getRealPath(String path) {
    // TODO need implement
    throw new HttpServerException("no implements this method!");
  }

  @Override
  public String getPathInfo() {
    // TODO need implement
    throw new HttpServerException("no implements this method!");
  }

  @Override
  public String getPathTranslated() {
    return new File(config.getServerHome(), getRequestURI()).getAbsolutePath();
  }

  //======================= authentication =======================
 
  @Override
  public String getRemoteUser() {
    // TODO need implement
    throw new HttpServerException("no implements this method!");
  }

  @Override
  public boolean isUserInRole(String role) {
    // TODO need implement
    throw new HttpServerException("no implements this method!");
  }

  @Override
  public Principal getUserPrincipal() {
    // TODO need implement
    throw new HttpServerException("no implements this method!");
  }

  @Override
  public String getAuthType() {
    // TODO need implement
    throw new HttpServerException("no implements this method!");
  }

  @Override
  public boolean isSecure() {
    // TODO need implement
    throw new HttpServerException("no implements this method!");
  }
 
  @Override
  public boolean authenticate(HttpServletResponse response)
      throws IOException, ServletException {
    // TODO need implement
    throw new HttpServerException("no implements this method!");
  }

  @Override
  public void login(String username, String password) throws ServletException {
    // TODO need implement
    throw new HttpServerException("no implements this method!");
  }

  @Override
  public void logout() throws ServletException {
    // TODO need implement
    throw new HttpServerException("no implements this method!");
  }

  @Override
  public String getRequestedSessionId() {
    return requestedSessionId;
  }

  @Override
  public HttpSession getSession(boolean create) {
    if (create) {
      httpSession = config.getHttpSessionManager().create();
      requestedSessionId = httpSession.getId();
      response.addCookie(new Cookie(config.getSessionIdName(),
          httpSession.getId()));
    } else {
      if (isRequestedSessionIdFromCookie()
          || isRequestedSessionIdFromURL()) {
        httpSession = config.getHttpSessionManager().get(
            requestedSessionId);
      }
    }

    return httpSession;
  }

  @Override
  public HttpSession getSession() {
    if (httpSession == null) {
      if (isRequestedSessionIdFromCookie()
          || isRequestedSessionIdFromURL())
        httpSession = config.getHttpSessionManager().get(
            requestedSessionId);

      if (httpSession == null)
        getSession(true);
    }
    return httpSession;
  }

  @Override
  public boolean isRequestedSessionIdValid() {
    return requestedSessionId != null ? config.getHttpSessionManager()
        .containsKey(requestedSessionId) : false;
  }

  @Override
  public boolean isRequestedSessionIdFromCookie() {
    if (requestedSessionId != null)
      return requestedSessionIdFromCookie;

    for (Cookie cookie : getCookies()) {
      if (cookie.getName().equals(config.getSessionIdName())) {
        requestedSessionId = cookie.getValue();
        requestedSessionIdFromCookie = true;
        return true;
      }
    }
    return false;
  }

  @Override
  public boolean isRequestedSessionIdFromURL() {
    if (requestedSessionId != null)
      return requestedSessionIdFromURL;

    String sessionId = getSessionId(requestURI, config.getSessionIdName());
    if (VerifyUtils.isNotEmpty(sessionId)) {
      requestedSessionId = sessionId;
      requestedSessionIdFromURL = true;
      return true;
    }
    return false;
  }

  public static String getSessionId(String uri, String sessionIdName) {
    String sessionId = null;
    int i = uri.indexOf(';');
    int j = uri.indexOf('#');
    if (i > 0) {
      String tmp = j > i ? uri.substring(i + 1, j) : uri.substring(i + 1);
      int m = 0;
      for (int k = 0; k < tmp.length(); k++) {
        if (tmp.charAt(k) == '=') {
          m = k;
          break;
        }
      }
      if (m > 0) {
        String name = tmp.substring(0, m);
        String value = tmp.substring(m + 1);
        if (name.equals(sessionIdName)) {
          sessionId = value;
        }
      }
    }
    return sessionId;
  }

  @Override
  public boolean isRequestedSessionIdFromUrl() {
    return isRequestedSessionIdFromURL();
  }

  @Override
  public String toString() {
    return method + " " + requestURI + queryString + " " + protocol + "\r\n" + headMap.toString();
  }

 

  //======================= asynchronous control =======================
  @Override
  public AsyncContext startAsync() throws IllegalStateException {
    return startAsync(this, response);
  }

  @Override
  public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException {
    if(asyncContext == null) {
      asyncContext = new AsyncContextImpl();
    }
    asyncContext.startAsync(servletRequest, servletResponse, (servletRequest == this && servletResponse == response), config.getMaxConnectionTimeout());
    return asyncContext;
  }

  @Override
  public boolean isAsyncStarted() {
    if(asyncContext == null)
      return false;
   
    return asyncContext.isStartAsync();
  }

  @Override
  public boolean isAsyncSupported() {
    return true;
  }

  @Override
  public AsyncContext getAsyncContext() {
    if(!isAsyncStarted())
      throw new IllegalStateException("async context not start!");
     
    return asyncContext;
  }

 

  //======================= multipart data =======================

  @Override
  public Collection<Part> getParts() throws IOException, ServletException {
    if(multipartFormData == null) {
      ServletInputStream input = null;
      try {
        input = getInputStream();
        PartImpl.tempdir = config.getTempdir();
        multipartFormData = new MultipartFormData(MultipartFormDataParser.parse(input, getHeader("Content-Type"), characterEncoding));
      } finally {
        input.close();
      }
    }
   
    return multipartFormData.getParts();
  }

  @Override
  public Part getPart(String name) throws IOException, ServletException {
    if(multipartFormData == null)
      getParts();
   
    return multipartFormData.getPart(name);
  }

}
TOP

Related Classes of com.firefly.server.http.HttpServletRequestImpl

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.