Copilot commented on code in PR #13820: URL: https://github.com/apache/trafficserver/pull/13820#discussion_r4248767836
########## tests/gold_tests/query/query-retry.test.py: ########## @@ -0,0 +1,78 @@ +''' +Verify QUERY is not retried once its request, content included, has been sent +to an origin that then closes the connection, whether or not request buffering +is enabled. +''' +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import re +import sys + +from ports import get_port + +Test.Summary = ''' +Verify QUERY is not retried once its request, content included, has been sent +to an origin that then closes the connection, whether or not request buffering +is enabled. +''' + +Test.ContinueOnFail = True + +BODY = 'SELECT * FROM t WHERE a' + + +def add_scenario(name: str, method: str, buffering: bool) -> None: + tr = Test.AddTestRun(f'{method} after the origin closes, request buffering {"enabled" if buffering else "disabled"}') + tr.Setup.Copy('query_retry_origin.py') + + server = Test.Processes.Process(f'origin-{name}') + server_port = get_port(server, 'http_port') + server.Command = f'{sys.executable} {tr.RunDirectory}/query_retry_origin.py {server_port}' + server.Ready = When.PortOpen(server_port) + + ts = Test.MakeATSProcess(f'ts-{name}') + ts.Disk.records_config.update( + { + 'proxy.config.http.request_buffer_enabled': 1 if buffering else 0, + 'proxy.config.http.connect_attempts_max_retries': 3, + 'proxy.config.diags.debug.enabled': 1, + 'proxy.config.diags.debug.tags': 'http_trans', + }) + ts.Disk.remap_config.AddLine(f'map / http://127.0.0.1:{server_port}/') + + content = f"-H 'Content-Type: application/sql' --data-binary '{BODY}' " if method == 'QUERY' else '' + tr.Processes.Default.StartBefore(server) + tr.Processes.Default.StartBefore(ts) + tr.Processes.Default.Command = ( + f"curl -s -o /dev/null -w '%{{http_code}}\\n' -X {method} {content}http://127.0.0.1:{ts.Variables.port}/search") + tr.Processes.Default.ReturnCode = 0 + + if method == 'QUERY': + server.Streams.stdout += Testers.ContainsExpression( + f'request attempt=1 method=QUERY body={re.escape(BODY)}', 'The origin must receive the QUERY and its content.') + server.Streams.stdout += Testers.ExcludesExpression('request attempt=2', 'ATS must not retry a QUERY after sending it.') Review Comment: The exclude pattern `'request attempt=2'` can also match later attempts like `attempt=20` because it is not anchored/bounded. Using a more specific pattern (e.g., anchoring to start-of-line and/or adding a word boundary) would make the assertion more robust and prevent accidental false failures if the test ever evolves to generate higher attempt counts. ########## src/proxy/http/HttpTransact.cc: ########## @@ -5819,9 +5819,9 @@ HttpTransact::check_request_validity(State *s, HTTPHdr *incoming_hdr) return RequestError_t::UNACCEPTABLE_TE_REQUIRED; } - // Require Content-Length/Transfer-Encoding for POST/PUSH/PUT + // Require Content-Length/Transfer-Encoding for POST/PUSH/PUT/QUERY if ((scheme == URL_WKSIDX_HTTP || scheme == URL_WKSIDX_HTTPS) && - (method == HTTP_WKSIDX_POST || method == HTTP_WKSIDX_PUSH || method == HTTP_WKSIDX_PUT) && + (method == HTTP_WKSIDX_POST || method == HTTP_WKSIDX_PUSH || method == HTTP_WKSIDX_PUT || method == HTTP_WKSIDX_QUERY) && s->client_info.transfer_encoding != TransferEncoding_t::CHUNKED) { Review Comment: The current validity check makes `QUERY` require `Content-Length` or chunked framing even when no request body is sent, which leads to `411` for a body-less `QUERY`. The draft’s intent is generally to *allow* a body on a safe method, not necessarily to *require* one; rejecting a payload-free `QUERY` may reduce interoperability with clients that omit `Content-Length: 0`. Consider relaxing this for `QUERY` (treat missing `Content-Length` and non-chunked `Transfer-Encoding` as \"no request body\") while still enforcing proper framing when a body is actually present. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
