Repository navigation
Tests: cover the library and fix the bugs found - #158
Merged
Merged
Conversation
… MIME Raises line coverage of nusoap.php from 52% to 73% and of nusoapmime.php from 37% to 89%, focusing on logic without network access.
nusoap_server_mime::$responseAttachments had no default, so sending a response without attachments called count(null), a TypeError on PHP 8.
- opaque was written inside the quoted uri value - the nonce count never increased, as it was post-incremented - the nonce count was hashed as decimal but sent as hexadecimal - a qop list offered by the server (auth,auth-int) was echoed back, auth is now picked, and qop is sent as a token (RFC 2617) - without qop, empty qop, nc and cnonce were sent and a missing qop key raised a warning (RFC 2069) - the WWW-Authenticate challenge was split on every comma, breaking quoted values containing commas FakeHttpStream now keeps a connection with a known response length alive, so the challenge and the retried request can be tested.
setURL() copies every parse_url() part to a property, so a URL with credentials or a fragment created dynamic properties, deprecated since PHP 8.2.
parseCookie() searched for lowercase "domain=", "path=", "expires=" and "secure" anywhere in the header. Capitalized attributes (Path, Domain, Secure), common in server responses, were ignored, and a cookie value containing "path=" was taken as the path. Attributes are now parsed one by one, with case-insensitive names as required by RFC 6265.
parseFile() passed the result of file() to join(), which throws a TypeError on PHP 8 when the file cannot be read, so the "Error reading XML" error was never set.
- complexType extensions were serialized without their complexContent or simpleContent extension, dropping the base type - attributes declared or referenced inside a complexType were also registered as global attributes, so serializeSchema() declared them again at the top level and same-named attributes of different types overwrote each other
A scalar with a type from another namespace, e.g. new soapval('code',
'Currency', 'EUR', false, 'urn:types'), was serialized as xsd:string
with an unused namespace declaration. Only arrays and objects used the
given type.
- chunk-size lines with an extension (RFC 7230), e.g. "5;name=value", raised a deprecation from hexdec() in both getResponse() and decodeChunked() - decodeChunked() threw a ValueError on a truncated body instead of returning the data received so far
configureWSDL() read SERVER_PORT and SCRIPT_NAME whenever SERVER_NAME was set. Without them, an undefined key warning was raised and the empty port produced a stray colon in the endpoint URL.
getProxy() evaluates PHP code generated from the WSDL. Operation names, part names, types, the namespace and the SOAPAction were concatenated into it unescaped, so a WSDL could run arbitrary code, e.g. with a quote in a soapAction. Values are now exported as PHP literals, names must be PHP identifiers and comments cannot be terminated early.
Covers calling functions and class methods, faults, header and charset parsing, compressed requests and responses, the debug log and serving the WSDL and web description.
parseRequest() only set an error for a wrong or missing content type, so the request was processed with an empty method name and the client got a misleading "method '' not defined" fault.
A method name with nested delimiters, e.g. Ns..Class..method, is called on a namespaced class. When the class did not exist, get_class_methods() threw a TypeError on PHP 8, so any client could crash the server.
The gzip header was skipped as a fixed 10 bytes, so a request with an original file name or other optional header fields could not be decoded, and invalid data raised a warning from gzinflate().
HTTP deflate is zlib wrapped data, but many implementations send raw deflate data, as nusoap_server itself does for responses. Such requests were rejected.
A request with "Content-Encoding: GZIP" was not decoded and failed to parse, although content codings are case-insensitive (RFC 7231).
"Content-Encoding: GZIP" passed the case-insensitive check, but the payload was only decoded for the lowercase values, so the compressed data was passed to the XML parser.
HTTP deflate is zlib wrapped data (RFC 7230), but only raw deflate data was accepted, so responses of standard compliant servers failed with "Error using gzinflate to inflate the payload".
The gzip header was skipped as a fixed 10 bytes, so responses with an original file name or other optional header fields could not be decoded.
The result of the final xml_parse() call was ignored, so an incomplete document, e.g. a truncated response, was taken as successfully parsed, returned null and raised undefined key warnings.
An envelope without an element in the Body, e.g. the response of a one-way operation, raised undefined key warnings.
An element with a prefix without a namespace declaration raised undefined key warnings. Its namespace is now empty.
Serializing the WSDL before any operation was registered raised undefined key and invalid foreach warnings.
A top-level element such as <binding> was first handled by the section before it. It was stored as a bogus "binding" entry of the last portType operation, and after an empty portType it used null as an array offset, deprecated since PHP 8.5.
nusoap_server_mime::parseRequest() read the content-type header without checking it, raising undefined key warnings before the missing content type was reported.
nusoap_client_mime::parseResponse() read the content-type header without checking it, raising undefined key warnings before the missing content type was reported.
Only URLs containing "http://" were redirected, so an https:// WSDL URL was fetched and passed through instead, which fails without allow_url_fopen.
The service name, operation names, parts and documentation were written to the HTML page unescaped, so e.g. documentation mentioning <element> was rendered as a tag and & made the page invalid.
getOperationData() passed the missing operations of a binding to array_keys(), a TypeError on PHP 8, e.g. when a request reached a server whose WSDL had no operations registered.
Only xsd:string values were escaped, so e.g. an xsd:anyURI with a query containing "&" produced malformed XML.
The "!" value of a complexType with simpleContent was written unescaped, so special characters produced malformed XML.
Values of a simpleType defined in the WSDL, e.g. an enumeration, were written unescaped, so special characters produced malformed XML.
The debug message for an element without type interpolated its value, raising an "Array to string conversion" warning for an array value.
The debug message for each map entry interpolated its value, raising an "Array to string conversion" warning for an array value.
The debug message for each repeated element without type interpolated its value, raising an "Array to string conversion" warning for an array value.
An attribute referenced by ref="tns:lang" was written with its namespace qualified name, e.g. urn:svc:lang="...", which is malformed XML. It is now written as tns:lang and its value is also taken from "!tns:lang".
The SOAP header and document XML is rebuilt from the parsed elements, but the unescaped character data was appended, so e.g. a header value "x&y" was returned by getHeaders() as "x&y", which is malformed XML.
Attribute values were written unescaped to the rebuilt header and document XML, so e.g. a value containing a quote produced malformed XML.
The cookie domain was matched as a suffix of the host, so a cookie for example.com was also sent to notexample.com. The host now has to be the domain or one of its subdomains (RFC 6265).
The cookie path was matched as a case-insensitive prefix of the request path including its query, so a cookie for /app was also sent to /application. The request path now has to be the cookie path or below it (RFC 6265).
When the cache directory did not exist or was not writable, fopen() of the lock file failed with a warning and flock(false) threw a TypeError on PHP 8, so a misconfigured cache broke every client.
remove() ignores failures to obtain the lock, but released it anyway. A lock held by the caller was released early, and without any lock the unset handle was passed to flock().
A relative Location header (RFC 7231) was passed to setURL() as is, so e.g. "/other" raised undefined key warnings and "next.php" was sent as the request target. The location is now resolved against the current URL.
Only 301, 302 and 307 redirects were followed. A 308 response (RFC 7538) failed with "no data present after HTTP headers".
The debug message of send() read the content-type header without checking it, raising an undefined key warning before the missing content type was reported.
A response whose first line was not an HTTP status line, e.g. from a server not speaking HTTP, raised an undefined key warning and was processed as status 0.
With a persistent connection, a redirect to another host, port or scheme sent the request again over the connection to the previous server.
Covers rpc/encoded, rpc/literal, document/literal and literal wrapped calls, string parameters, SOAP headers and the SOAPAction header.
serializeTypeDef() read the target namespace from the schema file name, a TypeError on PHP 8, and attributes and elements without checking them. Local elements, which are no types of their own, are now rendered as empty elements instead of being dropped, and the "^" marking an element is not part of the element name.
The array type of an array of objects was "object", which is not a type. Objects are serialized as structs, so they are declared like an array of associative arrays.
The array type of an array of null values was "NULL", which is not a type.
An array of floats was declared as xsd:double[n], while its items were serialized as xsd:float.
Every parsed message was scanned for MIME boundaries and headers, so an XML response with a text line starting with "--" or containing "Content-Type:" got bogus attachments. Only a payload that fails to parse as XML can be a multipart message.
A MIME header line before the first boundary of a payload that is not XML was stored as an attachment with the key -1.
An array value for e.g. xsd:int was serialized as the text "Array" with an "Array to string conversion" warning. It is now an error, which the server reports as "unable to serialize result".
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #158 +/- ##
===========================================
+ Coverage 50.95% 81.56% +30.61%
===========================================
Files 2 2
Lines 3839 3921 +82
===========================================
+ Hits 1956 3198 +1242
+ Misses 1883 723 -1160 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Mail_mimePart::encode() of pear/mail_mime 1.10.0 and 1.10.1 counts the uninitialized subparts of a part without subparts, a TypeError on PHP 8, which failed the MIME attachment tests with --prefer-lowest.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds tests for most of the library and fixes the bugs they found. Each fix is a separate commit with a regression test that fails without the fix. The full suite passes at every commit.
Line coverage goes from 52% to 81% for
nusoap.phpand from 37% to 93% fornusoapmime.php. PHPStan errors drop from 706 to 692.Crashes on PHP 8
count(null).a..b..cnaming a missing namespaced class threw aTypeError, so any client could crash the server.TypeError.soapvalwith attributes: a scalarsoapvalwith attributes and an XSD type threw aTypeError.flock(false)throw aTypeError.TypeErrorinstead of reporting the error.serializeTypeDef(): threw aTypeErroron every call.decodeChunked()threw aValueError.Security
getProxy()evaluated code built from unescaped WSDL values, so a WSDL could run arbitrary PHP.example.comcookies tonotexample.com) and to other paths (/appcookies to/application).Wrong results
timestamp_to_iso8601()in UTC mode was off by the offset of the default timezone.=of theContent-Type. Valid UTF-8 messages with further parameters were rejected, on both the client and the server.--or containingContent-Type:got bogus attachments.opaquewas placed insideuri.ncnever increased.ncwas hashed as decimal but sent as hex.qoplist from the server was echoed back verbatim.urn:x:lang="...".Arrayfor scalar types.bindingentry was stored on the lastportTypeoperation.xsd:string.Interoperability
deflate, rawdeflateand gzip with optional header fields are now decoded.Content-Encodingis read case-insensitively.308are followed.HTTPS://) are accepted.Set-Cookieattributes are read case-insensitively.?xsd=xsd0).dateTimewithout timezone, faults withoutfaultstringand invalid status lines are now handled.Warnings and deprecations removed
SERVER_PORTmissing inconfigureWSDL().Other fixes
text/xmlnow gets a proper client fault.remove()in the WSDL cache releases only the lock it obtained.Tests
soapval, the WSDL cache and MIME attachments.FakeHttpStreamnow keeps connections with a known response length alive, so retried and redirected requests can be tested.