From: Jean Baptiste Favre Date: Sat, 21 May 2022 17:28:31 +0000 (+0100) Subject: Improper Input Validation vulnerability in request line parsing X-Git-Tag: archive/raspbian/8.1.1+ds-1.1+rpi1+deb11u1^2~2 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=83d3e94345eb8d019d5fee30e047b356ebc2208a;p=trafficserver.git Improper Input Validation vulnerability in request line parsing Origin: upstream Applied-Upstream: 85c319a7f7c0537bee408ea25df6f1a5ed0a4071, c4e6661a5a205b1f60279f0e66aa496023185967, 8c6f2ed84ba0d8e6255baceb99ee891ebe1ce473 Reviewed-by: Jean Baptiste Favre Last-Update: 2022-05-21 Last-Update: 2022-05-21 Gbp-Pq: Name 0019-CVE_2021_44040.patch --- diff --git a/doc/admin-guide/files/records.config.en.rst b/doc/admin-guide/files/records.config.en.rst index 1f92683b..ba89d10e 100644 --- a/doc/admin-guide/files/records.config.en.rst +++ b/doc/admin-guide/files/records.config.en.rst @@ -1134,10 +1134,12 @@ mptcp An arbitrary string value that, if set, will be used to replace any request ``User-Agent`` header. -.. ts:cv:: CONFIG proxy.config.http.strict_uri_parsing INT 0 +.. ts:cv:: CONFIG proxy.config.http.strict_uri_parsing INT 2 - Enables (``1``) or disables (``0``) Traffic Server to return a 400 Bad Request - if client's request URI includes character which is not RFC 3986 compliant + Takes a value between 0 and 2. ``0`` disables strict_uri_parsing. Any character can appears + in the URI. ``1`` causes |TS| to return 400 Bad Request + if client's request URI includes character which is not RFC 3986 compliant. ``2`` directs |TS| + to reject the clients request if it contains whitespace or non-printable characters. .. ts:cv:: CONFIG proxy.config.http.errors.log_error_pages INT 1 :reloadable: diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index b55cd1bf..5c00cde2 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -354,7 +354,7 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.http.post.check.content_length.enabled", RECD_INT, "1", RECU_DYNAMIC, RR_NULL, RECC_INT, "[0-1]", RECA_NULL} , - {RECT_CONFIG, "proxy.config.http.strict_uri_parsing", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_INT, "[0-1]", RECA_NULL} + {RECT_CONFIG, "proxy.config.http.strict_uri_parsing", RECD_INT, "2", RECU_DYNAMIC, RR_NULL, RECC_INT, "[0-2]", RECA_NULL} , // # Send http11 requests // # diff --git a/proxy/hdrs/HTTP.cc b/proxy/hdrs/HTTP.cc index 48032dd9..d2392644 100644 --- a/proxy/hdrs/HTTP.cc +++ b/proxy/hdrs/HTTP.cc @@ -885,7 +885,7 @@ http_parser_clear(HTTPParser *parser) ParseResult http_parser_parse_req(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const char **start, const char *end, - bool must_copy_strings, bool eof, bool strict_uri_parsing) + bool must_copy_strings, bool eof, int strict_uri_parsing) { if (parser->m_parsing_http) { MIMEScanner *scanner = &parser->m_mime_parser.m_scanner; diff --git a/proxy/hdrs/HTTP.h b/proxy/hdrs/HTTP.h index 6867d371..4ad54950 100644 --- a/proxy/hdrs/HTTP.h +++ b/proxy/hdrs/HTTP.h @@ -445,7 +445,7 @@ const char *http_hdr_reason_lookup(unsigned status); void http_parser_init(HTTPParser *parser); void http_parser_clear(HTTPParser *parser); ParseResult http_parser_parse_req(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const char **start, const char *end, - bool must_copy_strings, bool eof, bool strict_uri_parsing); + bool must_copy_strings, bool eof, int strict_uri_parsing); ParseResult validate_hdr_host(HTTPHdrImpl *hh); ParseResult validate_hdr_content_length(HdrHeap *heap, HTTPHdrImpl *hh); ParseResult http_parser_parse_resp(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const char **start, const char *end, @@ -624,10 +624,10 @@ public: const char *reason_get(int *length); void reason_set(const char *value, int length); - ParseResult parse_req(HTTPParser *parser, const char **start, const char *end, bool eof, bool strict_uri_parsing = false); + ParseResult parse_req(HTTPParser *parser, const char **start, const char *end, bool eof, int strict_uri_parsing = 0); ParseResult parse_resp(HTTPParser *parser, const char **start, const char *end, bool eof); - ParseResult parse_req(HTTPParser *parser, IOBufferReader *r, int *bytes_used, bool eof, bool strict_uri_parsing = false); + ParseResult parse_req(HTTPParser *parser, IOBufferReader *r, int *bytes_used, bool eof, int strict_uri_parsing = 0); ParseResult parse_resp(HTTPParser *parser, IOBufferReader *r, int *bytes_used, bool eof); public: @@ -1225,7 +1225,7 @@ HTTPHdr::reason_set(const char *value, int length) -------------------------------------------------------------------------*/ inline ParseResult -HTTPHdr::parse_req(HTTPParser *parser, const char **start, const char *end, bool eof, bool strict_uri_parsing) +HTTPHdr::parse_req(HTTPParser *parser, const char **start, const char *end, bool eof, int strict_uri_parsing) { ink_assert(valid()); ink_assert(m_http->m_polarity == HTTP_TYPE_REQUEST); diff --git a/proxy/hdrs/HdrTSOnly.cc b/proxy/hdrs/HdrTSOnly.cc index 6841b1e9..6d9d0144 100644 --- a/proxy/hdrs/HdrTSOnly.cc +++ b/proxy/hdrs/HdrTSOnly.cc @@ -45,7 +45,7 @@ -------------------------------------------------------------------------*/ ParseResult -HTTPHdr::parse_req(HTTPParser *parser, IOBufferReader *r, int *bytes_used, bool eof, bool strict_uri_parsing) +HTTPHdr::parse_req(HTTPParser *parser, IOBufferReader *r, int *bytes_used, bool eof, int strict_uri_parsing) { const char *start; const char *tmp; diff --git a/proxy/hdrs/URL.cc b/proxy/hdrs/URL.cc index d38a1f5d..48bac50b 100644 --- a/proxy/hdrs/URL.cc +++ b/proxy/hdrs/URL.cc @@ -1179,10 +1179,34 @@ url_is_strictly_compliant(const char *start, const char *end) return true; } +/** + * This method will return TRUE if the uri is mostly compliant with + * RFC 3986 and it will return FALSE if not. Specifically denying white + * space an unprintable characters + */ +static bool +url_is_mostly_compliant(const char *start, const char *end) +{ + for (const char *i = start; i < end; ++i) { + if (isspace(*i)) { + Debug("http", "Whitespace character [0x%.2X] found in URL", (unsigned char)*i); + return false; + } + if (!isprint(*i)) { + Debug("http", "Non-printable character [0x%.2X] found in URL", (unsigned char)*i); + return false; + } + } + return true; +} + ParseResult -url_parse(HdrHeap *heap, URLImpl *url, const char **start, const char *end, bool copy_strings_p, bool strict_uri_parsing) +url_parse(HdrHeap *heap, URLImpl *url, const char **start, const char *end, bool copy_strings_p, int strict_uri_parsing) { - if (strict_uri_parsing && !url_is_strictly_compliant(*start, end)) { + if (strict_uri_parsing == 1 && !url_is_strictly_compliant(*start, end)) { + return PARSE_RESULT_ERROR; + } + if (strict_uri_parsing == 2 && !url_is_mostly_compliant(*start, end)) { return PARSE_RESULT_ERROR; } diff --git a/proxy/hdrs/URL.h b/proxy/hdrs/URL.h index d1fa5822..4ab99e36 100644 --- a/proxy/hdrs/URL.h +++ b/proxy/hdrs/URL.h @@ -198,14 +198,13 @@ void url_query_set(HdrHeap *heap, URLImpl *url, const char *value, int length, b void url_fragment_set(HdrHeap *heap, URLImpl *url, const char *value, int length, bool copy_string); ParseResult url_parse(HdrHeap *heap, URLImpl *url, const char **start, const char *end, bool copy_strings, - bool strict_uri_parsing = false); + int strict_uri_parsing = false); ParseResult url_parse_no_path_component_breakdown(HdrHeap *heap, URLImpl *url, const char **start, const char *end, bool copy_strings); ParseResult url_parse_internet(HdrHeap *heap, URLImpl *url, const char **start, const char *end, bool copy_strings); ParseResult url_parse_http(HdrHeap *heap, URLImpl *url, const char **start, const char *end, bool copy_strings); ParseResult url_parse_http_no_path_component_breakdown(HdrHeap *heap, URLImpl *url, const char **start, const char *end, bool copy_strings); - char *url_unescapify(Arena *arena, const char *str, int length); void unescape_str(char *&buf, char *buf_e, const char *&str, const char *str_e, int &state); diff --git a/proxy/http/HttpConfig.cc b/proxy/http/HttpConfig.cc index 0a99ca14..2b22a411 100644 --- a/proxy/http/HttpConfig.cc +++ b/proxy/http/HttpConfig.cc @@ -1473,7 +1473,7 @@ HttpConfig::reconfigure() params->referer_filter_enabled = INT_TO_BOOL(m_master.referer_filter_enabled); params->referer_format_redirect = INT_TO_BOOL(m_master.referer_format_redirect); - params->strict_uri_parsing = INT_TO_BOOL(m_master.strict_uri_parsing); + params->strict_uri_parsing = m_master.strict_uri_parsing; params->oride.down_server_timeout = m_master.oride.down_server_timeout; params->oride.client_abort_threshold = m_master.oride.client_abort_threshold; diff --git a/proxy/http/HttpConfig.h b/proxy/http/HttpConfig.h index 93dd2ebf..5b395a36 100644 --- a/proxy/http/HttpConfig.h +++ b/proxy/http/HttpConfig.h @@ -847,7 +847,7 @@ public: MgmtByte referer_filter_enabled = 0; MgmtByte referer_format_redirect = 0; - MgmtByte strict_uri_parsing = 0; + MgmtByte strict_uri_parsing = 2; MgmtByte reverse_proxy_enabled = 0; MgmtByte url_remap_required = 1; diff --git a/tests/gold_tests/headers/gold/bad_good_request.gold b/tests/gold_tests/headers/gold/bad_good_request.gold new file mode 100644 index 00000000..ceef1e5e --- /dev/null +++ b/tests/gold_tests/headers/gold/bad_good_request.gold @@ -0,0 +1,9 @@ +``HTTP/1.1 400 Invalid HTTP Request +``Connection: close +``Server: ATS/`` +``Content-Length: 219 +`` +Bad Request +``

