public JettyRequestAPIData()

in runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/http/JettyRequestAPIData.java [115:322]


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

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

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

    HttpFields.Mutable fields = HttpFields.build();
    for (HttpField field : request.getHeaders()) {
      // 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.getLowerCaseName();
      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 = field.getLongValue();
          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 = HttpURI.build(request.getHttpURI()).scheme(HttpScheme.HTTPS);
      isSecure = true;
    } else {
      httpURI = request.getHttpURI();
      isSecure = request.isSecure();
    }

    String decodedPath = request.getHttpURI().getDecodedPath();
    if (BACKGROUND_REQUEST_URL.equals(decodedPath)) {
      if (WARMUP_IP.equals(userIp)) {
        requestType = RuntimePb.UPRequest.RequestType.BACKGROUND;
      }
    } else if (WARMUP_REQUEST_URL.equals(decodedPath)) {
      if (WARMUP_IP.equals(userIp)) {
        // 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;
      }
    }

    StringBuilder sb = new StringBuilder(HttpURI.build(httpURI).query(null).asString());
    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 =
          com.google.apphosting.base.protos.TracePb.TraceContextProto.getDefaultInstance();

    String finalUserIp = userIp;
    this.originalRequest = request;
    this.request =
        new Request.Wrapper(request) {
          @Override
          public HttpURI getHttpURI() {
            return httpURI;
          }

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

          @Override
          public HttpFields getHeaders() {
            return fields;
          }

          @Override
          public ConnectionMetaData getConnectionMetaData() {
            return new ConnectionMetaData.Wrapper(super.getConnectionMetaData()) {
              @Override
              public SocketAddress getRemoteSocketAddress() {
                return InetSocketAddress.createUnresolved(finalUserIp, 0);
              }

              @Override
              public HostPort getServerAuthority() {
                return new HostPort(UNSPECIFIED_IP, 0);
              }

              @Override
              public SocketAddress getLocalSocketAddress() {
                return InetSocketAddress.createUnresolved(UNSPECIFIED_IP, 0);
              }
            };
          }
        };
  }