diff --git a/cmd/api-errors.go b/cmd/api-errors.go index 3b3496107..d95d23225 100644 --- a/cmd/api-errors.go +++ b/cmd/api-errors.go @@ -24,6 +24,7 @@ import ( "fmt" "net/http" "net/url" + "os" "strconv" "strings" @@ -297,7 +298,6 @@ const ( ErrAdminConfigLDAPValidation ErrAdminConfigIDPCfgNameAlreadyExists ErrAdminConfigIDPCfgNameDoesNotExist - ErrAdminCredentialsMismatch ErrInsecureClientRequest ErrObjectTampered @@ -1425,11 +1425,6 @@ var errorCodes = errorCodeMap{ Description: "Unable to perform the requested operation because profiling is not enabled", HTTPStatusCode: http.StatusBadRequest, }, - ErrAdminCredentialsMismatch: { - Code: "XMinioAdminCredentialsMismatch", - Description: "Credentials in config mismatch with server environment variables", - HTTPStatusCode: http.StatusServiceUnavailable, - }, ErrAdminBucketQuotaExceeded: { Code: "XMinioAdminBucketQuotaExceeded", Description: "Bucket quota exceeded", @@ -2082,6 +2077,11 @@ func toAPIErrorCode(ctx context.Context, err error) (apiErr APIErrorCode) { return ErrNone } + // Errors that are generated by net.Conn and any context errors must be handled here. + if errors.Is(err, os.ErrDeadlineExceeded) || errors.Is(err, context.DeadlineExceeded) { + return ErrRequestTimedout + } + // Only return ErrClientDisconnected if the provided context is actually canceled. // This way downstream context.Canceled will still report ErrRequestTimedout if contextCanceled(ctx) && errors.Is(ctx.Err(), context.Canceled) { diff --git a/cmd/api-response.go b/cmd/api-response.go index d713fc5f8..78c081fea 100644 --- a/cmd/api-response.go +++ b/cmd/api-response.go @@ -946,11 +946,13 @@ func writeSuccessResponseHeadersOnly(w http.ResponseWriter) { // writeErrorRespone writes error headers func writeErrorResponse(ctx context.Context, w http.ResponseWriter, err APIError, reqURL *url.URL) { - switch err.Code { - case "SlowDown", "XMinioServerNotInitialized", "XMinioReadQuorum", "XMinioWriteQuorum": + if err.HTTPStatusCode == http.StatusServiceUnavailable { // Set retry-after header to indicate user-agents to retry request after 120secs. // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After w.Header().Set(xhttp.RetryAfter, "120") + } + + switch err.Code { case "InvalidRegion": err.Description = fmt.Sprintf("Region does not match; expecting '%s'.", globalSite.Region) case "AuthorizationHeaderMalformed": diff --git a/cmd/apierrorcode_string.go b/cmd/apierrorcode_string.go index 24a01a2cc..9e5ee1e0d 100644 --- a/cmd/apierrorcode_string.go +++ b/cmd/apierrorcode_string.go @@ -208,132 +208,131 @@ func _() { _ = x[ErrAdminConfigLDAPValidation-197] _ = x[ErrAdminConfigIDPCfgNameAlreadyExists-198] _ = x[ErrAdminConfigIDPCfgNameDoesNotExist-199] - _ = x[ErrAdminCredentialsMismatch-200] - _ = x[ErrInsecureClientRequest-201] - _ = x[ErrObjectTampered-202] - _ = x[ErrSiteReplicationInvalidRequest-203] - _ = x[ErrSiteReplicationPeerResp-204] - _ = x[ErrSiteReplicationBackendIssue-205] - _ = x[ErrSiteReplicationServiceAccountError-206] - _ = x[ErrSiteReplicationBucketConfigError-207] - _ = x[ErrSiteReplicationBucketMetaError-208] - _ = x[ErrSiteReplicationIAMError-209] - _ = x[ErrSiteReplicationConfigMissing-210] - _ = x[ErrSiteReplicationIAMConfigMismatch-211] - _ = x[ErrAdminRebalanceAlreadyStarted-212] - _ = x[ErrAdminRebalanceNotStarted-213] - _ = x[ErrAdminBucketQuotaExceeded-214] - _ = x[ErrAdminNoSuchQuotaConfiguration-215] - _ = x[ErrHealNotImplemented-216] - _ = x[ErrHealNoSuchProcess-217] - _ = x[ErrHealInvalidClientToken-218] - _ = x[ErrHealMissingBucket-219] - _ = x[ErrHealAlreadyRunning-220] - _ = x[ErrHealOverlappingPaths-221] - _ = x[ErrIncorrectContinuationToken-222] - _ = x[ErrEmptyRequestBody-223] - _ = x[ErrUnsupportedFunction-224] - _ = x[ErrInvalidExpressionType-225] - _ = x[ErrBusy-226] - _ = x[ErrUnauthorizedAccess-227] - _ = x[ErrExpressionTooLong-228] - _ = x[ErrIllegalSQLFunctionArgument-229] - _ = x[ErrInvalidKeyPath-230] - _ = x[ErrInvalidCompressionFormat-231] - _ = x[ErrInvalidFileHeaderInfo-232] - _ = x[ErrInvalidJSONType-233] - _ = x[ErrInvalidQuoteFields-234] - _ = x[ErrInvalidRequestParameter-235] - _ = x[ErrInvalidDataType-236] - _ = x[ErrInvalidTextEncoding-237] - _ = x[ErrInvalidDataSource-238] - _ = x[ErrInvalidTableAlias-239] - _ = x[ErrMissingRequiredParameter-240] - _ = x[ErrObjectSerializationConflict-241] - _ = x[ErrUnsupportedSQLOperation-242] - _ = x[ErrUnsupportedSQLStructure-243] - _ = x[ErrUnsupportedSyntax-244] - _ = x[ErrUnsupportedRangeHeader-245] - _ = x[ErrLexerInvalidChar-246] - _ = x[ErrLexerInvalidOperator-247] - _ = x[ErrLexerInvalidLiteral-248] - _ = x[ErrLexerInvalidIONLiteral-249] - _ = x[ErrParseExpectedDatePart-250] - _ = x[ErrParseExpectedKeyword-251] - _ = x[ErrParseExpectedTokenType-252] - _ = x[ErrParseExpected2TokenTypes-253] - _ = x[ErrParseExpectedNumber-254] - _ = x[ErrParseExpectedRightParenBuiltinFunctionCall-255] - _ = x[ErrParseExpectedTypeName-256] - _ = x[ErrParseExpectedWhenClause-257] - _ = x[ErrParseUnsupportedToken-258] - _ = x[ErrParseUnsupportedLiteralsGroupBy-259] - _ = x[ErrParseExpectedMember-260] - _ = x[ErrParseUnsupportedSelect-261] - _ = x[ErrParseUnsupportedCase-262] - _ = x[ErrParseUnsupportedCaseClause-263] - _ = x[ErrParseUnsupportedAlias-264] - _ = x[ErrParseUnsupportedSyntax-265] - _ = x[ErrParseUnknownOperator-266] - _ = x[ErrParseMissingIdentAfterAt-267] - _ = x[ErrParseUnexpectedOperator-268] - _ = x[ErrParseUnexpectedTerm-269] - _ = x[ErrParseUnexpectedToken-270] - _ = x[ErrParseUnexpectedKeyword-271] - _ = x[ErrParseExpectedExpression-272] - _ = x[ErrParseExpectedLeftParenAfterCast-273] - _ = x[ErrParseExpectedLeftParenValueConstructor-274] - _ = x[ErrParseExpectedLeftParenBuiltinFunctionCall-275] - _ = x[ErrParseExpectedArgumentDelimiter-276] - _ = x[ErrParseCastArity-277] - _ = x[ErrParseInvalidTypeParam-278] - _ = x[ErrParseEmptySelect-279] - _ = x[ErrParseSelectMissingFrom-280] - _ = x[ErrParseExpectedIdentForGroupName-281] - _ = x[ErrParseExpectedIdentForAlias-282] - _ = x[ErrParseUnsupportedCallWithStar-283] - _ = x[ErrParseNonUnaryAgregateFunctionCall-284] - _ = x[ErrParseMalformedJoin-285] - _ = x[ErrParseExpectedIdentForAt-286] - _ = x[ErrParseAsteriskIsNotAloneInSelectList-287] - _ = x[ErrParseCannotMixSqbAndWildcardInSelectList-288] - _ = x[ErrParseInvalidContextForWildcardInSelectList-289] - _ = x[ErrIncorrectSQLFunctionArgumentType-290] - _ = x[ErrValueParseFailure-291] - _ = x[ErrEvaluatorInvalidArguments-292] - _ = x[ErrIntegerOverflow-293] - _ = x[ErrLikeInvalidInputs-294] - _ = x[ErrCastFailed-295] - _ = x[ErrInvalidCast-296] - _ = x[ErrEvaluatorInvalidTimestampFormatPattern-297] - _ = x[ErrEvaluatorInvalidTimestampFormatPatternSymbolForParsing-298] - _ = x[ErrEvaluatorTimestampFormatPatternDuplicateFields-299] - _ = x[ErrEvaluatorTimestampFormatPatternHourClockAmPmMismatch-300] - _ = x[ErrEvaluatorUnterminatedTimestampFormatPatternToken-301] - _ = x[ErrEvaluatorInvalidTimestampFormatPatternToken-302] - _ = x[ErrEvaluatorInvalidTimestampFormatPatternSymbol-303] - _ = x[ErrEvaluatorBindingDoesNotExist-304] - _ = x[ErrMissingHeaders-305] - _ = x[ErrInvalidColumnIndex-306] - _ = x[ErrAdminConfigNotificationTargetsFailed-307] - _ = x[ErrAdminProfilerNotEnabled-308] - _ = x[ErrInvalidDecompressedSize-309] - _ = x[ErrAddUserInvalidArgument-310] - _ = x[ErrAdminResourceInvalidArgument-311] - _ = x[ErrAdminAccountNotEligible-312] - _ = x[ErrAccountNotEligible-313] - _ = x[ErrAdminServiceAccountNotFound-314] - _ = x[ErrPostPolicyConditionInvalidFormat-315] - _ = x[ErrInvalidChecksum-316] - _ = x[ErrLambdaARNInvalid-317] - _ = x[ErrLambdaARNNotFound-318] - _ = x[ErrInvalidAttributeName-319] - _ = x[apiErrCodeEnd-320] + _ = x[ErrInsecureClientRequest-200] + _ = x[ErrObjectTampered-201] + _ = x[ErrSiteReplicationInvalidRequest-202] + _ = x[ErrSiteReplicationPeerResp-203] + _ = x[ErrSiteReplicationBackendIssue-204] + _ = x[ErrSiteReplicationServiceAccountError-205] + _ = x[ErrSiteReplicationBucketConfigError-206] + _ = x[ErrSiteReplicationBucketMetaError-207] + _ = x[ErrSiteReplicationIAMError-208] + _ = x[ErrSiteReplicationConfigMissing-209] + _ = x[ErrSiteReplicationIAMConfigMismatch-210] + _ = x[ErrAdminRebalanceAlreadyStarted-211] + _ = x[ErrAdminRebalanceNotStarted-212] + _ = x[ErrAdminBucketQuotaExceeded-213] + _ = x[ErrAdminNoSuchQuotaConfiguration-214] + _ = x[ErrHealNotImplemented-215] + _ = x[ErrHealNoSuchProcess-216] + _ = x[ErrHealInvalidClientToken-217] + _ = x[ErrHealMissingBucket-218] + _ = x[ErrHealAlreadyRunning-219] + _ = x[ErrHealOverlappingPaths-220] + _ = x[ErrIncorrectContinuationToken-221] + _ = x[ErrEmptyRequestBody-222] + _ = x[ErrUnsupportedFunction-223] + _ = x[ErrInvalidExpressionType-224] + _ = x[ErrBusy-225] + _ = x[ErrUnauthorizedAccess-226] + _ = x[ErrExpressionTooLong-227] + _ = x[ErrIllegalSQLFunctionArgument-228] + _ = x[ErrInvalidKeyPath-229] + _ = x[ErrInvalidCompressionFormat-230] + _ = x[ErrInvalidFileHeaderInfo-231] + _ = x[ErrInvalidJSONType-232] + _ = x[ErrInvalidQuoteFields-233] + _ = x[ErrInvalidRequestParameter-234] + _ = x[ErrInvalidDataType-235] + _ = x[ErrInvalidTextEncoding-236] + _ = x[ErrInvalidDataSource-237] + _ = x[ErrInvalidTableAlias-238] + _ = x[ErrMissingRequiredParameter-239] + _ = x[ErrObjectSerializationConflict-240] + _ = x[ErrUnsupportedSQLOperation-241] + _ = x[ErrUnsupportedSQLStructure-242] + _ = x[ErrUnsupportedSyntax-243] + _ = x[ErrUnsupportedRangeHeader-244] + _ = x[ErrLexerInvalidChar-245] + _ = x[ErrLexerInvalidOperator-246] + _ = x[ErrLexerInvalidLiteral-247] + _ = x[ErrLexerInvalidIONLiteral-248] + _ = x[ErrParseExpectedDatePart-249] + _ = x[ErrParseExpectedKeyword-250] + _ = x[ErrParseExpectedTokenType-251] + _ = x[ErrParseExpected2TokenTypes-252] + _ = x[ErrParseExpectedNumber-253] + _ = x[ErrParseExpectedRightParenBuiltinFunctionCall-254] + _ = x[ErrParseExpectedTypeName-255] + _ = x[ErrParseExpectedWhenClause-256] + _ = x[ErrParseUnsupportedToken-257] + _ = x[ErrParseUnsupportedLiteralsGroupBy-258] + _ = x[ErrParseExpectedMember-259] + _ = x[ErrParseUnsupportedSelect-260] + _ = x[ErrParseUnsupportedCase-261] + _ = x[ErrParseUnsupportedCaseClause-262] + _ = x[ErrParseUnsupportedAlias-263] + _ = x[ErrParseUnsupportedSyntax-264] + _ = x[ErrParseUnknownOperator-265] + _ = x[ErrParseMissingIdentAfterAt-266] + _ = x[ErrParseUnexpectedOperator-267] + _ = x[ErrParseUnexpectedTerm-268] + _ = x[ErrParseUnexpectedToken-269] + _ = x[ErrParseUnexpectedKeyword-270] + _ = x[ErrParseExpectedExpression-271] + _ = x[ErrParseExpectedLeftParenAfterCast-272] + _ = x[ErrParseExpectedLeftParenValueConstructor-273] + _ = x[ErrParseExpectedLeftParenBuiltinFunctionCall-274] + _ = x[ErrParseExpectedArgumentDelimiter-275] + _ = x[ErrParseCastArity-276] + _ = x[ErrParseInvalidTypeParam-277] + _ = x[ErrParseEmptySelect-278] + _ = x[ErrParseSelectMissingFrom-279] + _ = x[ErrParseExpectedIdentForGroupName-280] + _ = x[ErrParseExpectedIdentForAlias-281] + _ = x[ErrParseUnsupportedCallWithStar-282] + _ = x[ErrParseNonUnaryAgregateFunctionCall-283] + _ = x[ErrParseMalformedJoin-284] + _ = x[ErrParseExpectedIdentForAt-285] + _ = x[ErrParseAsteriskIsNotAloneInSelectList-286] + _ = x[ErrParseCannotMixSqbAndWildcardInSelectList-287] + _ = x[ErrParseInvalidContextForWildcardInSelectList-288] + _ = x[ErrIncorrectSQLFunctionArgumentType-289] + _ = x[ErrValueParseFailure-290] + _ = x[ErrEvaluatorInvalidArguments-291] + _ = x[ErrIntegerOverflow-292] + _ = x[ErrLikeInvalidInputs-293] + _ = x[ErrCastFailed-294] + _ = x[ErrInvalidCast-295] + _ = x[ErrEvaluatorInvalidTimestampFormatPattern-296] + _ = x[ErrEvaluatorInvalidTimestampFormatPatternSymbolForParsing-297] + _ = x[ErrEvaluatorTimestampFormatPatternDuplicateFields-298] + _ = x[ErrEvaluatorTimestampFormatPatternHourClockAmPmMismatch-299] + _ = x[ErrEvaluatorUnterminatedTimestampFormatPatternToken-300] + _ = x[ErrEvaluatorInvalidTimestampFormatPatternToken-301] + _ = x[ErrEvaluatorInvalidTimestampFormatPatternSymbol-302] + _ = x[ErrEvaluatorBindingDoesNotExist-303] + _ = x[ErrMissingHeaders-304] + _ = x[ErrInvalidColumnIndex-305] + _ = x[ErrAdminConfigNotificationTargetsFailed-306] + _ = x[ErrAdminProfilerNotEnabled-307] + _ = x[ErrInvalidDecompressedSize-308] + _ = x[ErrAddUserInvalidArgument-309] + _ = x[ErrAdminResourceInvalidArgument-310] + _ = x[ErrAdminAccountNotEligible-311] + _ = x[ErrAccountNotEligible-312] + _ = x[ErrAdminServiceAccountNotFound-313] + _ = x[ErrPostPolicyConditionInvalidFormat-314] + _ = x[ErrInvalidChecksum-315] + _ = x[ErrLambdaARNInvalid-316] + _ = x[ErrLambdaARNNotFound-317] + _ = x[ErrInvalidAttributeName-318] + _ = x[apiErrCodeEnd-319] } -const _APIErrorCode_name = "NoneAccessDeniedBadDigestEntityTooSmallEntityTooLargePolicyTooLargeIncompleteBodyInternalErrorInvalidAccessKeyIDAccessKeyDisabledInvalidArgumentInvalidBucketNameInvalidDigestInvalidRangeInvalidRangePartNumberInvalidCopyPartRangeInvalidCopyPartRangeSourceInvalidMaxKeysInvalidEncodingMethodInvalidMaxUploadsInvalidMaxPartsInvalidPartNumberMarkerInvalidPartNumberInvalidRequestBodyInvalidCopySourceInvalidMetadataDirectiveInvalidCopyDestInvalidPolicyDocumentInvalidObjectStateMalformedXMLMissingContentLengthMissingContentMD5MissingRequestBodyErrorMissingSecurityHeaderNoSuchBucketNoSuchBucketPolicyNoSuchBucketLifecycleNoSuchLifecycleConfigurationInvalidLifecycleWithObjectLockNoSuchBucketSSEConfigNoSuchCORSConfigurationNoSuchWebsiteConfigurationReplicationConfigurationNotFoundErrorRemoteDestinationNotFoundErrorReplicationDestinationMissingLockRemoteTargetNotFoundErrorReplicationRemoteConnectionErrorReplicationBandwidthLimitErrorBucketRemoteIdenticalToSourceBucketRemoteAlreadyExistsBucketRemoteLabelInUseBucketRemoteArnTypeInvalidBucketRemoteArnInvalidBucketRemoteRemoveDisallowedRemoteTargetNotVersionedErrorReplicationSourceNotVersionedErrorReplicationNeedsVersioningErrorReplicationBucketNeedsVersioningErrorReplicationDenyEditErrorRemoteTargetDenyAddErrorReplicationNoExistingObjectsReplicationValidationErrorReplicationPermissionCheckErrorObjectRestoreAlreadyInProgressNoSuchKeyNoSuchUploadInvalidVersionIDNoSuchVersionNotImplementedPreconditionFailedRequestTimeTooSkewedSignatureDoesNotMatchMethodNotAllowedInvalidPartInvalidPartOrderMissingPartAuthorizationHeaderMalformedMalformedPOSTRequestPOSTFileRequiredSignatureVersionNotSupportedBucketNotEmptyAllAccessDisabledPolicyInvalidVersionMissingFieldsMissingCredTagCredMalformedInvalidRegionInvalidServiceS3InvalidServiceSTSInvalidRequestVersionMissingSignTagMissingSignHeadersTagMalformedDateMalformedPresignedDateMalformedCredentialDateMalformedExpiresNegativeExpiresAuthHeaderEmptyExpiredPresignRequestRequestNotReadyYetUnsignedHeadersMissingDateHeaderInvalidQuerySignatureAlgoInvalidQueryParamsBucketAlreadyOwnedByYouInvalidDurationBucketAlreadyExistsMetadataTooLargeUnsupportedMetadataUnsupportedHostHeaderMaximumExpiresSlowDownReadSlowDownWriteMaxVersionsExceededInvalidPrefixMarkerBadRequestKeyTooLongErrorInvalidBucketObjectLockConfigurationObjectLockConfigurationNotFoundObjectLockConfigurationNotAllowedNoSuchObjectLockConfigurationObjectLockedInvalidRetentionDatePastObjectLockRetainDateUnknownWORMModeDirectiveBucketTaggingNotFoundObjectLockInvalidHeadersInvalidTagDirectivePolicyAlreadyAttachedPolicyNotAttachedExcessDataInvalidEncryptionMethodInvalidEncryptionKeyIDInsecureSSECustomerRequestSSEMultipartEncryptedSSEEncryptedObjectInvalidEncryptionParametersInvalidEncryptionParametersSSECInvalidSSECustomerAlgorithmInvalidSSECustomerKeyMissingSSECustomerKeyMissingSSECustomerKeyMD5SSECustomerKeyMD5MismatchInvalidSSECustomerParametersIncompatibleEncryptionMethodKMSNotConfiguredKMSKeyNotFoundExceptionKMSDefaultKeyAlreadyConfiguredNoAccessKeyInvalidTokenEventNotificationARNNotificationRegionNotificationOverlappingFilterNotificationFilterNameInvalidFilterNamePrefixFilterNameSuffixFilterValueInvalidOverlappingConfigsUnsupportedNotificationContentSHA256MismatchContentChecksumMismatchStorageFullRequestBodyParseObjectExistsAsDirectoryInvalidObjectNameInvalidObjectNamePrefixSlashInvalidResourceNameInvalidLifecycleQueryParameterServerNotInitializedRequestTimedoutClientDisconnectedTooManyRequestsInvalidRequestTransitionStorageClassNotFoundErrorInvalidStorageClassBackendDownMalformedJSONAdminNoSuchUserAdminNoSuchUserLDAPWarnAdminNoSuchGroupAdminGroupNotEmptyAdminGroupDisabledAdminNoSuchJobAdminNoSuchPolicyAdminPolicyChangeAlreadyAppliedAdminInvalidArgumentAdminInvalidAccessKeyAdminInvalidSecretKeyAdminConfigNoQuorumAdminConfigTooLargeAdminConfigBadJSONAdminNoSuchConfigTargetAdminConfigEnvOverriddenAdminConfigDuplicateKeysAdminConfigInvalidIDPTypeAdminConfigLDAPNonDefaultConfigNameAdminConfigLDAPValidationAdminConfigIDPCfgNameAlreadyExistsAdminConfigIDPCfgNameDoesNotExistAdminCredentialsMismatchInsecureClientRequestObjectTamperedSiteReplicationInvalidRequestSiteReplicationPeerRespSiteReplicationBackendIssueSiteReplicationServiceAccountErrorSiteReplicationBucketConfigErrorSiteReplicationBucketMetaErrorSiteReplicationIAMErrorSiteReplicationConfigMissingSiteReplicationIAMConfigMismatchAdminRebalanceAlreadyStartedAdminRebalanceNotStartedAdminBucketQuotaExceededAdminNoSuchQuotaConfigurationHealNotImplementedHealNoSuchProcessHealInvalidClientTokenHealMissingBucketHealAlreadyRunningHealOverlappingPathsIncorrectContinuationTokenEmptyRequestBodyUnsupportedFunctionInvalidExpressionTypeBusyUnauthorizedAccessExpressionTooLongIllegalSQLFunctionArgumentInvalidKeyPathInvalidCompressionFormatInvalidFileHeaderInfoInvalidJSONTypeInvalidQuoteFieldsInvalidRequestParameterInvalidDataTypeInvalidTextEncodingInvalidDataSourceInvalidTableAliasMissingRequiredParameterObjectSerializationConflictUnsupportedSQLOperationUnsupportedSQLStructureUnsupportedSyntaxUnsupportedRangeHeaderLexerInvalidCharLexerInvalidOperatorLexerInvalidLiteralLexerInvalidIONLiteralParseExpectedDatePartParseExpectedKeywordParseExpectedTokenTypeParseExpected2TokenTypesParseExpectedNumberParseExpectedRightParenBuiltinFunctionCallParseExpectedTypeNameParseExpectedWhenClauseParseUnsupportedTokenParseUnsupportedLiteralsGroupByParseExpectedMemberParseUnsupportedSelectParseUnsupportedCaseParseUnsupportedCaseClauseParseUnsupportedAliasParseUnsupportedSyntaxParseUnknownOperatorParseMissingIdentAfterAtParseUnexpectedOperatorParseUnexpectedTermParseUnexpectedTokenParseUnexpectedKeywordParseExpectedExpressionParseExpectedLeftParenAfterCastParseExpectedLeftParenValueConstructorParseExpectedLeftParenBuiltinFunctionCallParseExpectedArgumentDelimiterParseCastArityParseInvalidTypeParamParseEmptySelectParseSelectMissingFromParseExpectedIdentForGroupNameParseExpectedIdentForAliasParseUnsupportedCallWithStarParseNonUnaryAgregateFunctionCallParseMalformedJoinParseExpectedIdentForAtParseAsteriskIsNotAloneInSelectListParseCannotMixSqbAndWildcardInSelectListParseInvalidContextForWildcardInSelectListIncorrectSQLFunctionArgumentTypeValueParseFailureEvaluatorInvalidArgumentsIntegerOverflowLikeInvalidInputsCastFailedInvalidCastEvaluatorInvalidTimestampFormatPatternEvaluatorInvalidTimestampFormatPatternSymbolForParsingEvaluatorTimestampFormatPatternDuplicateFieldsEvaluatorTimestampFormatPatternHourClockAmPmMismatchEvaluatorUnterminatedTimestampFormatPatternTokenEvaluatorInvalidTimestampFormatPatternTokenEvaluatorInvalidTimestampFormatPatternSymbolEvaluatorBindingDoesNotExistMissingHeadersInvalidColumnIndexAdminConfigNotificationTargetsFailedAdminProfilerNotEnabledInvalidDecompressedSizeAddUserInvalidArgumentAdminResourceInvalidArgumentAdminAccountNotEligibleAccountNotEligibleAdminServiceAccountNotFoundPostPolicyConditionInvalidFormatInvalidChecksumLambdaARNInvalidLambdaARNNotFoundInvalidAttributeNameapiErrCodeEnd" +const _APIErrorCode_name = "NoneAccessDeniedBadDigestEntityTooSmallEntityTooLargePolicyTooLargeIncompleteBodyInternalErrorInvalidAccessKeyIDAccessKeyDisabledInvalidArgumentInvalidBucketNameInvalidDigestInvalidRangeInvalidRangePartNumberInvalidCopyPartRangeInvalidCopyPartRangeSourceInvalidMaxKeysInvalidEncodingMethodInvalidMaxUploadsInvalidMaxPartsInvalidPartNumberMarkerInvalidPartNumberInvalidRequestBodyInvalidCopySourceInvalidMetadataDirectiveInvalidCopyDestInvalidPolicyDocumentInvalidObjectStateMalformedXMLMissingContentLengthMissingContentMD5MissingRequestBodyErrorMissingSecurityHeaderNoSuchBucketNoSuchBucketPolicyNoSuchBucketLifecycleNoSuchLifecycleConfigurationInvalidLifecycleWithObjectLockNoSuchBucketSSEConfigNoSuchCORSConfigurationNoSuchWebsiteConfigurationReplicationConfigurationNotFoundErrorRemoteDestinationNotFoundErrorReplicationDestinationMissingLockRemoteTargetNotFoundErrorReplicationRemoteConnectionErrorReplicationBandwidthLimitErrorBucketRemoteIdenticalToSourceBucketRemoteAlreadyExistsBucketRemoteLabelInUseBucketRemoteArnTypeInvalidBucketRemoteArnInvalidBucketRemoteRemoveDisallowedRemoteTargetNotVersionedErrorReplicationSourceNotVersionedErrorReplicationNeedsVersioningErrorReplicationBucketNeedsVersioningErrorReplicationDenyEditErrorRemoteTargetDenyAddErrorReplicationNoExistingObjectsReplicationValidationErrorReplicationPermissionCheckErrorObjectRestoreAlreadyInProgressNoSuchKeyNoSuchUploadInvalidVersionIDNoSuchVersionNotImplementedPreconditionFailedRequestTimeTooSkewedSignatureDoesNotMatchMethodNotAllowedInvalidPartInvalidPartOrderMissingPartAuthorizationHeaderMalformedMalformedPOSTRequestPOSTFileRequiredSignatureVersionNotSupportedBucketNotEmptyAllAccessDisabledPolicyInvalidVersionMissingFieldsMissingCredTagCredMalformedInvalidRegionInvalidServiceS3InvalidServiceSTSInvalidRequestVersionMissingSignTagMissingSignHeadersTagMalformedDateMalformedPresignedDateMalformedCredentialDateMalformedExpiresNegativeExpiresAuthHeaderEmptyExpiredPresignRequestRequestNotReadyYetUnsignedHeadersMissingDateHeaderInvalidQuerySignatureAlgoInvalidQueryParamsBucketAlreadyOwnedByYouInvalidDurationBucketAlreadyExistsMetadataTooLargeUnsupportedMetadataUnsupportedHostHeaderMaximumExpiresSlowDownReadSlowDownWriteMaxVersionsExceededInvalidPrefixMarkerBadRequestKeyTooLongErrorInvalidBucketObjectLockConfigurationObjectLockConfigurationNotFoundObjectLockConfigurationNotAllowedNoSuchObjectLockConfigurationObjectLockedInvalidRetentionDatePastObjectLockRetainDateUnknownWORMModeDirectiveBucketTaggingNotFoundObjectLockInvalidHeadersInvalidTagDirectivePolicyAlreadyAttachedPolicyNotAttachedExcessDataInvalidEncryptionMethodInvalidEncryptionKeyIDInsecureSSECustomerRequestSSEMultipartEncryptedSSEEncryptedObjectInvalidEncryptionParametersInvalidEncryptionParametersSSECInvalidSSECustomerAlgorithmInvalidSSECustomerKeyMissingSSECustomerKeyMissingSSECustomerKeyMD5SSECustomerKeyMD5MismatchInvalidSSECustomerParametersIncompatibleEncryptionMethodKMSNotConfiguredKMSKeyNotFoundExceptionKMSDefaultKeyAlreadyConfiguredNoAccessKeyInvalidTokenEventNotificationARNNotificationRegionNotificationOverlappingFilterNotificationFilterNameInvalidFilterNamePrefixFilterNameSuffixFilterValueInvalidOverlappingConfigsUnsupportedNotificationContentSHA256MismatchContentChecksumMismatchStorageFullRequestBodyParseObjectExistsAsDirectoryInvalidObjectNameInvalidObjectNamePrefixSlashInvalidResourceNameInvalidLifecycleQueryParameterServerNotInitializedRequestTimedoutClientDisconnectedTooManyRequestsInvalidRequestTransitionStorageClassNotFoundErrorInvalidStorageClassBackendDownMalformedJSONAdminNoSuchUserAdminNoSuchUserLDAPWarnAdminNoSuchGroupAdminGroupNotEmptyAdminGroupDisabledAdminNoSuchJobAdminNoSuchPolicyAdminPolicyChangeAlreadyAppliedAdminInvalidArgumentAdminInvalidAccessKeyAdminInvalidSecretKeyAdminConfigNoQuorumAdminConfigTooLargeAdminConfigBadJSONAdminNoSuchConfigTargetAdminConfigEnvOverriddenAdminConfigDuplicateKeysAdminConfigInvalidIDPTypeAdminConfigLDAPNonDefaultConfigNameAdminConfigLDAPValidationAdminConfigIDPCfgNameAlreadyExistsAdminConfigIDPCfgNameDoesNotExistInsecureClientRequestObjectTamperedSiteReplicationInvalidRequestSiteReplicationPeerRespSiteReplicationBackendIssueSiteReplicationServiceAccountErrorSiteReplicationBucketConfigErrorSiteReplicationBucketMetaErrorSiteReplicationIAMErrorSiteReplicationConfigMissingSiteReplicationIAMConfigMismatchAdminRebalanceAlreadyStartedAdminRebalanceNotStartedAdminBucketQuotaExceededAdminNoSuchQuotaConfigurationHealNotImplementedHealNoSuchProcessHealInvalidClientTokenHealMissingBucketHealAlreadyRunningHealOverlappingPathsIncorrectContinuationTokenEmptyRequestBodyUnsupportedFunctionInvalidExpressionTypeBusyUnauthorizedAccessExpressionTooLongIllegalSQLFunctionArgumentInvalidKeyPathInvalidCompressionFormatInvalidFileHeaderInfoInvalidJSONTypeInvalidQuoteFieldsInvalidRequestParameterInvalidDataTypeInvalidTextEncodingInvalidDataSourceInvalidTableAliasMissingRequiredParameterObjectSerializationConflictUnsupportedSQLOperationUnsupportedSQLStructureUnsupportedSyntaxUnsupportedRangeHeaderLexerInvalidCharLexerInvalidOperatorLexerInvalidLiteralLexerInvalidIONLiteralParseExpectedDatePartParseExpectedKeywordParseExpectedTokenTypeParseExpected2TokenTypesParseExpectedNumberParseExpectedRightParenBuiltinFunctionCallParseExpectedTypeNameParseExpectedWhenClauseParseUnsupportedTokenParseUnsupportedLiteralsGroupByParseExpectedMemberParseUnsupportedSelectParseUnsupportedCaseParseUnsupportedCaseClauseParseUnsupportedAliasParseUnsupportedSyntaxParseUnknownOperatorParseMissingIdentAfterAtParseUnexpectedOperatorParseUnexpectedTermParseUnexpectedTokenParseUnexpectedKeywordParseExpectedExpressionParseExpectedLeftParenAfterCastParseExpectedLeftParenValueConstructorParseExpectedLeftParenBuiltinFunctionCallParseExpectedArgumentDelimiterParseCastArityParseInvalidTypeParamParseEmptySelectParseSelectMissingFromParseExpectedIdentForGroupNameParseExpectedIdentForAliasParseUnsupportedCallWithStarParseNonUnaryAgregateFunctionCallParseMalformedJoinParseExpectedIdentForAtParseAsteriskIsNotAloneInSelectListParseCannotMixSqbAndWildcardInSelectListParseInvalidContextForWildcardInSelectListIncorrectSQLFunctionArgumentTypeValueParseFailureEvaluatorInvalidArgumentsIntegerOverflowLikeInvalidInputsCastFailedInvalidCastEvaluatorInvalidTimestampFormatPatternEvaluatorInvalidTimestampFormatPatternSymbolForParsingEvaluatorTimestampFormatPatternDuplicateFieldsEvaluatorTimestampFormatPatternHourClockAmPmMismatchEvaluatorUnterminatedTimestampFormatPatternTokenEvaluatorInvalidTimestampFormatPatternTokenEvaluatorInvalidTimestampFormatPatternSymbolEvaluatorBindingDoesNotExistMissingHeadersInvalidColumnIndexAdminConfigNotificationTargetsFailedAdminProfilerNotEnabledInvalidDecompressedSizeAddUserInvalidArgumentAdminResourceInvalidArgumentAdminAccountNotEligibleAccountNotEligibleAdminServiceAccountNotFoundPostPolicyConditionInvalidFormatInvalidChecksumLambdaARNInvalidLambdaARNNotFoundInvalidAttributeNameapiErrCodeEnd" -var _APIErrorCode_index = [...]uint16{0, 4, 16, 25, 39, 53, 67, 81, 94, 112, 129, 144, 161, 174, 186, 208, 228, 254, 268, 289, 306, 321, 344, 361, 379, 396, 420, 435, 456, 474, 486, 506, 523, 546, 567, 579, 597, 618, 646, 676, 697, 720, 746, 783, 813, 846, 871, 903, 933, 962, 987, 1009, 1035, 1057, 1085, 1114, 1148, 1179, 1216, 1240, 1264, 1292, 1318, 1349, 1379, 1388, 1400, 1416, 1429, 1443, 1461, 1481, 1502, 1518, 1529, 1545, 1556, 1584, 1604, 1620, 1648, 1662, 1679, 1699, 1712, 1726, 1739, 1752, 1768, 1785, 1806, 1820, 1841, 1854, 1876, 1899, 1915, 1930, 1945, 1966, 1984, 1999, 2016, 2041, 2059, 2082, 2097, 2116, 2132, 2151, 2172, 2186, 2198, 2211, 2230, 2249, 2259, 2274, 2310, 2341, 2374, 2403, 2415, 2435, 2459, 2483, 2504, 2528, 2547, 2568, 2585, 2595, 2618, 2640, 2666, 2687, 2705, 2732, 2763, 2790, 2811, 2832, 2856, 2881, 2909, 2937, 2953, 2976, 3006, 3017, 3029, 3046, 3061, 3079, 3108, 3125, 3141, 3157, 3175, 3193, 3216, 3237, 3260, 3271, 3287, 3310, 3327, 3355, 3374, 3404, 3424, 3439, 3457, 3472, 3486, 3521, 3540, 3551, 3564, 3579, 3602, 3618, 3636, 3654, 3668, 3685, 3716, 3736, 3757, 3778, 3797, 3816, 3834, 3857, 3881, 3905, 3930, 3965, 3990, 4024, 4057, 4081, 4102, 4116, 4145, 4168, 4195, 4229, 4261, 4291, 4314, 4342, 4374, 4402, 4426, 4450, 4479, 4497, 4514, 4536, 4553, 4571, 4591, 4617, 4633, 4652, 4673, 4677, 4695, 4712, 4738, 4752, 4776, 4797, 4812, 4830, 4853, 4868, 4887, 4904, 4921, 4945, 4972, 4995, 5018, 5035, 5057, 5073, 5093, 5112, 5134, 5155, 5175, 5197, 5221, 5240, 5282, 5303, 5326, 5347, 5378, 5397, 5419, 5439, 5465, 5486, 5508, 5528, 5552, 5575, 5594, 5614, 5636, 5659, 5690, 5728, 5769, 5799, 5813, 5834, 5850, 5872, 5902, 5928, 5956, 5989, 6007, 6030, 6065, 6105, 6147, 6179, 6196, 6221, 6236, 6253, 6263, 6274, 6312, 6366, 6412, 6464, 6512, 6555, 6599, 6627, 6641, 6659, 6695, 6718, 6741, 6763, 6791, 6814, 6832, 6859, 6891, 6906, 6922, 6939, 6959, 6972} +var _APIErrorCode_index = [...]uint16{0, 4, 16, 25, 39, 53, 67, 81, 94, 112, 129, 144, 161, 174, 186, 208, 228, 254, 268, 289, 306, 321, 344, 361, 379, 396, 420, 435, 456, 474, 486, 506, 523, 546, 567, 579, 597, 618, 646, 676, 697, 720, 746, 783, 813, 846, 871, 903, 933, 962, 987, 1009, 1035, 1057, 1085, 1114, 1148, 1179, 1216, 1240, 1264, 1292, 1318, 1349, 1379, 1388, 1400, 1416, 1429, 1443, 1461, 1481, 1502, 1518, 1529, 1545, 1556, 1584, 1604, 1620, 1648, 1662, 1679, 1699, 1712, 1726, 1739, 1752, 1768, 1785, 1806, 1820, 1841, 1854, 1876, 1899, 1915, 1930, 1945, 1966, 1984, 1999, 2016, 2041, 2059, 2082, 2097, 2116, 2132, 2151, 2172, 2186, 2198, 2211, 2230, 2249, 2259, 2274, 2310, 2341, 2374, 2403, 2415, 2435, 2459, 2483, 2504, 2528, 2547, 2568, 2585, 2595, 2618, 2640, 2666, 2687, 2705, 2732, 2763, 2790, 2811, 2832, 2856, 2881, 2909, 2937, 2953, 2976, 3006, 3017, 3029, 3046, 3061, 3079, 3108, 3125, 3141, 3157, 3175, 3193, 3216, 3237, 3260, 3271, 3287, 3310, 3327, 3355, 3374, 3404, 3424, 3439, 3457, 3472, 3486, 3521, 3540, 3551, 3564, 3579, 3602, 3618, 3636, 3654, 3668, 3685, 3716, 3736, 3757, 3778, 3797, 3816, 3834, 3857, 3881, 3905, 3930, 3965, 3990, 4024, 4057, 4078, 4092, 4121, 4144, 4171, 4205, 4237, 4267, 4290, 4318, 4350, 4378, 4402, 4426, 4455, 4473, 4490, 4512, 4529, 4547, 4567, 4593, 4609, 4628, 4649, 4653, 4671, 4688, 4714, 4728, 4752, 4773, 4788, 4806, 4829, 4844, 4863, 4880, 4897, 4921, 4948, 4971, 4994, 5011, 5033, 5049, 5069, 5088, 5110, 5131, 5151, 5173, 5197, 5216, 5258, 5279, 5302, 5323, 5354, 5373, 5395, 5415, 5441, 5462, 5484, 5504, 5528, 5551, 5570, 5590, 5612, 5635, 5666, 5704, 5745, 5775, 5789, 5810, 5826, 5848, 5878, 5904, 5932, 5965, 5983, 6006, 6041, 6081, 6123, 6155, 6172, 6197, 6212, 6229, 6239, 6250, 6288, 6342, 6388, 6440, 6488, 6531, 6575, 6603, 6617, 6635, 6671, 6694, 6717, 6739, 6767, 6790, 6808, 6835, 6867, 6882, 6898, 6915, 6935, 6948} func (i APIErrorCode) String() string { if i < 0 || i >= APIErrorCode(len(_APIErrorCode_index)-1) { diff --git a/cmd/common-main.go b/cmd/common-main.go index 66cb10efc..32abee71b 100644 --- a/cmd/common-main.go +++ b/cmd/common-main.go @@ -394,6 +394,7 @@ func buildServerCtxt(ctx *cli.Context, ctxt *serverCtxt) (err error) { ctxt.UserTimeout = ctx.Duration("conn-user-timeout") ctxt.ConnReadDeadline = ctx.Duration("conn-read-deadline") ctxt.ConnWriteDeadline = ctx.Duration("conn-write-deadline") + ctxt.ConnClientReadDeadline = ctx.Duration("conn-client-read-deadline") ctxt.ShutdownTimeout = ctx.Duration("shutdown-timeout") ctxt.IdleTimeout = ctx.Duration("idle-timeout") diff --git a/cmd/globals.go b/cmd/globals.go index ce78c17d0..659f37e4e 100644 --- a/cmd/globals.go +++ b/cmd/globals.go @@ -160,9 +160,10 @@ type serverCtxt struct { FTP []string SFTP []string - UserTimeout time.Duration - ConnReadDeadline time.Duration - ConnWriteDeadline time.Duration + UserTimeout time.Duration + ConnReadDeadline time.Duration + ConnWriteDeadline time.Duration + ConnClientReadDeadline time.Duration ShutdownTimeout time.Duration IdleTimeout time.Duration diff --git a/cmd/server-main.go b/cmd/server-main.go index 97bdf1981..cd3e69fdb 100644 --- a/cmd/server-main.go +++ b/cmd/server-main.go @@ -101,6 +101,12 @@ var ServerFlags = []cli.Flag{ EnvVar: "MINIO_READ_HEADER_TIMEOUT", Hidden: true, }, + cli.DurationFlag{ + Name: "conn-client-read-deadline", + Usage: "custom connection READ deadline for incoming requests", + Hidden: true, + EnvVar: "MINIO_CONN_CLIENT_READ_DEADLINE", + }, cli.DurationFlag{ Name: "conn-read-deadline", Usage: "custom connection READ deadline", @@ -351,8 +357,9 @@ func serverHandleCmdArgs(ctxt serverCtxt) { }) globalTCPOptions = xhttp.TCPOptions{ - UserTimeout: int(ctxt.UserTimeout.Milliseconds()), - Interface: ctxt.Interface, + UserTimeout: int(ctxt.UserTimeout.Milliseconds()), + ClientReadTimeout: ctxt.ConnClientReadDeadline, + Interface: ctxt.Interface, } // On macOS, if a process already listens on LOCALIPADDR:PORT, net.Listen() falls back diff --git a/docs/distributed/decom-compressed-sse-s3.sh b/docs/distributed/decom-compressed-sse-s3.sh index d7d2f10f0..8f1e4f109 100755 --- a/docs/distributed/decom-compressed-sse-s3.sh +++ b/docs/distributed/decom-compressed-sse-s3.sh @@ -147,4 +147,9 @@ if [ $ret -ne 0 ]; then exit 1 fi -# kill $pid +go install github.com/minio/minio/docs/debugging/s3-check-md5@latest + +s3-check-md5 -versions -access-key minioadmin -secret-key minioadmin -endpoint http://127.0.0.1:9001/ -bucket bucket2 +s3-check-md5 -versions -access-key minioadmin -secret-key minioadmin -endpoint http://127.0.0.1:9001/ -bucket versioned + +kill $pid diff --git a/docs/distributed/decom-encrypted-sse-s3.sh b/docs/distributed/decom-encrypted-sse-s3.sh index 58a10f855..3ab966910 100755 --- a/docs/distributed/decom-encrypted-sse-s3.sh +++ b/docs/distributed/decom-encrypted-sse-s3.sh @@ -158,4 +158,9 @@ if [ $ret -ne 0 ]; then exit 1 fi +go install github.com/minio/minio/docs/debugging/s3-check-md5@latest + +s3-check-md5 -versions -access-key minioadmin -secret-key minioadmin -endpoint http://127.0.0.1:9001/ -bucket bucket2 +s3-check-md5 -versions -access-key minioadmin -secret-key minioadmin -endpoint http://127.0.0.1:9001/ -bucket versioned + kill $pid diff --git a/docs/distributed/decom-encrypted.sh b/docs/distributed/decom-encrypted.sh index ea95c415b..1cc0008a7 100755 --- a/docs/distributed/decom-encrypted.sh +++ b/docs/distributed/decom-encrypted.sh @@ -144,4 +144,9 @@ if [ "${expected_checksum}" != "${got_checksum}" ]; then exit 1 fi +go install github.com/minio/minio/docs/debugging/s3-check-md5@latest + +s3-check-md5 -versions -access-key minioadmin -secret-key minioadmin -endpoint http://127.0.0.1:9001/ -bucket bucket2 +s3-check-md5 -versions -access-key minioadmin -secret-key minioadmin -endpoint http://127.0.0.1:9001/ -bucket versioned + kill $pid diff --git a/docs/distributed/decom.sh b/docs/distributed/decom.sh index 39107f606..37ec00653 100755 --- a/docs/distributed/decom.sh +++ b/docs/distributed/decom.sh @@ -210,4 +210,9 @@ if [ "${expected_checksum}" != "${got_checksum}" ]; then exit 1 fi +go install github.com/minio/minio/docs/debugging/s3-check-md5@latest + +s3-check-md5 -versions -access-key minioadmin -secret-key minioadmin -endpoint http://127.0.0.1:9001/ -bucket bucket2 +s3-check-md5 -versions -access-key minioadmin -secret-key minioadmin -endpoint http://127.0.0.1:9001/ -bucket versioned + kill $pid diff --git a/internal/http/listener.go b/internal/http/listener.go index baae25775..bda86485d 100644 --- a/internal/http/listener.go +++ b/internal/http/listener.go @@ -22,6 +22,9 @@ import ( "fmt" "net" "syscall" + "time" + + "github.com/minio/minio/internal/deadlineconn" ) type acceptResult struct { @@ -32,6 +35,7 @@ type acceptResult struct { // httpListener - HTTP listener capable of handling multiple server addresses. type httpListener struct { + opts TCPOptions tcpListeners []*net.TCPListener // underlying TCP listeners. acceptCh chan acceptResult // channel where all TCP listeners write accepted connection. ctx context.Context @@ -74,7 +78,8 @@ func (listener *httpListener) Accept() (conn net.Conn, err error) { select { case result, ok := <-listener.acceptCh: if ok { - return result.conn, result.err + return deadlineconn.New(result.conn). + WithReadDeadline(listener.opts.ClientReadTimeout), result.err } case <-listener.ctx.Done(): } @@ -119,9 +124,10 @@ func (listener *httpListener) Addrs() (addrs []net.Addr) { // TCPOptions specify customizable TCP optimizations on raw socket type TCPOptions struct { - UserTimeout int // this value is expected to be in milliseconds - Interface string // this is a VRF device passed via `--interface` flag - Trace func(msg string) // Trace when starting. + UserTimeout int // this value is expected to be in milliseconds + ClientReadTimeout time.Duration // When the net.Conn is idle for more than ReadTimeout duration, we close the connection on the client proactively. + Interface string // this is a VRF device passed via `--interface` flag + Trace func(msg string) // Trace when starting. } // newHTTPListener - creates new httpListener object which is interface compatible to net.Listener. @@ -173,6 +179,7 @@ func newHTTPListener(ctx context.Context, serverAddrs []string, opts TCPOptions) listener = &httpListener{ tcpListeners: tcpListeners, acceptCh: make(chan acceptResult, len(tcpListeners)), + opts: opts, } listener.ctx, listener.ctxCanceler = context.WithCancel(ctx) if opts.Trace != nil { diff --git a/internal/http/server.go b/internal/http/server.go index ec777709d..9839f72b0 100644 --- a/internal/http/server.go +++ b/internal/http/server.go @@ -109,8 +109,12 @@ func (srv *Server) Init(listenCtx context.Context, listenErrCallback func(listen wrappedHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // If server is in shutdown. if atomic.LoadUint32(&srv.inShutdown) != 0 { - // To indicate disable keep-alive + // To indicate disable keep-alive, server is shutting down. w.Header().Set("Connection", "close") + + // Add 1 minute retry header, incase-client wants to honor it + w.Header().Set(RetryAfter, "60") + w.WriteHeader(http.StatusServiceUnavailable) w.Write([]byte(http.ErrServerClosed.Error())) return