Bad Request

+``Description: Could not process this request. +`` diff --git a/tests/gold_tests/headers/gold/bad_good_request_header.gold b/tests/gold_tests/headers/gold/bad_good_request_header.gold new file mode 100644 index 00000000..fecd2a2d --- /dev/null +++ b/tests/gold_tests/headers/gold/bad_good_request_header.gold @@ -0,0 +1,5 @@ +``HTTP/1.1 400 Invalid HTTP Request +``Connection: close +``Server: ATS/`` +``Content-Length: 219 +`` diff --git a/tests/gold_tests/headers/gold/bad_good_request_http1.gold b/tests/gold_tests/headers/gold/bad_good_request_http1.gold new file mode 100644 index 00000000..5f31ffa9 --- /dev/null +++ b/tests/gold_tests/headers/gold/bad_good_request_http1.gold @@ -0,0 +1,8 @@ +``HTTP/1.0 400 Invalid HTTP Request +``Server: ATS/`` +``Content-Length: 219 +`` +Bad Request +``

Bad Request

+``Description: Could not process this request. +`` diff --git a/tests/gold_tests/headers/gold/bad_method.gold b/tests/gold_tests/headers/gold/bad_method.gold new file mode 100644 index 00000000..3a9558b1 --- /dev/null +++ b/tests/gold_tests/headers/gold/bad_method.gold @@ -0,0 +1,24 @@ +HTTP/1.1 501 Unsupported method ('gET') +Content-Type: text/html;charset=utf-8 +Content-Length: 496 +Date: `` +Age: 0 +Connection: keep-alive +Server: ATS/`` + + + + + + Error response + + +

