diff options
Diffstat (limited to 'tests/auto/networkselftest')
-rw-r--r-- | tests/auto/networkselftest/networkselftest.pro | 21 | ||||
-rw-r--r-- | tests/auto/networkselftest/rfc3252.txt | 899 | ||||
-rw-r--r-- | tests/auto/networkselftest/tst_networkselftest.cpp | 1049 |
3 files changed, 1969 insertions, 0 deletions
diff --git a/tests/auto/networkselftest/networkselftest.pro b/tests/auto/networkselftest/networkselftest.pro new file mode 100644 index 0000000000..2742fcb297 --- /dev/null +++ b/tests/auto/networkselftest/networkselftest.pro @@ -0,0 +1,21 @@ +load(qttest_p4) + +SOURCES += tst_networkselftest.cpp +QT = core network + +wince*: { + addFiles.files = rfc3252.txt + addFiles.path = . + DEPLOYMENT += addFiles + DEFINES += SRCDIR=\\\"\\\" +} else:symbian { + addFiles.files = rfc3252.txt + addFiles.path = . + DEPLOYMENT += addFiles + TARGET.CAPABILITY = NetworkServices ReadUserData +} else:vxworks*: { + DEFINES += SRCDIR=\\\"\\\" +} else { + DEFINES += SRCDIR=\\\"$$PWD/\\\" +} + diff --git a/tests/auto/networkselftest/rfc3252.txt b/tests/auto/networkselftest/rfc3252.txt new file mode 100644 index 0000000000..b80c61bf0a --- /dev/null +++ b/tests/auto/networkselftest/rfc3252.txt @@ -0,0 +1,899 @@ + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + <ip> + <header length="474"> + <version value="4"/> + <tos precedence="Routine" delay="Normal" throughput="Normal" + relibility="Normal" reserved="0"/> + <total.length value="461"/> + <id value="1"/> + <flags reserved="0" df="dont" mf="last"/> + <offset value="0"/> + <ttl value="255"/> + <protocol value="6"/> + <checksum value="8707"/> + <source address="10.0.0.22"/> + <destination address="10.0.0.1"/> + <options> + <end copied="0" class="0" number="0"/> + </options> + <padding pad="0"/> + </header> + <payload> + </payload> + </ip> + +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + <tcp> + <tcp.header> + <src port="31415"/> + <dest port="42424"/> + <sequence number="322622954"/> + <acknowledgement number="689715995"/> + <offset number=""/> + <reserved value="0"/> + <control syn="1" ack="1"/> + <window size="1"/> + <urgent pointer="0"/> + <checksum value="2988"/> + <tcp.options> + <tcp.end kind="0"/> + </tcp.options> + <padding pad="0"/> + </tcp.header> + <payload> + </payload> + </tcp> + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header + as well as the <!DOCTYPE> declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + <udp> + <udp.header> + <src port="31415"/> + <dest port="42424"/> + <udp.length value="143"/> + <checksum value="2988"/> + </udp.header> + <payload> + </payload> + </udp> + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c ("<?xml".) + +5.2. IEEE 802 + + BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except + that the protocol type code for IPoXML is 0xBEEF. + + + + + +Kennedy Informational [Page 6] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +6. Gatewaying over IP + + In order to facilitate the gradual introduction of BLOAT into the + public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to + gateway between networks that run BLOAT natively on their LANs. + +7. DTDs + + The Transport DTDs (7.2. and 7.3.) build on the definitions in the + Network DTD (7.1.) + + The DTDs are referenced by their PubidLiteral and SystemLiteral (from + [XML]) although it is understood that most IPoXML implementations + will not need to pull down the DTD, as it will normally be embedded + in the implementation, and presents something of a catch-22 if you + need to load part of your network protocol over the network. + +7.1. IPoXML DTD + + <!-- + DTD for IP over XML. + Refer to this DTD as: + + <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd"> + --> + <!-- + DTD data types: + + Digits [0..9]+ + + Precedence "NetworkControl | InternetworkControl | + CRITIC | FlashOverride | Flash | Immediate | + Priority | Routine" + + IP4Addr "dotted-decimal" notation of [RFC1123] + + Class [0..3] + + Sec "Unclassified | Confidential | EFTO | MMMM | PROG | + Restricted | Secret | Top Secret | Reserved" + + Compartments [0..65535] + + Handling [0..65535] + + TCC [0..16777216] + + --> + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ENTITY % Digits "CDATA"> + <!ENTITY % Precedence "CDATA"> + <!ENTITY % IP4Addr "CDATA"> + <!ENTITY % Class "CDATA"> + <!ENTITY % Sec "CDATA"> + <!ENTITY % Compartments "CDATA"> + <!ENTITY % Handling "CDATA"> + <!ENTITY % TCC "CDATA"> + + <!ELEMENT ip (header, payload)> + + <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl, + protocol, checksum, source, destination, options, + padding)> + <!-- length of header in 32-bit words --> + <!ATTLIST header + length %Digits; #REQUIRED> + + <!ELEMENT version EMPTY> + <!-- ip version. SHOULD be "4" --> + <!ATTLIST version + value %Digits; #REQUIRED> + + <!ELEMENT tos EMPTY> + <!ATTLIST tos + precedence %Precedence; #REQUIRED + delay (normal | low) #REQUIRED + throughput (normal | high) #REQUIRED + relibility (normal | high) #REQUIRED + reserved CDATA #FIXED "0"> + + <!ELEMENT total.length EMPTY> + <!-- + total length of datagram (header and payload) in octets, MUST be + less than 65,535 (and SHOULD be less than 1024 for IPoXML on local + ethernets). + --> + <!ATTLIST total.length + value %Digits; #REQUIRED> + + <!ELEMENT id EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST id + value %Digits; #REQUIRED> + + <!ELEMENT flags EMPTY> + <!-- df = don't fragment, mf = more fragments --> + <!ATTLIST flags + + + +Kennedy Informational [Page 8] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + reserved CDATA #FIXED "0" + df (may|dont) #REQUIRED + mf (last|more) #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks --> + <!ATTLIST offset + value %Digits; #REQUIRED> + + <!ELEMENT ttl EMPTY> + <!-- 0 <= ttl <= 255 --> + <!ATTLIST ttl + value %Digits; #REQUIRED> + + <!ELEMENT protocol EMPTY> + <!-- 0 <= protocol <= 255 (per IANA) --> + <!ATTLIST protocol + value %Digits; #REQUIRED> + + <!ELEMENT checksum EMPTY> + <!-- 0 <= checksum <= 65535 (over header only) --> + <!ATTLIST checksum + value %Digits; #REQUIRED> + + <!ELEMENT source EMPTY> + <!ATTLIST source + address %IP4Addr; #REQUIRED> + + <!ELEMENT destination EMPTY> + <!ATTLIST destination + address %IP4Addr; #REQUIRED> + + <!ELEMENT options ( end | noop | security | loose | strict | record + | stream | timestamp )*> + + <!ELEMENT end EMPTY> + <!ATTLIST end + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "0"> + + <!ELEMENT noop EMPTY> + <!ATTLIST noop + copied (0|1) #REQUIRED + class CDATA #FIXED "0" + number CDATA #FIXED "1"> + + <!ELEMENT security EMPTY> + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST security + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "2" + length CDATA #FIXED "11" + security %Sec; #REQUIRED + compartments %Compartments; #REQUIRED + handling %Handling; #REQUIRED + tcc %TCC; #REQUIRED> + <!ELEMENT loose (hop)+> + <!ATTLIST loose + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "3" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT hop EMPTY> + <!ATTLIST hop + address %IP4Addr; #REQUIRED> + + <!ELEMENT strict (hop)+> + <!ATTLIST strict + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "9" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT record (hop)+> + <!ATTLIST record + copied CDATA #FIXED "0" + class CDATA #FIXED "0" + number CDATA #FIXED "7" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED> + + <!ELEMENT stream EMPTY> + <!-- 0 <= id <= 65,535 --> + <!ATTLIST stream + copied CDATA #FIXED "1" + class CDATA #FIXED "0" + number CDATA #FIXED "8" + length CDATA #FIXED "4" + id %Digits; #REQUIRED> + + <!ELEMENT timestamp (tstamp)+> + <!-- 0 <= oflw <=15 --> + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST timestamp + copied CDATA #FIXED "0" + class CDATA #FIXED "2" + number CDATA #FIXED "4" + length %Digits; #REQUIRED + pointer %Digits; #REQUIRED + oflw %Digits; #REQUIRED + flag (0 | 1 | 3) #REQUIRED> + + <!ELEMENT tstamp EMPTY> + <!ATTLIST tstamp + time %Digits; #REQUIRED + address %IP4Addr; #IMPLIED> + <!-- + padding to bring header to 32-bit boundary. + pad MUST be "0"* + --> + <!ELEMENT padding EMPTY> + <!ATTLIST padding + pad CDATA #REQUIRED> + + <!-- payload MUST be encoded as base-64 [RFC2045], as modified + by section 2.1 of this RFC --> + <!ELEMENT payload (CDATA)> + +7.2. TCPoXML DTD + + <!-- + DTD for TCP over XML. + Refer to this DTD as: + + <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd"> + --> + + <!-- the pseudoheader is only included for checksum calculations --> + <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)> + + <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset, + reserved, control, window, checksum, urgent, + tcp.options, padding)> + + <!ELEMENT src EMPTY> + <!-- 0 <= port <= 65,535 --> + <!ATTLIST src + port %Digits; #REQUIRED> + + <!ELEMENT dest EMPTY> + <!-- 0 <= port <= 65,535 --> + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ATTLIST dest + port %Digits; #REQUIRED> + + <!ELEMENT sequence EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST sequence + number %Digits; #REQUIRED> + + <!ELEMENT acknowledgement EMPTY> + <!-- 0 <= number <= 4294967295 --> + <!ATTLIST acknowledgement + number %Digits; #REQUIRED> + + <!ELEMENT offset EMPTY> + <!-- 0 <= number <= 255 --> + <!ATTLIST offset + number %Digits; #REQUIRED> + + <!ELEMENT reserved EMPTY> + <!ATTLIST reserved + value CDATA #FIXED "0"> + + <!ELEMENT control EMPTY> + <!ATTLIST control + urg (0|1) #IMPLIED + ack (0|1) #IMPLIED + psh (0|1) #IMPLIED + rst (0|1) #IMPLIED + syn (0|1) #IMPLIED + fin (0|1) #IMPLIED> + + <!ELEMENT window EMPTY> + <!-- 0 <= size <= 65,535 --> + <!ATTLIST window + size %Digits; #REQUIRED> + + <!-- + checksum as in ip, but with + the following pseudo-header added into the tcp element: + --> + <!ELEMENT tcp.pseudoheader (source, destination, protocol, + tcp.length)> + + <!-- + tcp header + data length in octets. does not include the size of + + the pseudoheader. + --> + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + <!ELEMENT tcp.length EMPTY> + <!ATTLIST tcp.length + value %Digits; #REQUIRED> + + <!ELEMENT urgent EMPTY> + <!-- 0 <= pointer <= 65,535 --> + <!ATTLIST urgent + pointer %Digits; #REQUIRED> + + <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+> + + <!ELEMENT tcp.end EMPTY> + <!ATTLIST tcp.end + kind CDATA #FIXED "0"> + + <!ELEMENT tcp.noop EMPTY> + <!ATTLIST tcp.noop + kind CDATA #FIXED "1"> + + <!ELEMENT tcp.mss EMPTY> + <!ATTLIST tcp.mss + kind CDATA #FIXED "2" + length CDATA #FIXED "4" + size %Digits; #REQUIRED> + +7.3. UDPoXML DTD + + <!-- + DTD for UDP over XML. + Refer to this DTD as: + + <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd"> + --> + + <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)> + + <!ELEMENT udp.header (src, dest, udp.length, checksum)> + + <!ELEMENT udp.pseudoheader (source, destination, protocol, + udp.length)> + + <!-- + udp header + data length in octets. does not include the size of + the pseudoheader. + --> + <!ELEMENT udp.length EMPTY> + <!ATTLIST udp.length + value %Digits; #REQUIRED> + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + diff --git a/tests/auto/networkselftest/tst_networkselftest.cpp b/tests/auto/networkselftest/tst_networkselftest.cpp new file mode 100644 index 0000000000..f40ea3e065 --- /dev/null +++ b/tests/auto/networkselftest/tst_networkselftest.cpp @@ -0,0 +1,1049 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtNetwork/QtNetwork> + +#include <time.h> + +#ifndef QT_NO_BEARERMANAGEMENT +#include <QtNetwork/qnetworkconfigmanager.h> +#include <QtNetwork/qnetworkconfiguration.h> +#include <QtNetwork/qnetworksession.h> +#endif + +#ifdef Q_OS_SYMBIAN +// In Symbian OS test data is located in applications private dir +// Current path (C:\private\<UID>) contains only ascii chars +//#define SRCDIR QDir::currentPath() +#define SRCDIR "." +#endif + +#include "../network-settings.h" + +class tst_NetworkSelfTest: public QObject +{ + Q_OBJECT + QHostAddress cachedIpAddress; +public: + tst_NetworkSelfTest(); + virtual ~tst_NetworkSelfTest(); + + QHostAddress serverIpAddress(); + +private slots: + void initTestCase(); + void hostTest(); + void dnsResolution_data(); + void dnsResolution(); + void serverReachability(); + void remotePortsOpen_data(); + void remotePortsOpen(); + void fileLineEndingTest(); + + // specific protocol tests + void ftpServer(); + void ftpProxyServer(); + void imapServer(); + void httpServer(); + void httpServerFiles_data(); + void httpServerFiles(); + void httpServerCGI_data(); + void httpServerCGI(); + void httpsServer(); + void httpProxy(); + void httpProxyBasicAuth(); + void httpProxyNtlmAuth(); + void socks5Proxy(); + void socks5ProxyAuth(); + void smbServer(); + + // ssl supported test + void supportsSsl(); +private: +#ifndef QT_NO_BEARERMANAGEMENT + QNetworkConfigurationManager *netConfMan; + QNetworkConfiguration networkConfiguration; + QScopedPointer<QNetworkSession> networkSession; +#endif +}; + +class Chat +{ +public: + enum Type { + Reconnect, + Send, + Expect, + SkipBytes, + DiscardUntil, + DiscardUntilDisconnect, + Disconnect, + RemoteDisconnect, + StartEncryption + }; + Chat(Type t, const QByteArray &d) + : data(d), type(t) + { + } + Chat(Type t, int val = 0) + : value(val), type(t) + { + } + + static inline Chat send(const QByteArray &data) + { return Chat(Send, data); } + static inline Chat expect(const QByteArray &data) + { return Chat(Expect, data); } + static inline Chat discardUntil(const QByteArray &data) + { return Chat(DiscardUntil, data); } + static inline Chat skipBytes(int count) + { return Chat(SkipBytes, count); } + + QByteArray data; + int value; + Type type; +}; + +static QString prettyByteArray(const QByteArray &array) +{ + // any control chars? + QString result; + result.reserve(array.length() + array.length() / 3); + for (int i = 0; i < array.length(); ++i) { + char c = array.at(i); + switch (c) { + case '\n': + result += "\\n"; + continue; + case '\r': + result += "\\r"; + continue; + case '\t': + result += "\\t"; + continue; + case '"': + result += "\\\""; + continue; + default: + break; + } + + if (c < 0x20 || uchar(c) >= 0x7f) { + result += '\\'; + result += QString::number(uchar(c), 8); + } else { + result += c; + } + } + return result; +} + +static bool doSocketRead(QTcpSocket *socket, int minBytesAvailable, int timeout = 4000) +{ + QElapsedTimer timer; + timer.start(); + forever { + if (socket->bytesAvailable() >= minBytesAvailable) + return true; + if (socket->state() == QAbstractSocket::UnconnectedState + || timer.elapsed() >= timeout) + return false; + if (!socket->waitForReadyRead(timeout - timer.elapsed())) + return false; + } +} + +static bool doSocketFlush(QTcpSocket *socket, int timeout = 4000) +{ +#ifndef QT_NO_OPENSSL + QSslSocket *sslSocket = qobject_cast<QSslSocket *>(socket); +#endif + QTime timer; + timer.start(); + forever { + if (socket->bytesToWrite() == 0 +#ifndef QT_NO_OPENSSL + && sslSocket->encryptedBytesToWrite() == 0 +#endif + ) + return true; + if (socket->state() == QAbstractSocket::UnconnectedState + || timer.elapsed() >= timeout) + return false; + if (!socket->waitForBytesWritten(timeout - timer.elapsed())) + return false; + } +} + +static void netChat(int port, const QList<Chat> &chat) +{ +#ifndef QT_NO_OPENSSL + QSslSocket socket; +#else + QTcpSocket socket; +#endif + + socket.connectToHost(QtNetworkSettings::serverName(), port); + qDebug() << 0 << "Connecting to server on port" << port; + QVERIFY2(socket.waitForConnected(10000), + QString("Failed to connect to server in step 0: %1").arg(socket.errorString()).toLocal8Bit()); + + // now start the chat + QList<Chat>::ConstIterator it = chat.constBegin(); + for (int i = 1; it != chat.constEnd(); ++it, ++i) { + switch (it->type) { + case Chat::Expect: { + qDebug() << i << "Expecting" << prettyByteArray(it->data); + if (!doSocketRead(&socket, it->data.length())) + QFAIL(QString("Failed to receive data in step %1: timeout").arg(i).toLocal8Bit()); + + // pop that many bytes off the socket + QByteArray received = socket.read(it->data.length()); + + // is it what we expected? + QVERIFY2(received == it->data, + QString("Did not receive expected data in step %1: data received was:\n%2") + .arg(i).arg(prettyByteArray(received)).toLocal8Bit()); + + break; + } + + case Chat::DiscardUntil: + qDebug() << i << "Discarding until" << prettyByteArray(it->data); + while (true) { + // scan the buffer until we have our string + if (!doSocketRead(&socket, it->data.length())) + QFAIL(QString("Failed to receive data in step %1: timeout").arg(i).toLocal8Bit()); + + QByteArray buffer; + buffer.resize(socket.bytesAvailable()); + socket.peek(buffer.data(), socket.bytesAvailable()); + + int pos = buffer.indexOf(it->data); + if (pos == -1) { + // data not found, keep trying + continue; + } + + buffer = socket.read(pos + it->data.length()); + qDebug() << i << "Discarded" << prettyByteArray(buffer); + break; + } + break; + + case Chat::SkipBytes: { + qDebug() << i << "Skipping" << it->value << "bytes"; + if (!doSocketRead(&socket, it->value)) + QFAIL(QString("Failed to receive data in step %1: timeout").arg(i).toLocal8Bit()); + + // now discard the bytes + QByteArray buffer = socket.read(it->value); + qDebug() << i << "Skipped" << prettyByteArray(buffer); + break; + } + + case Chat::Send: { + qDebug() << i << "Sending" << prettyByteArray(it->data); + socket.write(it->data); + if (!doSocketFlush(&socket)) { + QVERIFY2(socket.state() == QAbstractSocket::ConnectedState, + QString("Socket disconnected while sending data in step %1").arg(i).toLocal8Bit()); + QFAIL(QString("Failed to send data in step %1: timeout").arg(i).toLocal8Bit()); + } + break; + } + + case Chat::Disconnect: + qDebug() << i << "Disconnecting from host"; + socket.disconnectFromHost(); + + // is this the last command? + if (it + 1 != chat.constEnd()) + break; + + // fall through: + case Chat::RemoteDisconnect: + case Chat::DiscardUntilDisconnect: + qDebug() << i << "Waiting for remote disconnect"; + if (socket.state() != QAbstractSocket::UnconnectedState) + socket.waitForDisconnected(10000); + QVERIFY2(socket.state() == QAbstractSocket::UnconnectedState, + QString("Socket did not disconnect as expected in step %1").arg(i).toLocal8Bit()); + + // any data left? + if (it->type == Chat::DiscardUntilDisconnect) { + QByteArray buffer = socket.readAll(); + qDebug() << i << "Discarded in the process:" << prettyByteArray(buffer); + } + + if (socket.bytesAvailable() != 0) + QFAIL(QString("Unexpected bytes still on buffer when disconnecting in step %1:\n%2") + .arg(i).arg(prettyByteArray(socket.readAll())).toLocal8Bit()); + break; + + case Chat::Reconnect: + qDebug() << i << "Reconnecting to server on port" << port; + socket.connectToHost(QtNetworkSettings::serverName(), port); + QVERIFY2(socket.waitForConnected(10000), + QString("Failed to reconnect to server in step %1: %2").arg(i).arg(socket.errorString()).toLocal8Bit()); + break; + + case Chat::StartEncryption: +#ifdef QT_NO_OPENSSL + QFAIL("Internal error: SSL required for this test"); +#else + qDebug() << i << "Starting client encryption"; + socket.ignoreSslErrors(); + socket.startClientEncryption(); + QVERIFY2(socket.waitForEncrypted(5000), + QString("Failed to start client encryption in step %1: %2").arg(i) + .arg(socket.errorString()).toLocal8Bit()); + break; +#endif + } + } +} + +tst_NetworkSelfTest::tst_NetworkSelfTest() +{ + Q_SET_DEFAULT_IAP +} + +tst_NetworkSelfTest::~tst_NetworkSelfTest() +{ +} + +QHostAddress tst_NetworkSelfTest::serverIpAddress() +{ + if (cachedIpAddress.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol) { + // need resolving + QHostInfo resolved = QHostInfo::fromName(QtNetworkSettings::serverName()); + if(resolved.error() != QHostInfo::NoError || + resolved.addresses().isEmpty()) { + qWarning("QHostInfo::fromName failed (%d).", resolved.error()); + return QHostAddress(QHostAddress::Null); + } + cachedIpAddress = resolved.addresses().first(); + } + return cachedIpAddress; +} + +void tst_NetworkSelfTest::initTestCase() +{ +#ifndef QT_NO_BEARERMANAGEMENT + netConfMan = new QNetworkConfigurationManager(this); + networkConfiguration = netConfMan->defaultConfiguration(); + networkSession.reset(new QNetworkSession(networkConfiguration)); + if (!networkSession->isOpen()) { + networkSession->open(); + QVERIFY(networkSession->waitForOpened(30000)); + } +#endif +} + +void tst_NetworkSelfTest::hostTest() +{ + // this is a localhost self-test + QHostInfo localhost = QHostInfo::fromName("localhost"); + QCOMPARE(localhost.error(), QHostInfo::NoError); + QVERIFY(!localhost.addresses().isEmpty()); + + QTcpServer server; + QVERIFY(server.listen()); + + QTcpSocket socket; + socket.connectToHost("127.0.0.1", server.serverPort()); + QVERIFY(socket.waitForConnected(10000)); +} + +void tst_NetworkSelfTest::dnsResolution_data() +{ + QTest::addColumn<QString>("hostName"); + QTest::newRow("local-name") << QtNetworkSettings::serverLocalName(); + QTest::newRow("fqdn") << QtNetworkSettings::serverName(); +} + +void tst_NetworkSelfTest::dnsResolution() +{ + QFETCH(QString, hostName); + QHostInfo resolved = QHostInfo::fromName(hostName); + QVERIFY2(resolved.error() == QHostInfo::NoError, + QString("Failed to resolve hostname %1: %2").arg(hostName, resolved.errorString()).toLocal8Bit()); + QVERIFY2(resolved.addresses().size() > 0, "Got 0 addresses for server IP"); + + cachedIpAddress = resolved.addresses().first(); +} + +void tst_NetworkSelfTest::serverReachability() +{ + // check that we get a proper error connecting to port 12346 + QTcpSocket socket; + socket.connectToHost(QtNetworkSettings::serverName(), 12346); + + QTime timer; + timer.start(); + socket.waitForConnected(10000); + QVERIFY2(timer.elapsed() < 9900, "Connection to closed port timed out instead of refusing, something is wrong"); + + QVERIFY2(socket.state() == QAbstractSocket::UnconnectedState, "Socket connected unexpectedly!"); + QVERIFY2(socket.error() == QAbstractSocket::ConnectionRefusedError, + QString("Could not reach server: %1").arg(socket.errorString()).toLocal8Bit()); +} + +void tst_NetworkSelfTest::remotePortsOpen_data() +{ + QTest::addColumn<int>("portNumber"); + QTest::newRow("echo") << 7; + QTest::newRow("daytime") << 13; + QTest::newRow("ftp") << 21; + QTest::newRow("ssh") << 22; + QTest::newRow("imap") << 143; + QTest::newRow("http") << 80; + QTest::newRow("https") << 443; + QTest::newRow("http-proxy") << 3128; + QTest::newRow("http-proxy-auth-basic") << 3129; + QTest::newRow("http-proxy-auth-ntlm") << 3130; + QTest::newRow("socks5-proxy") << 1080; + QTest::newRow("socks5-proxy-auth") << 1081; + QTest::newRow("ftp-proxy") << 2121; + QTest::newRow("smb") << 139; +} + +void tst_NetworkSelfTest::remotePortsOpen() +{ +#ifdef Q_OS_SYMBIAN + if (qstrcmp(QTest::currentDataTag(), "http-proxy-auth-ntlm") == 0) + QSKIP("NTML authentication not yet supported in Symbian", SkipSingle); +#endif + + QFETCH(int, portNumber); + QTcpSocket socket; + socket.connectToHost(QtNetworkSettings::serverName(), portNumber); + + if (!socket.waitForConnected(10000)) { + if (socket.error() == QAbstractSocket::SocketTimeoutError) + QFAIL(QString("Network timeout connecting to the server on port %1").arg(portNumber).toLocal8Bit()); + else + QFAIL(QString("Error connecting to server on port %1: %2").arg(portNumber).arg(socket.errorString()).toLocal8Bit()); + } + QVERIFY(socket.state() == QAbstractSocket::ConnectedState); +} + + +void tst_NetworkSelfTest::fileLineEndingTest() +{ + QString referenceName = SRCDIR "/rfc3252.txt"; + long long expectedReferenceSize = 25962; + + QString lineEndingType("LF"); + + QFile reference(referenceName); + QVERIFY(reference.open(QIODevice::ReadOnly)); + QByteArray byteLine = reference.readLine(); + if(byteLine.endsWith("\r\n")) + lineEndingType = "CRLF"; + else if(byteLine.endsWith("\r")) + lineEndingType = "CR"; + + QString referenceAsTextData; + QFile referenceAsText(referenceName); + QVERIFY(referenceAsText.open(QIODevice::ReadOnly)); + referenceAsTextData = referenceAsText.readAll(); + + QVERIFY2(expectedReferenceSize == referenceAsTextData.length(), QString("Reference file %1 has %2 as line ending and file size not matching - Git checkout issue !?!").arg(referenceName, lineEndingType).toLocal8Bit()); + QVERIFY2(!lineEndingType.compare("LF"), QString("Reference file %1 has %2 as line ending - Git checkout issue !?!").arg(referenceName, lineEndingType).toLocal8Bit()); +} + +static QList<Chat> ftpChat(const QByteArray &userSuffix = QByteArray()) +{ + QList<Chat> rv; + rv << Chat::expect("220") + << Chat::discardUntil("\r\n") + << Chat::send("USER anonymous" + userSuffix + "\r\n") + << Chat::expect("331") + << Chat::discardUntil("\r\n") + << Chat::send("PASS user@hostname\r\n") + << Chat::expect("230") + << Chat::discardUntil("\r\n") + + << Chat::send("CWD pub\r\n") + << Chat::expect("250") + << Chat::discardUntil("\r\n") + << Chat::send("CWD dir-not-readable\r\n") + << Chat::expect("550") + << Chat::discardUntil("\r\n") + << Chat::send("PWD\r\n") + << Chat::expect("257 \"/pub\"\r\n") + << Chat::send("SIZE file-not-readable.txt\r\n") + << Chat::expect("213 41\r\n") + << Chat::send("CWD qxmlquery\r\n") + << Chat::expect("250") + << Chat::discardUntil("\r\n") + + << Chat::send("CWD /qtest\r\n") + << Chat::expect("250") + << Chat::discardUntil("\r\n") + << Chat::send("SIZE bigfile\r\n") + << Chat::expect("213 519240\r\n") + << Chat::send("SIZE rfc3252\r\n") + << Chat::expect("213 25962\r\n") + << Chat::send("SIZE rfc3252.txt\r\n") + << Chat::expect("213 25962\r\n") +// << Chat::send("SIZE nonASCII/german_\344\366\374\304\326\334\337\r\n") +// << Chat::expect("213 40\r\n") + + << Chat::send("QUIT\r\n"); +#ifdef Q_OS_SYMBIAN + if (userSuffix.length() == 0) // received but unacknowledged packets are discarded by TCP RST, so this doesn't work with frox proxy +#endif + rv << Chat::expect("221") + << Chat::discardUntil("\r\n"); + + rv << Chat::RemoteDisconnect; + return rv; +} + +void tst_NetworkSelfTest::ftpServer() +{ + netChat(21, ftpChat()); +} + +void tst_NetworkSelfTest::ftpProxyServer() +{ + netChat(2121, ftpChat("@" + QtNetworkSettings::serverName().toLatin1())); +} + +void tst_NetworkSelfTest::imapServer() +{ + netChat(143, QList<Chat>() + << Chat::expect("* OK ") + << Chat::discardUntil("\r\n") + << Chat::send("1 CAPABILITY\r\n") + << Chat::expect("* CAPABILITY ") + << Chat::discardUntil("1 OK") + << Chat::discardUntil("\r\n") + << Chat::send("2 LOGOUT\r\n") + << Chat::discardUntil("2 OK") + << Chat::discardUntil("\r\n") + << Chat::RemoteDisconnect); +} + +void tst_NetworkSelfTest::httpServer() +{ + QString uniqueExtension; + qsrand(time(0)); +#ifndef Q_OS_WINCE + uniqueExtension = QString("%1%2%3").arg((qulonglong)this).arg(qrand()).arg((qulonglong)time(0)); +#else + uniqueExtension = QString("%1%2").arg((qulonglong)this).arg(qrand()); +#endif + + netChat(80, QList<Chat>() + // HTTP/0.9 chat: + << Chat::send("GET /\r\n") + << Chat::DiscardUntilDisconnect + + // HTTP/1.0 chat: + << Chat::Reconnect + << Chat::send("GET / HTTP/1.0\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Connection: close\r\n" + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("200 ") + << Chat::DiscardUntilDisconnect + + // HTTP/1.0 POST: + << Chat::Reconnect + << Chat::send("POST / HTTP/1.0\r\n" + "Content-Length: 5\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Connection: close\r\n" + "\r\n" + "Hello") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("200 ") + << Chat::DiscardUntilDisconnect + + // HTTP protected area + << Chat::Reconnect + << Chat::send("GET /qtest/protected/rfc3252.txt HTTP/1.0\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Connection: close\r\n" + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("401 ") + << Chat::DiscardUntilDisconnect + + << Chat::Reconnect + << Chat::send("HEAD /qtest/protected/rfc3252.txt HTTP/1.0\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Connection: close\r\n" + "Authorization: Basic cXNvY2tzdGVzdDpwYXNzd29yZA==\r\n" + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("200 ") + << Chat::DiscardUntilDisconnect + + // DAV area + << Chat::Reconnect + << Chat::send("HEAD /dav/ HTTP/1.0\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Connection: close\r\n" + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("200 ") + << Chat::DiscardUntilDisconnect + + // HTTP/1.0 PUT + << Chat::Reconnect + << Chat::send("PUT /dav/networkselftest-" + uniqueExtension.toLatin1() + ".txt HTTP/1.0\r\n" + "Content-Length: 5\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Connection: close\r\n" + "\r\n" + "Hello") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("201 ") + << Chat::DiscardUntilDisconnect + + // check that the file did get uploaded + << Chat::Reconnect + << Chat::send("HEAD /dav/networkselftest-" + uniqueExtension.toLatin1() + ".txt HTTP/1.0\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Connection: close\r\n" + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("200 ") + << Chat::discardUntil("\r\nContent-Length: 5\r\n") + << Chat::DiscardUntilDisconnect + + // HTTP/1.0 DELETE + << Chat::Reconnect + << Chat::send("DELETE /dav/networkselftest-" + uniqueExtension.toLatin1() + ".txt HTTP/1.0\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Connection: close\r\n" + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("204 ") + << Chat::DiscardUntilDisconnect + ); +} + +void tst_NetworkSelfTest::httpServerFiles_data() +{ + QTest::addColumn<QString>("uri"); + QTest::addColumn<int>("size"); + + QTest::newRow("fluke.gif") << "/qtest/fluke.gif" << -1; + QTest::newRow("bigfile") << "/qtest/bigfile" << 519240; + QTest::newRow("rfc3252.txt") << "/qtest/rfc3252.txt" << 25962; + QTest::newRow("protected/rfc3252.txt") << "/qtest/protected/rfc3252.txt" << 25962; + QTest::newRow("completelyEmptyQuery.xq") << "/qtest/qxmlquery/completelyEmptyQuery.xq" << -1; + QTest::newRow("notWellformedViaHttps.xml") << "/qtest/qxmlquery/notWellformedViaHttps.xml" << -1; + QTest::newRow("notWellformed.xml") << "/qtest/qxmlquery/notWellformed.xml" << -1; + QTest::newRow("viaHttp.xq") << "/qtest/qxmlquery/viaHttp.xq" << -1; + QTest::newRow("wellFormedViaHttps.xml") << "/qtest/qxmlquery/wellFormedViaHttps.xml" << -1; + QTest::newRow("wellFormed.xml") << "/qtest/qxmlquery/wellFormed.xml" << -1; +} + +void tst_NetworkSelfTest::httpServerFiles() +{ + QFETCH(QString, uri); + QFETCH(int, size); + + QList<Chat> chat; + chat << Chat::send("HEAD " + QUrl::toPercentEncoding(uri, "/") + " HTTP/1.0\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Connection: close\r\n" + "Authorization: Basic cXNvY2tzdGVzdDpwYXNzd29yZA==\r\n" + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::skipBytes(1) // HTTP/1.0 or 1.1 reply + << Chat::expect(" 200 "); + if (size != -1) + chat << Chat::discardUntil("\r\nContent-Length: " + QByteArray::number(size) + "\r\n"); + chat << Chat::DiscardUntilDisconnect; + netChat(80, chat); +} + +void tst_NetworkSelfTest::httpServerCGI_data() +{ + QTest::addColumn<QByteArray>("request"); + QTest::addColumn<QByteArray>("result"); + QTest::addColumn<QByteArray>("additionalHeader"); + + QTest::newRow("echo.cgi") + << QByteArray("GET /qtest/cgi-bin/echo.cgi?Hello+World HTTP/1.0\r\n" + "Connection: close\r\n" + "\r\n") + << QByteArray("Hello+World") + << QByteArray(); + + QTest::newRow("echo.cgi(POST)") + << QByteArray("POST /qtest/cgi-bin/echo.cgi?Hello+World HTTP/1.0\r\n" + "Connection: close\r\n" + "Content-Length: 15\r\n" + "\r\n" + "Hello, World!\r\n") + << QByteArray("Hello, World!\r\n") + << QByteArray(); + + QTest::newRow("md5sum.cgi") + << QByteArray("POST /qtest/cgi-bin/md5sum.cgi HTTP/1.0\r\n" + "Connection: close\r\n" + "Content-Length: 15\r\n" + "\r\n" + "Hello, World!\r\n") + << QByteArray("29b933a8d9a0fcef0af75f1713f4940e\n") + << QByteArray(); + + QTest::newRow("protected/md5sum.cgi") + << QByteArray("POST /qtest/protected/cgi-bin/md5sum.cgi HTTP/1.0\r\n" + "Connection: close\r\n" + "Authorization: Basic cXNvY2tzdGVzdDpwYXNzd29yZA==\r\n" + "Content-Length: 15\r\n" + "\r\n" + "Hello, World!\r\n") + << QByteArray("29b933a8d9a0fcef0af75f1713f4940e\n") + << QByteArray(); + + QTest::newRow("set-cookie.cgi") + << QByteArray("POST /qtest/cgi-bin/set-cookie.cgi HTTP/1.0\r\n" + "Connection: close\r\n" + "Content-Length: 8\r\n" + "\r\n" + "foo=bar\n") + << QByteArray("Success\n") + << QByteArray("\r\nSet-Cookie: foo=bar\r\n"); +} + +void tst_NetworkSelfTest::httpServerCGI() +{ + QFETCH(QByteArray, request); + QFETCH(QByteArray, result); + QFETCH(QByteArray, additionalHeader); + QList<Chat> chat; + chat << Chat::send(request) + << Chat::expect("HTTP/1.") << Chat::skipBytes(1) + << Chat::expect(" 200 "); + + if (!additionalHeader.isEmpty()) + chat << Chat::discardUntil(additionalHeader); + + chat << Chat::discardUntil("\r\n\r\n") + << Chat::expect(result) + << Chat::RemoteDisconnect; + netChat(80, chat); +} + +void tst_NetworkSelfTest::httpsServer() +{ +#ifndef QT_NO_OPENSSL + netChat(443, QList<Chat>() + << Chat::StartEncryption + << Chat::send("GET / HTTP/1.0\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Connection: close\r\n" + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("200 ") + << Chat::DiscardUntilDisconnect); +#else + QSKIP("SSL not enabled, cannot test", SkipAll); +#endif +} + +void tst_NetworkSelfTest::httpProxy() +{ + netChat(3128, QList<Chat>() + // proxy GET by IP + << Chat::send("GET http://" + serverIpAddress().toString().toLatin1() + "/ HTTP/1.0\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Proxy-connection: close\r\n" + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("200 ") + << Chat::DiscardUntilDisconnect + + // proxy GET by hostname + << Chat::Reconnect + << Chat::send("GET http://" + QtNetworkSettings::serverName().toLatin1() + "/ HTTP/1.0\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Proxy-connection: close\r\n" + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("200 ") + << Chat::DiscardUntilDisconnect + + // proxy CONNECT by IP + << Chat::Reconnect + << Chat::send("CONNECT " + serverIpAddress().toString().toLatin1() + ":21 HTTP/1.0\r\n" + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("200 ") + << Chat::discardUntil("\r\n\r\n") + << ftpChat() + + // proxy CONNECT by hostname + << Chat::Reconnect + << Chat::send("CONNECT " + QtNetworkSettings::serverName().toLatin1() + ":21 HTTP/1.0\r\n" + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("200 ") + << Chat::discardUntil("\r\n\r\n") + << ftpChat() + ); +} + +void tst_NetworkSelfTest::httpProxyBasicAuth() +{ + netChat(3129, QList<Chat>() + // test auth required response + << Chat::send("GET http://" + QtNetworkSettings::serverName().toLatin1() + "/ HTTP/1.0\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Proxy-connection: close\r\n" + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("407 ") + << Chat::discardUntil("\r\nProxy-Authenticate: Basic realm=\"") + << Chat::DiscardUntilDisconnect + + // now try sending our credentials + << Chat::Reconnect + << Chat::send("GET http://" + QtNetworkSettings::serverName().toLatin1() + "/ HTTP/1.0\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Proxy-connection: close\r\n" + "Proxy-Authorization: Basic cXNvY2tzdGVzdDpwYXNzd29yZA==\r\n" + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("200 ") + << Chat::DiscardUntilDisconnect); +} + +void tst_NetworkSelfTest::httpProxyNtlmAuth() +{ +#ifdef Q_OS_SYMBIAN + QSKIP("NTML authentication not yet supported in Symbian", SkipAll); +#else + netChat(3130, QList<Chat>() + // test auth required response + << Chat::send("GET http://" + QtNetworkSettings::serverName().toLatin1() + "/ HTTP/1.0\r\n" + "Host: " + QtNetworkSettings::serverName().toLatin1() + "\r\n" + "Proxy-connection: keep-alive\r\n" // NTLM auth will disconnect + "\r\n") + << Chat::expect("HTTP/1.") + << Chat::discardUntil(" ") + << Chat::expect("407 ") + << Chat::discardUntil("\r\nProxy-Authenticate: NTLM\r\n") + << Chat::DiscardUntilDisconnect + ); +#endif +} + +// SOCKSv5 is a binary protocol +static const char handshakeNoAuth[] = "\5\1\0"; +static const char handshakeOkNoAuth[] = "\5\0"; +static const char handshakeAuthPassword[] = "\5\1\2\1\12qsockstest\10password"; +static const char handshakeOkPasswdAuth[] = "\5\2\1\0"; +static const char handshakeAuthNotOk[] = "\5\377"; +static const char connect1[] = "\5\1\0\1\177\0\0\1\0\25"; // Connect IPv4 127.0.0.1 port 21 +static const char connect1a[] = "\5\1\0\1"; // just "Connect to IPv4" +static const char connect1b[] = "\0\25"; // just "port 21" +static const char connect2[] = "\5\1\0\3\11localhost\0\25"; // Connect hostname localhost 21 +static const char connect2a[] = "\5\1\0\3"; // just "Connect to hostname" +static const char connected[] = "\5\0\0"; + +#define QBA(x) (QByteArray::fromRawData(x, -1 + sizeof(x))) + +void tst_NetworkSelfTest::socks5Proxy() +{ + union { + char buf[4]; + quint32 data; + } ip4Address; + ip4Address.data = qToBigEndian(serverIpAddress().toIPv4Address()); + + netChat(1080, QList<Chat>() + // IP address connection + << Chat::send(QByteArray(handshakeNoAuth, -1 + sizeof handshakeNoAuth)) + << Chat::expect(QByteArray(handshakeOkNoAuth, -1 + sizeof handshakeOkNoAuth)) + << Chat::send(QByteArray(connect1, -1 + sizeof connect1)) + << Chat::expect(QByteArray(connected, -1 + sizeof connected)) + << Chat::expect("\1") // IPv4 address following + << Chat::skipBytes(6) // the server's local address and port + << ftpChat() + + // connect by IP + << Chat::Reconnect + << Chat::send(QByteArray(handshakeNoAuth, -1 + sizeof handshakeNoAuth)) + << Chat::expect(QByteArray(handshakeOkNoAuth, -1 + sizeof handshakeOkNoAuth)) + << Chat::send(QBA(connect1a) + QByteArray::fromRawData(ip4Address.buf, 4) + QBA(connect1b)) + << Chat::expect(QByteArray(connected, -1 + sizeof connected)) + << Chat::expect("\1") // IPv4 address following + << Chat::skipBytes(6) // the server's local address and port + << ftpChat() + + // connect to "localhost" by hostname + << Chat::Reconnect + << Chat::send(QByteArray(handshakeNoAuth, -1 + sizeof handshakeNoAuth)) + << Chat::expect(QByteArray(handshakeOkNoAuth, -1 + sizeof handshakeOkNoAuth)) + << Chat::send(QByteArray(connect2, -1 + sizeof connect2)) + << Chat::expect(QByteArray(connected, -1 + sizeof connected)) + << Chat::expect("\1") // IPv4 address following + << Chat::skipBytes(6) // the server's local address and port + << ftpChat() + + // connect to server by its official name + << Chat::Reconnect + << Chat::send(QByteArray(handshakeNoAuth, -1 + sizeof handshakeNoAuth)) + << Chat::expect(QByteArray(handshakeOkNoAuth, -1 + sizeof handshakeOkNoAuth)) + << Chat::send(QBA(connect2a) + char(QtNetworkSettings::serverName().size()) + QtNetworkSettings::serverName().toLatin1() + QBA(connect1b)) + << Chat::expect(QByteArray(connected, -1 + sizeof connected)) + << Chat::expect("\1") // IPv4 address following + << Chat::skipBytes(6) // the server's local address and port + << ftpChat() + ); +} + +void tst_NetworkSelfTest::socks5ProxyAuth() +{ + netChat(1081, QList<Chat>() + // unauthenticated connect -- will get error + << Chat::send(QByteArray(handshakeNoAuth, -1 + sizeof handshakeNoAuth)) + << Chat::expect(QByteArray(handshakeAuthNotOk, -1 + sizeof handshakeAuthNotOk)) + << Chat::RemoteDisconnect + + // now try to connect with authentication + << Chat::Reconnect + << Chat::send(QByteArray(handshakeAuthPassword, -1 + sizeof handshakeAuthPassword)) + << Chat::expect(QByteArray(handshakeOkPasswdAuth, -1 + sizeof handshakeOkPasswdAuth)) + << Chat::send(QByteArray(connect1, -1 + sizeof connect1)) + << Chat::expect(QByteArray(connected, -1 + sizeof connected)) + << Chat::expect("\1") // IPv4 address following + << Chat::skipBytes(6) // the server's local address and port + << ftpChat() + ); +} + +void tst_NetworkSelfTest::supportsSsl() +{ +#ifdef QT_NO_OPENSSL + QFAIL("SSL not compiled in"); +#else + QVERIFY2(QSslSocket::supportsSsl(), "Could not load SSL libraries"); +#endif +} + +void tst_NetworkSelfTest::smbServer() +{ + static const char contents[] = "This is 34 bytes. Do not change..."; +#ifdef Q_OS_WIN + // use Windows's native UNC support to try and open a file on the server + QString filepath = QString("\\\\%1\\testshare\\test.pri").arg(QtNetworkSettings::winServerName()); + FILE *f = fopen(filepath.toLatin1(), "rb"); + QVERIFY2(f, qt_error_string().toLocal8Bit()); + + char buf[128]; + size_t ret = fread(buf, 1, sizeof buf, f); + fclose(f); + + QCOMPARE(ret, strlen(contents)); + QVERIFY(memcmp(buf, contents, strlen(contents)) == 0); +#else + // try to use Samba + QString progname = "smbclient"; + QProcess smbclient; + smbclient.start(progname, QIODevice::ReadOnly); + if (!smbclient.waitForStarted(2000)) + QSKIP("Could not find smbclient (from Samba), cannot continue testing", SkipAll); + if (!smbclient.waitForFinished(2000) || smbclient.exitStatus() != QProcess::NormalExit) + QSKIP("smbclient isn't working, cannot continue testing", SkipAll); + smbclient.close(); + + // try listing the server + smbclient.start(progname, QStringList() << "-g" << "-N" << "-L" << QtNetworkSettings::winServerName(), QIODevice::ReadOnly); + QVERIFY(smbclient.waitForFinished(5000)); + if (smbclient.exitStatus() != QProcess::NormalExit) + QSKIP("smbclient crashed", SkipAll); + QVERIFY2(smbclient.exitCode() == 0, "Test server not found"); + + QByteArray output = smbclient.readAll(); + QVERIFY(output.contains("Disk|testshare|")); + QVERIFY(output.contains("Disk|testsharewritable|")); + QVERIFY(output.contains("Disk|testsharelargefile|")); + qDebug() << "Test server found and shares are correct"; + + // try getting a file + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert("PAGER", "/bin/cat"); // just in case + smbclient.setProcessEnvironment(env); + smbclient.start(progname, QStringList() << "-N" << "-c" << "more test.pri" + << QString("\\\\%1\\testshare").arg(QtNetworkSettings::winServerName()), QIODevice::ReadOnly); + QVERIFY(smbclient.waitForFinished(5000)); + if (smbclient.exitStatus() != QProcess::NormalExit) + QSKIP("smbclient crashed", SkipAll); + QVERIFY2(smbclient.exitCode() == 0, "File //qt-test-server/testshare/test.pri not found"); + + output = smbclient.readAll(); + QCOMPARE(output.constData(), contents); + qDebug() << "Test file is correct"; +#endif +} + +QTEST_MAIN(tst_NetworkSelfTest) +#include "tst_networkselftest.moc" |