public JettyRequestAPIData()

in runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/JettyRequestAPIData.java [117:369]


  public JettyRequestAPIData(
      Request request,
      HttpServletRequest httpServletRequest,
      AppInfoFactory appInfoFactory,
      boolean passThroughPrivateHeaders) {
    this.appInfoFactory = appInfoFactory;

    // Can be overridden by X_APPENGINE_USER_IP header.
    String userIp = request.getRemoteAddr();

    // Can be overridden by X_APPENGINE_API_TICKET header.
    this.securityTicket = DEFAULT_SECRET_KEY;

    HttpFields fields = new HttpFields();
    for (HttpField field : request.getHttpFields()) {
      // If it has a HttpHeader it is one of the standard headers so won't match any appengine
      // specific header.
      if (field.getHeader() != null) {
        fields.add(field);
        continue;
      }

      String name = field.getName().toLowerCase(Locale.ROOT);
      String value = field.getValue();
      if (Strings.isNullOrEmpty(value)) {
        continue;
      }

      switch (name) {
        case X_APPENGINE_TRUSTED_IP_REQUEST:
          // If there is a value, then the application is trusted
          // If the value is IS_TRUSTED, then the user is trusted
          isTrusted = value.equals(IS_TRUSTED);
          isTrustedApp = true;
          break;
        case X_APPENGINE_HTTPS:
          isHttps = value.equals("on");
          break;
        case X_APPENGINE_USER_IP:
          userIp = value;
          break;
        case X_FORWARDED_PROTO:
          isHttps = value.equals("https");
          break;
        case X_APPENGINE_USER_ID:
          obfuscatedGaiaId = value;
          break;
        case X_APPENGINE_USER_ORGANIZATION:
          userOrganization = value;
          break;
        case X_APPENGINE_LOAS_PEER_USERNAME:
          peerUsername = value;
          break;
        case X_APPENGINE_GAIA_ID:
          gaiaId = Long.parseLong(value);
          break;
        case X_APPENGINE_GAIA_AUTHUSER:
          authUser = value;
          break;
        case X_APPENGINE_GAIA_SESSION:
          gaiaSession = value;
          break;
        case X_APPENGINE_APPSERVER_DATACENTER:
          appserverDataCenter = value;
          break;
        case X_APPENGINE_APPSERVER_TASK_BNS:
          appserverTaskBns = value;
          break;
        case X_APPENGINE_ID_HASH:
          eventIdHash = value;
          break;
        case X_APPENGINE_REQUEST_LOG_ID:
          requestLogId = value;
          break;
        case X_APPENGINE_DEFAULT_VERSION_HOSTNAME:
          defaultVersionHostname = value;
          break;
        case X_APPENGINE_USER_IS_ADMIN:
          isAdmin = Objects.equals(value, IS_ADMIN_HEADER_VALUE);
          break;
        case X_APPENGINE_USER_EMAIL:
          email = value;
          break;
        case X_APPENGINE_AUTH_DOMAIN:
          authDomain = value;
          break;
        case X_APPENGINE_API_TICKET:
          securityTicket = value;
          break;

        case X_CLOUD_TRACE_CONTEXT:
          try {
            traceContext = TraceContextHelper.parseTraceContextHeader(value);
          } catch (NumberFormatException e) {
            logger.atWarning().withCause(e).log("Could not parse trace context header: %s", value);
          }
          break;

        case X_GOOGLE_INTERNAL_SKIPADMINCHECK:
          request.setAttribute(SKIP_ADMIN_CHECK_ATTR, true);
          isHttps = true;
          break;

        case X_APPENGINE_QUEUENAME:
          request.setAttribute(SKIP_ADMIN_CHECK_ATTR, true);
          isOffline = true;
          break;

        case X_APPENGINE_TIMEOUT_MS:
          duration = Duration.ofMillis(Long.parseLong(value));
          break;

        case X_GOOGLE_INTERNAL_PROFILER:
          /* TODO: what to do here?
          try {
            TextFormat.merge(value, upReqBuilder.getProfilerSettingsBuilder());
          } catch (IOException ex) {
            throw new IllegalStateException("X-Google-Internal-Profiler read content error:", ex);
          }
           */
          break;

        case X_APPENGINE_BACKGROUNDREQUEST:
          backgroundRequestId = value;
          break;

        default:
          break;
      }

      if (passThroughPrivateHeaders || !PRIVATE_APPENGINE_HEADERS.contains(name)) {
        // Only non AppEngine specific headers are passed to the application.
        fields.add(field);
      }
    }

    HttpURI httpUri;
    boolean isSecure;
    if (isHttps) {
      httpUri = new HttpURI(request.getHttpURI());
      httpUri.setScheme(HttpScheme.HTTPS.asString());
      isSecure = true;
    } else {
      httpUri = request.getHttpURI();
      isSecure = request.isSecure();
    }

    String decodedPath = request.getHttpURI().getDecodedPath();
    if (Objects.equals(decodedPath, BACKGROUND_REQUEST_URL)) {
      if (Objects.equals(userIp, WARMUP_IP)) {
        requestType = RuntimePb.UPRequest.RequestType.BACKGROUND;
      }
    } else if (Objects.equals(decodedPath, WARMUP_REQUEST_URL)) {
      if (Objects.equals(userIp, WARMUP_IP)) {
        // This request came from within App Engine via secure internal channels; tell Jetty
        // it's HTTPS to avoid 403 because of web.xml security-constraint checks.
        isHttps = true;
      }
    }

    HttpURI uri = new HttpURI(httpUri);
    uri.setQuery(null);
    StringBuilder sb = new StringBuilder(uri.toString());
    String query = httpUri.getQuery();
    // No need to escape, URL retains any %-escaping it might have, which is what we want.
    if (query != null) {
      sb.append('?').append(query);
    }
    url = sb.toString();

    if (traceContext == null) {
      traceContext = TraceContextProto.getDefaultInstance();
    }

    String finalUserIp = NORMALIZE_INET_ADDR ? HostPort.normalizeHost(userIp) : userIp;
    this.httpServletRequest =
        new HttpServletRequestWrapper(httpServletRequest) {

          @Override
          public long getDateHeader(String name) {
            return fields.getDateField(name);
          }

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

          @Override
          public Enumeration<String> getHeaders(String name) {
            return fields.getValues(name);
          }

          @Override
          public Enumeration<String> getHeaderNames() {
            return fields.getFieldNames();
          }

          @Override
          public int getIntHeader(String name) {
            return Math.toIntExact(fields.getLongField(name));
          }

          @Override
          public String getRequestURI() {
            return httpUri.getPath();
          }

          @Override
          public String getScheme() {
            return httpUri.getScheme();
          }

          @Override
          public boolean isSecure() {
            return isSecure;
          }

          @Override
          public String getRemoteAddr() {
            return finalUserIp;
          }

          @Override
          public String getRemoteHost() {
            return finalUserIp;
          }

          @Override
          public int getRemotePort() {
            return 0;
          }

          @Override
          public String getLocalName() {
            return UNSPECIFIED_IP;
          }

          @Override
          public String getLocalAddr() {
            return UNSPECIFIED_IP;
          }

          @Override
          public int getLocalPort() {
            return 0;
          }
        };

    this.baseRequest = request;
    this.baseRequest.setSecure(isSecure);
    this.baseRequest.setHttpURI(httpUri);
  }