001package ca.uhn.fhir.rest.server; 002 003/*- 004 * #%L 005 * HAPI FHIR - Server Framework 006 * %% 007 * Copyright (C) 2014 - 2022 Smile CDR, Inc. 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import ca.uhn.fhir.rest.api.Constants; 024import org.apache.commons.lang3.RandomStringUtils; 025import org.slf4j.Logger; 026import org.slf4j.LoggerFactory; 027 028import javax.annotation.Nullable; 029import javax.servlet.ServletRequest; 030import javax.servlet.http.HttpServletRequest; 031 032import static org.apache.commons.lang3.StringUtils.isBlank; 033import static org.apache.commons.lang3.StringUtils.isNotBlank; 034 035public class ServletRequestTracing { 036 private static final Logger ourLog = LoggerFactory.getLogger(ServletRequestTracing.class); 037 public static final String ATTRIBUTE_REQUEST_ID = ServletRequestTracing.class.getName() + '.' + Constants.HEADER_REQUEST_ID; 038 039 ServletRequestTracing() { } 040 041 /** 042 * Assign a tracing id to this request, using 043 * the X-Request-ID if present and compatible. 044 * 045 * If none present, generate a 64 random alpha-numeric string that is not 046 * cryptographically secure. 047 * 048 * @param theServletRequest the request to trace 049 * @return the tracing id 050 */ 051 public static String getOrGenerateRequestId(ServletRequest theServletRequest) { 052 String requestId = maybeGetRequestId(theServletRequest); 053 if (isBlank(requestId)) { 054 requestId = RandomStringUtils.randomAlphanumeric(Constants.REQUEST_ID_LENGTH); 055 } 056 057 ourLog.debug("Assigned tracing id {}", requestId); 058 059 theServletRequest.setAttribute(ATTRIBUTE_REQUEST_ID, requestId); 060 061 return requestId; 062 } 063 064 @Nullable 065 public static String maybeGetRequestId(ServletRequest theServletRequest) { 066 // have we already seen this request? 067 String requestId = (String) theServletRequest.getAttribute(ATTRIBUTE_REQUEST_ID); 068 069 if (requestId == null && theServletRequest instanceof HttpServletRequest) { 070 // Also applies to non-FHIR (e.g. admin-json) requests). 071 HttpServletRequest request = (HttpServletRequest) theServletRequest; 072 requestId = request.getHeader(Constants.HEADER_REQUEST_ID); 073 if (isNotBlank(requestId)) { 074 for (char nextChar : requestId.toCharArray()) { 075 if (!Character.isLetterOrDigit(nextChar)) { 076 if (nextChar != '.' && nextChar != '-' && nextChar != '_' && nextChar != ' ') { 077 requestId = null; 078 break; 079 } 080 } 081 } 082 } 083 } 084 return requestId; 085 } 086 087}