content: /*
   * Copyright 1999-2023 Alibaba Group Holding Ltd.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.alibaba.nacos.core.context.remote;
  
  import com.alibaba.nacos.common.constant.HttpHeaderConsts;
  import com.alibaba.nacos.common.utils.StringUtils;
  import com.alibaba.nacos.core.context.RequestContext;
  import com.alibaba.nacos.core.context.RequestContextHolder;
  import com.alibaba.nacos.core.context.addition.BasicContext;
  import com.alibaba.nacos.core.utils.WebUtils;
  
  import jakarta.servlet.Filter;
  import jakarta.servlet.FilterChain;
  import jakarta.servlet.ServletException;
  import jakarta.servlet.ServletRequest;
  import jakarta.servlet.ServletResponse;
  import jakarta.servlet.http.HttpServletRequest;
  import org.apache.hc.core5.http.HttpHeaders;
  
  import java.io.IOException;
  
  import static com.alibaba.nacos.api.common.Constants.CLIENT_APPNAME_HEADER;
  
  /**
   * The Filter to add request context for HTTP protocol.
   *
   * @author xiweng.yy
   */
  public class HttpRequestContextFilter implements Filter {
      
      private static final String PATTERN_REQUEST_TARGET = "%s %s";
      
      @Override
      public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
              throws IOException, ServletException {
          RequestContext requestContext = RequestContextHolder.getContext();
          try {
              requestContext.getBasicContext().setRequestProtocol(BasicContext.HTTP_PROTOCOL);
              HttpServletRequest request = (HttpServletRequest) servletRequest;
              setRequestTarget(request, requestContext);
              setEncoding(request, requestContext);
              setAddressContext(request, requestContext);
              setOtherBasicContext(request, requestContext);
              filterChain.doFilter(servletRequest, servletResponse);
          } finally {
              RequestContextHolder.removeContext();
          }
      }
      
      private void setRequestTarget(HttpServletRequest request, RequestContext requestContext) {
          String uri = request.getRequestURI();
          String method = request.getMethod();
          requestContext.getBasicContext().setRequestTarget(String.format(PATTERN_REQUEST_TARGET, method, uri));
      }
      
      private void setEncoding(HttpServletRequest request, RequestContext requestContext) {
          String encoding = request.getCharacterEncoding();
          if (StringUtils.isNotBlank(encoding)) {
              requestContext.getBasicContext().setEncoding(encoding);
          }
      }
      
      private void setAddressContext(HttpServletRequest request, RequestContext requestContext) {
          String remoteAddress = request.getRemoteAddr();
          int remotePort = request.getRemotePort();
          String sourceIp = WebUtils.getRemoteIp(request);
          String host = request.getHeader(HttpHeaders.HOST);
          requestContext.getBasicContext().getAddressContext().setRemoteIp(remoteAddress);
          requestContext.getBasicContext().getAddressContext().setRemotePort(remotePort);
          requestContext.getBasicContext().getAddressContext().setSourceIp(sourceIp);
          requestContext.getBasicContext().getAddressContext().setHost(host);
      }
      
      private void setOtherBasicContext(HttpServletRequest request, RequestContext requestContext) {
          String userAgent = WebUtils.getUserAgent(request);
          requestContext.getBasicContext().setUserAgent(userAgent);
          String app = getAppName(request);
          if (StringUtils.isNotBlank(app)) {
              requestContext.getBasicContext().setApp(app);
          }
      }
      
      private String getAppName(HttpServletRequest request) {
          String app = request.getHeader(HttpHeaderConsts.APP_FILED);
          if (StringUtils.isBlank(app)) {
              app = request.getHeader(CLIENT_APPNAME_HEADER);
          }
          return app;
      }
  }
  