Error response

+

Error code: 501

+

Message: Unsupported method ('gET').

+

Error code explanation: HTTPStatus.NOT_IMPLEMENTED - Server does not support this operation.

+ + +HTTP/1.1 200 OK +`` diff --git a/tests/gold_tests/headers/gold/bad_protocol_number.gold b/tests/gold_tests/headers/gold/bad_protocol_number.gold new file mode 100644 index 00000000..6f16cc17 --- /dev/null +++ b/tests/gold_tests/headers/gold/bad_protocol_number.gold @@ -0,0 +1,22 @@ +HTTP/1.1 505 Unsupported HTTP Version +Date: `` +Server: ATS/`` +Cache-Control: no-store +Content-Type: text/html +Content-Language: en +Content-Length: 219 + + + +Bad Request + + + +

Bad Request

+
+ + +Description: Could not process this request. + +
+ diff --git a/tests/gold_tests/headers/gold/bad_te_value.gold b/tests/gold_tests/headers/gold/bad_te_value.gold new file mode 100644 index 00000000..7fae2c54 --- /dev/null +++ b/tests/gold_tests/headers/gold/bad_te_value.gold @@ -0,0 +1,25 @@ +HTTP/1.1 501 Field not implemented +Date: `` +Connection: keep-alive +Server: ATS/`` +Cache-Control: no-store +Content-Type: text/html +Content-Language: en +Content-Length: 289 + + + +Transcoding Not Available + + + +

