LCOV - code coverage report
Current view: top level - server/notedb - NoteDbUtil.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 56 66 84.8 %
Date: 2022-11-19 15:00:39 Functions: 10 11 90.9 %

          Line data    Source code
       1             : // Copyright (C) 2017 The Android Open Source Project
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License");
       4             : // you may not use this file except in compliance with the License.
       5             : // You may obtain a copy of the License at
       6             : //
       7             : // http://www.apache.org/licenses/LICENSE-2.0
       8             : //
       9             : // Unless required by applicable law or agreed to in writing, software
      10             : // distributed under the License is distributed on an "AS IS" BASIS,
      11             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             : // See the License for the specific language governing permissions and
      13             : // limitations under the License.
      14             : 
      15             : package com.google.gerrit.server.notedb;
      16             : 
      17             : import com.google.common.base.CharMatcher;
      18             : import com.google.common.collect.ImmutableList;
      19             : import com.google.common.collect.ImmutableSet;
      20             : import com.google.common.primitives.Ints;
      21             : import com.google.gerrit.common.Nullable;
      22             : import com.google.gerrit.entities.Account;
      23             : import com.google.gerrit.extensions.restapi.RestModifyView;
      24             : import com.google.gerrit.server.account.externalids.ExternalId;
      25             : import com.google.gerrit.server.account.externalids.ExternalIdCache;
      26             : import java.io.IOException;
      27             : import java.sql.Timestamp;
      28             : import java.util.Optional;
      29             : import org.eclipse.jgit.errors.ConfigInvalidException;
      30             : import org.eclipse.jgit.lib.PersonIdent;
      31             : import org.eclipse.jgit.util.GitDateFormatter;
      32             : import org.eclipse.jgit.util.GitDateFormatter.Format;
      33             : 
      34             : public class NoteDbUtil {
      35             : 
      36         104 :   private static final CharMatcher INVALID_FOOTER_CHARS = CharMatcher.anyOf("\r\n\0");
      37             : 
      38         104 :   private static final ImmutableList<String> PACKAGE_PREFIXES =
      39         104 :       ImmutableList.of("com.google.gerrit.server.", "com.google.gerrit.");
      40         104 :   private static final ImmutableSet<String> SERVLET_NAMES =
      41         104 :       ImmutableSet.of("com.google.gerrit.httpd.restapi.RestApiServlet");
      42             : 
      43             :   /** Returns an AccountId for the given email address. */
      44             :   public static Optional<Account.Id> parseIdent(PersonIdent ident) {
      45          54 :     String email = ident.getEmailAddress();
      46          54 :     int at = email.indexOf('@');
      47          54 :     if (at >= 0) {
      48          54 :       Integer id = Ints.tryParse(email.substring(0, at));
      49          54 :       if (id != null) {
      50          54 :         return Optional.of(Account.id(id));
      51             :       }
      52             :     }
      53           3 :     return Optional.empty();
      54             :   }
      55             : 
      56             :   /**
      57             :    * Returns an AccountId for the given email address and the current serverId. Reverse lookup the
      58             :    * AccountId using the ExternalIdCache if the account has a foreign serverId.
      59             :    *
      60             :    * @param ident the accountId@serverId identity
      61             :    * @param serverId the Gerrit's serverId
      62             :    * @param externalIdCache reference to the cache for looking up the external ids
      63             :    * @return a defined accountId if the account was found, {@link Account#UNKNOWN_ACCOUNT_ID} if the
      64             :    *     lookup via external-id did not return any account, or an empty value if the identity was
      65             :    *     malformed.
      66             :    * @throws ConfigInvalidException when the lookup of the external-id failed
      67             :    */
      68             :   public static Optional<Account.Id> parseIdent(
      69             :       PersonIdent ident, String serverId, ExternalIdCache externalIdCache)
      70             :       throws ConfigInvalidException {
      71         103 :     String email = ident.getEmailAddress();
      72         103 :     int at = email.indexOf('@');
      73         103 :     if (at >= 0) {
      74         103 :       Integer id = Ints.tryParse(email.substring(0, at));
      75         103 :       String accountServerId = email.substring(at + 1);
      76         103 :       if (id != null) {
      77         103 :         if (accountServerId.equals(serverId)) {
      78         103 :           return Optional.of(Account.id(id));
      79             :         }
      80             : 
      81           1 :         ExternalId.Key extIdKey = ExternalId.Key.create(ExternalId.SCHEME_IMPORTED, email, false);
      82             :         try {
      83           1 :           return externalIdCache
      84           1 :               .byKey(extIdKey)
      85           1 :               .map(ExternalId::accountId)
      86           1 :               .or(() -> Optional.of(Account.UNKNOWN_ACCOUNT_ID));
      87           0 :         } catch (IOException e) {
      88           0 :           throw new ConfigInvalidException("Unable to lookup external id from cache", e);
      89             :         }
      90             :       }
      91             :     }
      92           1 :     return Optional.empty();
      93             :   }
      94             : 
      95             :   public static String extractHostPartFromPersonIdent(PersonIdent ident) {
      96         103 :     String email = ident.getEmailAddress();
      97         103 :     int at = email.indexOf('@');
      98         103 :     if (at >= 0) {
      99         103 :       return email.substring(at + 1);
     100             :     }
     101           0 :     throw new IllegalArgumentException("No host part found: " + email);
     102             :   }
     103             : 
     104             :   public static String formatTime(PersonIdent ident, Timestamp t) {
     105           0 :     GitDateFormatter dateFormatter = new GitDateFormatter(Format.DEFAULT);
     106             :     // TODO(dborowitz): Use a ThreadLocal or use Joda.
     107           0 :     PersonIdent newIdent = new PersonIdent(ident, t);
     108           0 :     return dateFormatter.formatDate(newIdent);
     109             :   }
     110             : 
     111             :   /**
     112             :    * Returns the name of the REST API handler that is in the stack trace of the caller of this
     113             :    * method.
     114             :    */
     115             :   @Nullable
     116             :   static String guessRestApiHandler() {
     117          91 :     StackTraceElement[] trace = Thread.currentThread().getStackTrace();
     118          91 :     int i = findRestApiServlet(trace);
     119          91 :     if (i < 0) {
     120          90 :       i = findApiImpl(trace);
     121             :     }
     122          91 :     if (i < 0) {
     123          62 :       return null;
     124             :     }
     125             :     try {
     126          84 :       for (i--; i >= 0; i--) {
     127          84 :         String cn = trace[i].getClassName();
     128          84 :         Class<?> cls = Class.forName(cn);
     129          84 :         if (RestModifyView.class.isAssignableFrom(cls)) {
     130          79 :           return viewName(cn);
     131             :         }
     132             :       }
     133          31 :       return null;
     134           0 :     } catch (ClassNotFoundException e) {
     135           0 :       return null;
     136             :     }
     137             :   }
     138             : 
     139             :   static String sanitizeFooter(String value) {
     140             :     // Remove characters that would confuse JGit's footer parser if they were
     141             :     // included in footer values, for example by splitting the footer block into
     142             :     // multiple paragraphs.
     143             :     //
     144             :     // One painful example: RevCommit#getShorMessage() might return a message
     145             :     // containing "\r\r", which RevCommit#getFooterLines() will treat as an
     146             :     // empty paragraph for the purposes of footer parsing.
     147         103 :     return INVALID_FOOTER_CHARS.trimAndCollapseFrom(value, ' ');
     148             :   }
     149             : 
     150             :   private static int findRestApiServlet(StackTraceElement[] trace) {
     151          91 :     for (int i = 0; i < trace.length; i++) {
     152          91 :       if (SERVLET_NAMES.contains(trace[i].getClassName())) {
     153          10 :         return i;
     154             :       }
     155             :     }
     156          90 :     return -1;
     157             :   }
     158             : 
     159             :   private static int findApiImpl(StackTraceElement[] trace) {
     160          90 :     for (int i = 0; i < trace.length; i++) {
     161          90 :       String clazz = trace[i].getClassName();
     162          90 :       if (clazz.startsWith("com.google.gerrit.server.api.") && clazz.endsWith("ApiImpl")) {
     163          82 :         return i;
     164             :       }
     165             :     }
     166          62 :     return -1;
     167             :   }
     168             : 
     169             :   private static String viewName(String cn) {
     170          79 :     String impl = cn.replace('$', '.');
     171          79 :     for (String p : PACKAGE_PREFIXES) {
     172          79 :       if (impl.startsWith(p)) {
     173          79 :         return impl.substring(p.length());
     174             :       }
     175           0 :     }
     176           0 :     return impl;
     177             :   }
     178             : 
     179             :   private NoteDbUtil() {}
     180             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750