1 /* This file is part of the KDE libraries
2 Copyright (c) 2008 Andreas Hartmetz <ahartmetz@gmail.com>
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
20 #include <qtest_kde.h>
22 #include <QtCore/QByteArray>
23 #include <QtCore/QHash>
24 #include <QtCore/QObject>
27 #include <parsinghelpers.h>
29 #include "httpheadertokenizetest.h"
30 #include "httpheadertokenizetest.moc"
32 #include <parsinghelpers.cpp>
34 QTEST_KDEMAIN(HeaderTokenizeTest
, NoGUI
)
36 /* some possible fields that can be used for test headers
37 {"accept-ranges", false},
38 {"cache-control", true},
40 {"content-disposition", false}, //is multi-valued in a way, but with ";" separator!
41 {"content-encoding", true},
42 {"content-language", true},
43 {"content-length", false},
44 {"content-location", false},
45 {"content-md5", false},
46 {"content-type", false},
48 {"dav", true}, //RFC 2518
51 {"keep-alive", false}, //RFC 2068
52 {"last-modified", false},
53 {"link", false}, //RFC 2068, multi-valued with ";" separator
57 //no use testing many different headers, just a couple each of the multi-valued
58 //and the single-valued group to make sure that corner cases work both if there
59 //are already entries for the header and if there are no entries.
60 static const char *messyHeader
=
62 "accept-ranges:foo\r\n"
68 "accept-Ranges:\tmaybe \r"
70 "CoNNectIoN:four, , ,, , \r\n"
73 "\tinvalid: connection:close\t\r"
74 "connection: Six, seven ,, , eight\r" //one malformed newline...
75 "\n\r "; //two malformed newlines; end of header. also observe the trailing space.
77 //tab separates values, newline separates header lines. the first word is the key.
78 static const char* messyResult
=
79 "accept-ranges\tfoo\t42\tmaybe or not\n"
80 "connection\tone t_ wo\tthree\tfour\t:fi:ve\tSix\tseven\teight";
83 static const char *redirectHeader
=
84 //"HTTP/1.1 302 Moved Temporarily\r\n"
85 "Location: http://www.hertz.de/rentacar/index.jsp?bsc=t&targetPage=reservationOnHomepage.jsp\r\n"
86 "Connection:close\r\n"
87 "Cache-Control: no-cache\r\n"
88 "Pragma: no-cache\r\n"
91 static const char *redirectResult
=
92 "cache-control\tno-cache\n"
94 "location\thttp://www.hertz.de/rentacar/index.jsp?bsc=t&targetPage=reservationOnHomepage.jsp\n"
97 static const int bufSize
= 4096;
100 void HeaderTokenizeTest::testMessyHeader()
102 //Copy the header into a writable buffer
103 for (int i
= 0; i
< bufSize
; i
++) {
106 strcpy(buffer
, messyHeader
);
108 HeaderTokenizer
tokenizer(buffer
);
109 int tokenizeEnd
= tokenizer
.tokenize(0, strlen(messyHeader
));
110 QCOMPARE(tokenizeEnd
, (int)(strlen(messyHeader
) - 1));
112 // If the output of the tokenizer contains all the terms that should be there and
113 // exactly the number of terms that should be there then it's exactly correct.
114 // We are lax wrt trailing whitespace, by the way. It does neither explicitly matter
115 // nor not matter according to the standard. Internal whitespace similarly should not
116 // matter but we have to be exact because the tokenizer does not move strings around,
117 // it only overwrites \r and \n in case of line continuations.
119 typedef QPair
<int, int> intPair
; //foreach is a macro and does not like commas
122 foreach (const QByteArray
&ba
, QByteArray(messyResult
).split('\n')) {
123 QList
<QByteArray
> values
= ba
.split('\t');
124 QByteArray key
= values
.takeFirst();
125 nValues
+= values
.count();
127 QList
<QByteArray
> comparisonValues
;
128 foreach (const intPair
&be
, tokenizer
.value(key
).beginEnd
) {
129 comparisonValues
.append(QByteArray(buffer
+ be
.first
, be
.second
- be
.first
));
132 QCOMPARE(comparisonValues
.count(), values
.count());
133 for (int i
= 0; i
< values
.count(); i
++) {
134 QVERIFY(comparisonValues
[i
].startsWith(values
[i
]));
139 HeaderTokenizer::ConstIterator it
= tokenizer
.constBegin();
140 for (; it
!= tokenizer
.constEnd(); ++it
) {
141 nValues2
+= it
.value().beginEnd
.count();
143 QCOMPARE(nValues2
, nValues
);
145 return; //comment out for parsed header dump to stdout
147 it
= tokenizer
.constBegin();
148 for (; it
!= tokenizer
.constEnd(); ++it
) {
149 if (!it
.value().beginEnd
.isEmpty()) {
150 kDebug() << it
.key() << ":";
152 foreach (const intPair
&be
, it
.value().beginEnd
) {
153 kDebug() << " " << QByteArray(buffer
+ be
.first
, be
.second
- be
.first
);
158 void HeaderTokenizeTest::testRedirectHeader()
160 //Copy the header into a writable buffer
161 for (int i
= 0; i
< bufSize
; i
++) {
164 strcpy(buffer
, redirectHeader
);
166 HeaderTokenizer
tokenizer(buffer
);
167 int tokenizeEnd
= tokenizer
.tokenize(0, strlen(redirectHeader
));
168 QCOMPARE(tokenizeEnd
, (int)strlen(redirectHeader
));
170 typedef QPair
<int, int> intPair
;
173 foreach (const QByteArray
&ba
, QByteArray(redirectResult
).split('\n')) {
174 QList
<QByteArray
> values
= ba
.split('\t');
175 QByteArray key
= values
.takeFirst();
176 nValues
+= values
.count();
178 QList
<QByteArray
> comparisonValues
;
179 foreach (const intPair
&be
, tokenizer
.value(key
).beginEnd
) {
180 comparisonValues
.append(QByteArray(buffer
+ be
.first
, be
.second
- be
.first
));
183 QCOMPARE(comparisonValues
.count(), values
.count());
184 for (int i
= 0; i
< values
.count(); i
++) {
185 QVERIFY(comparisonValues
[i
].startsWith(values
[i
]));
190 HeaderTokenizer::ConstIterator it
= tokenizer
.constBegin();
191 for (; it
!= tokenizer
.constEnd(); ++it
) {
192 nValues2
+= it
.value().beginEnd
.count();
194 QCOMPARE(nValues2
, nValues
);