Transcoding Not Available

+
+ + + + Description: Unable to provide the document in the +format requested by your browser. + +
+ diff --git a/tests/gold_tests/headers/good_request_after_bad.test.py b/tests/gold_tests/headers/good_request_after_bad.test.py new file mode 100644 index 00000000..3a99d412 --- /dev/null +++ b/tests/gold_tests/headers/good_request_after_bad.test.py @@ -0,0 +1,196 @@ +''' +Verify that request following a ill-formed request is not processed +''' +# 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 os + +Test.Summary = ''' +Verify that request following a ill-formed request is not processed +''' +Test.ContinueOnFail = True +ts = Test.MakeATSProcess("ts") +Test.ContinueOnFail = True +ts.Disk.records_config.update({'proxy.config.diags.debug.tags': 'http', + 'proxy.config.diags.debug.enabled': 0, + 'proxy.config.http.strict_uri_parsing': 1 + }) + +ts2 = Test.MakeATSProcess("ts2") + +ts2.Disk.records_config.update({'proxy.config.diags.debug.tags': 'http', + 'proxy.config.diags.debug.enabled': 0, + 'proxy.config.http.strict_uri_parsing': 2 + }) + + +server = Test.MakeOriginServer("server") +request_header = {"headers": "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n", "timestamp": "1469733493.993", "body": ""} +response_header = { + "headers": "HTTP/1.1 200 OK\r\nConnection: close\r\nLast-Modified: Tue, 08 May 2018 15:49:41 GMT\r\nCache-Control: max-age=1000\r\n\r\n", + "timestamp": "1469733493.993", + "body": "xxx"} +server.addResponse("sessionlog.json", request_header, response_header) + +ts.Disk.remap_config.AddLine( + 'map / http://127.0.0.1:{0}'.format(server.Variables.Port) +) +ts.Disk.remap_config.AddLine( + 'map /bob<> http://127.0.0.1:{0}'.format(server.Variables.Port) +) +ts2.Disk.remap_config.AddLine( + 'map / http://127.0.0.1:{0}'.format(server.Variables.Port) +) +ts2.Disk.remap_config.AddLine( + 'map /bob<> http://127.0.0.1:{0}'.format(server.Variables.Port) +) + +trace_out = Test.Disk.File("trace_curl.txt") + +# Make a good request to get item in the cache for later tests +tr = Test.AddTestRun("Good control") +tr.Processes.Default.StartBefore(server) +tr.Processes.Default.StartBefore(Test.Processes.ts) +tr.Processes.Default.Command = 'printf "GET / HTTP/1.1\r\nHost: bob\r\n\r\n" | nc 127.0.0.1 {}'.format(ts.Variables.port) +tr.Processes.Default.ReturnCode = 0 + +tr = Test.AddTestRun("Good control") +tr.Processes.Default.StartBefore(server) +tr.Processes.Default.StartBefore(Test.Processes.ts2) +tr.Processes.Default.Command = 'printf "GET / HTTP/1.1\r\nHost: bob\r\n\r\n" | nc 127.0.0.1 {}'.format(ts2.Variables.port) +tr.Processes.Default.ReturnCode = 0 + +tr = Test.AddTestRun("space after header name") +tr.Processes.Default.Command = 'printf "GET / HTTP/1.1\r\nHost : bob\r\n\r\nGET / HTTP/1.1\r\nHost: boa\r\n\r\n" | nc 127.0.0.1 {}'.format( + ts.Variables.port) +tr.Processes.Default.ReturnCode = 0 +tr.Processes.Default.Streams.stdout = 'gold/bad_good_request.gold' + +# Commenting out a bunch of tests on master whose fixes are not in 8.1.x. +#tr = Test.AddTestRun("Bad protocol number") +#tr.Processes.Default.Command = 'printf "GET / HTTP/11.1\r\nhost: bob\r\n\r\nGET / HTTP/1.1\r\nHost: boa\r\n\r\n" | nc 127.0.0.1 {}'.format( +# ts.Variables.port) +#tr.Processes.Default.ReturnCode = 0 +#tr.Processes.Default.Streams.stdout = 'gold/bad_protocol_number.gold' +# +#tr = Test.AddTestRun("Unsupported Transfer Encoding value") +#tr.Processes.Default.Command = 'printf "GET / HTTP/1.1\r\nhost: bob\r\ntransfer-encoding: random\r\n\r\nGET / HTTP/1.1\r\nHost: boa\r\n\r\n" | nc 127.0.0.1 {}'.format( +# ts.Variables.port) +#tr.Processes.Default.ReturnCode = 0 +#tr.Processes.Default.Streams.stdout = 'gold/bad_te_value.gold' +# +#tr = Test.AddTestRun("Another unsupported Transfer Encoding value") +#tr.Processes.Default.Command = 'printf "GET / HTTP/1.1\r\nhost: bob\r\ntransfer-encoding: \x08chunked\r\n\r\nGET / HTTP/1.1\r\nHost: boa\r\n\r\n" | nc 127.0.0.1 {}'.format( +# ts.Variables.port) +#tr.Processes.Default.ReturnCode = 0 +#tr.Processes.Default.Streams.stdout = 'gold/bad_te_value.gold' +# +#tr = Test.AddTestRun("Extra characters in content-length") +#tr.Processes.Default.Command = 'printf "GET / HTTP/1.1\r\nhost: bob\r\ncontent-length:+3\r\n\r\nGET / HTTP/1.1\r\nHost: boa\r\n\r\n" | nc 127.0.0.1 {}'.format( +# ts.Variables.port) +#tr.Processes.Default.ReturnCode = 0 +#tr.Processes.Default.Streams.stdout = 'gold/bad_good_request_header.gold' +# +#tr = Test.AddTestRun("Different extra characters in content-length") +#tr.Processes.Default.Command = 'printf "GET / HTTP/1.1\r\nhost: bob\r\ncontent-length:\x0c3\r\n\r\nGET / HTTP/1.1\r\nHost: boa\r\n\r\n" | nc 127.0.0.1 {}'.format( +# ts.Variables.port) +#tr.Processes.Default.ReturnCode = 0 +#tr.Processes.Default.Streams.stdout = 'gold/bad_good_request_header.gold' +# +# +## TRACE request with a body +#tr = Test.AddTestRun("Trace request with a body") +#tr.Processes.Default.Command = 'printf "TRACE /foo HTTP/1.1\r\nHost: bob\r\nContent-length:2\r\n\r\nokGET / HTTP/1.1\r\nHost: boa\r\n\r\n" | nc 127.0.0.1 {}'.format( +# ts.Variables.port) +#tr.Processes.Default.ReturnCode = 0 +#tr.Processes.Default.Streams.stdout = 'gold/bad_good_request.gold' +# +#tr = Test.AddTestRun("Trace request with a chunked body") +#tr.Processes.Default.Command = 'printf "TRACE /foo HTTP/1.1\r\nHost: bob\r\ntransfer-encoding: chunked\r\n\r\n2\r\nokGGET / HTTP/1.1\r\nHost: boa\r\n\r\n" | nc 127.0.0.1 {}'.format( +# ts.Variables.port) +#tr.Processes.Default.ReturnCode = 0 +#tr.Processes.Default.Streams.stdout = 'gold/bad_good_request.gold' +# +#tr = Test.AddTestRun("Trace request with a chunked body via curl") +#tr.Processes.Default.Command = 'curl -v --http1.1 --header "Transfer-Encoding: chunked" -d aaa -X TRACE -o trace_curl.txt -k http://127.0.0.1:{}/foo'.format( +# ts.Variables.port) +#tr.Processes.Default.ReturnCode = 0 +#tr.Processes.Default.Streams.All = 'gold/bad_good_request_header.gold' +#trace_out.Content = Testers.ContainsExpression("Bad Request", "ATS error msg") +#trace_out.Content += Testers.ContainsExpression("Description: Could not process this request.", "ATS error msg") +# +#tr = Test.AddTestRun("Trace request via curl") +#tr.Processes.Default.Command = 'curl -v --http1.1 -X TRACE -k http://127.0.0.1:{}/bar'.format(ts.Variables.port) +#tr.Processes.Default.ReturnCode = 0 +#tr.Processes.Default.Streams.All = Testers.ContainsExpression( +# r"HTTP/1.1 501 Unsupported method \('TRACE'\)", +# "microserver does not support TRACE") +# +## Methods are case sensitive. Verify that "gET" is not confused with "GET". +#tr = Test.AddTestRun("mixed case method") +#tr.Processes.Default.Command = 'printf "gET / HTTP/1.1\r\nHost:bob\r\n\r\nGET / HTTP/1.1\r\nHost: boa\r\n\r\n" | nc 127.0.0.1 {}'.format( +# ts.Variables.port) +#tr.Processes.Default.ReturnCode = 0 +#tr.Processes.Default.Streams.stdout = 'gold/bad_method.gold' +# +## mangled termination +#tr = Test.AddTestRun("mangled line termination") +#tr.Processes.Default.Command = 'printf "GET / HTTP/1.1\r\nHost:bob\r\n \r\nGET / HTTP/1.1\r\nHost: boa\r\n\r\n" | nc 127.0.0.1 {}'.format( +# ts.Variables.port) +#tr.Processes.Default.ReturnCode = 0 +#tr.Processes.Default.Streams.stdout = 'gold/bad_good_request.gold' + +tr = Test.AddTestRun("Catch bad URL characters") +tr.Processes.Default.Command = 'printf "GET /bob<> HTTP/1.1\r\nhost: bob\r\n\r\nGET / HTTP/1.1\r\nHost: boa\r\n\r\n" | nc 127.0.0.1 {}'.format( + ts.Variables.port) +tr.Processes.Default.ReturnCode = 0 +# Since the request line is messsed up ATS will reply with HTTP/1.0 +tr.Processes.Default.Streams.stdout = 'gold/bad_good_request_http1.gold' + +tr = Test.AddTestRun("Catch whitespace in URL") +tr.Processes.Default.Command = 'printf "GET /bob foo HTTP/1.1\r\nhost: bob\r\n\r\nGET / HTTP/1.1\r\nHost: boa\r\n\r\n" | nc 127.0.0.1 {}'.format( + ts.Variables.port) +tr.Processes.Default.ReturnCode = 0 +# Since the request line is messsed up ATS will reply with HTTP/1.0 +tr.Processes.Default.Streams.stdout = 'gold/bad_good_request_http1.gold' + +tr = Test.AddTestRun("Extra characters in protocol") +tr.Processes.Default.Command = 'printf "GET / HTP/1.1\r\nhost: bob\r\n\r\nGET / HTTP/1.1\r\nHost: boa\r\n\r\n" | nc 127.0.0.1 {}'.format( + ts.Variables.port) +tr.Processes.Default.ReturnCode = 0 +# Since the request line is messsed up ATS will reply with HTTP/1.0 +tr.Processes.Default.Streams.stdout = 'gold/bad_good_request_http1.gold' + +tr = Test.AddTestRun("Characters that are strict but not case 2 bad") +tr.Processes.Default.Command = 'printf "GET /bob<> HTTP/1.1\r\nhost: bob\r\n\r\nGET / HTTP/1.1\r\nHost: boa\r\n\r\n" | nc 127.0.0.1 {}'.format( + ts2.Variables.port) +tr.Processes.Default.ReturnCode = 0 +tr.Processes.Default.Streams.All = Testers.ContainsExpression("HTTP/1.1 200 OK", "Success") + +tr = Test.AddTestRun("Catch whitespace in URL") +tr.Processes.Default.Command = 'printf "GET /bob foo HTTP/1.1\r\nhost: bob\r\n\r\nGET / HTTP/1.1\r\nHost: boa\r\n\r\n" | nc 127.0.0.1 {}'.format( + ts2.Variables.port) +tr.Processes.Default.ReturnCode = 0 +# Since the request line is messsed up ATS will reply with HTTP/1.0 +tr.Processes.Default.Streams.stdout = 'gold/bad_good_request_http1.gold' + +tr = Test.AddTestRun("Extra characters in protocol") +tr.Processes.Default.Command = 'printf "GET / HTP/1.1\r\nhost: bob\r\n\r\nGET / HTTP/1.1\r\nHost: boa\r\n\r\n" | nc 127.0.0.1 {}'.format( + ts2.Variables.port) +tr.Processes.Default.ReturnCode = 0 +# Since the request line is messsed up ATS will reply with HTTP/1.0 +tr.Processes.Default.Streams.stdout = 'gold/bad_good_request_http1.gold'