1/****************************************************************************
2**
3** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
4** Copyright (C) 2016 The Qt Company Ltd.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtNetwork module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include <private/qspdyprotocolhandler_p.h>
42#include <private/qnoncontiguousbytedevice_p.h>
43#include <private/qhttpnetworkconnectionchannel_p.h>
44#include <QtCore/QtEndian>
45
46#if !defined(QT_NO_SSL)
47
48QT_BEGIN_NAMESPACE
49
50static const char spdyDictionary[] = {
51 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, // ....opti
52 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, // ons....h
53 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, // ead....p
54 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, // ost....p
55 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, // ut....de
56 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, // lete....
57 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, // trace...
58 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, // .accept.
59 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, // ...accep
60 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // t-charse
61 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, // t....acc
62 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // ept-enco
63 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, // ding....
64 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, // accept-l
65 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, // anguage.
66 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, // ...accep
67 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, // t-ranges
68 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, // ....age.
69 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, // ...allow
70 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, // ....auth
71 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, // orizatio
72 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, // n....cac
73 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, // he-contr
74 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, // ol....co
75 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, // nnection
76 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, // ....cont
77 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, // ent-base
78 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, // ....cont
79 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // ent-enco
80 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, // ding....
81 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, // content-
82 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, // language
83 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, // ....cont
84 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, // ent-leng
85 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, // th....co
86 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, // ntent-lo
87 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, // cation..
88 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // ..conten
89 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, // t-md5...
90 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, // .content
91 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, // -range..
92 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // ..conten
93 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, // t-type..
94 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, // ..date..
95 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, // ..etag..
96 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, // ..expect
97 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, // ....expi
98 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, // res....f
99 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, // rom....h
100 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, // ost....i
101 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, // f-match.
102 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, // ...if-mo
103 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, // dified-s
104 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, // ince....
105 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, // if-none-
106 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, // match...
107 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, // .if-rang
108 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, // e....if-
109 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, // unmodifi
110 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, // ed-since
111 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, // ....last
112 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, // -modifie
113 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, // d....loc
114 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, // ation...
115 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, // .max-for
116 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, // wards...
117 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, // .pragma.
118 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, // ...proxy
119 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, // -authent
120 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, // icate...
121 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, // .proxy-a
122 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, // uthoriza
123 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, // tion....
124 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, // range...
125 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, // .referer
126 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, // ....retr
127 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, // y-after.
128 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, // ...serve
129 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, // r....te.
130 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, // ...trail
131 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, // er....tr
132 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, // ansfer-e
133 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, // ncoding.
134 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, // ...upgra
135 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, // de....us
136 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, // er-agent
137 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, // ....vary
138 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, // ....via.
139 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, // ...warni
140 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, // ng....ww
141 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, // w-authen
142 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, // ticate..
143 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, // ..method
144 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, // ....get.
145 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, // ...statu
146 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, // s....200
147 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, // .OK....v
148 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, // ersion..
149 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, // ..HTTP.1
150 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, // .1....ur
151 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, // l....pub
152 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, // lic....s
153 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, // et-cooki
154 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, // e....kee
155 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, // p-alive.
156 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, // ...origi
157 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, // n1001012
158 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, // 01202205
159 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, // 20630030
160 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, // 23033043
161 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, // 05306307
162 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, // 40240540
163 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, // 64074084
164 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, // 09410411
165 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, // 41241341
166 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, // 44154164
167 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, // 17502504
168 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, // 505203.N
169 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, // on-Autho
170 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, // ritative
171 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, // .Informa
172 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, // tion204.
173 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, // No.Conte
174 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, // nt301.Mo
175 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, // ved.Perm
176 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, // anently4
177 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, // 00.Bad.R
178 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, // equest40
179 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, // 1.Unauth
180 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, // orized40
181 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, // 3.Forbid
182 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, // den404.N
183 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, // ot.Found
184 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, // 500.Inte
185 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, // rnal.Ser
186 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, // ver.Erro
187 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, // r501.Not
188 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, // .Impleme
189 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, // nted503.
190 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, // Service.
191 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, // Unavaila
192 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, // bleJan.F
193 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, // eb.Mar.A
194 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, // pr.May.J
195 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, // un.Jul.A
196 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, // ug.Sept.
197 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, // Oct.Nov.
198 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, // Dec.00.0
199 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, // 0.00.Mon
200 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, // ..Tue..W
201 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, // ed..Thu.
202 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, // .Fri..Sa
203 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, // t..Sun..
204 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, // GMTchunk
205 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, // ed.text.
206 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, // html.ima
207 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, // ge.png.i
208 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, // mage.jpg
209 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, // .image.g
210 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // if.appli
211 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // cation.x
212 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // ml.appli
213 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // cation.x
214 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, // html.xml
215 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, // .text.pl
216 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, // ain.text
217 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, // .javascr
218 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, // ipt.publ
219 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, // icprivat
220 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, // emax-age
221 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, // .gzip.de
222 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, // flate.sd
223 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // chcharse
224 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, // t.utf-8c
225 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, // harset.i
226 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, // so-8859-
227 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, // 1.utf-..
228 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e // .enq.0.
229};
230
231// uncomment to debug
232//static void printHex(const QByteArray &ba)
233//{
234// QByteArray hex;
235// QByteArray clearText;
236// for (int a = 0; a < ba.count(); ++a) {
237// QByteArray currentHexChar = QByteArray(1, ba.at(a)).toHex().rightJustified(2, ' ');
238// QByteArray currentChar;
239// if (ba.at(a) >= 32 && ba.at(a) < 126) { // if ASCII, print the letter
240// currentChar = QByteArray(1, ba.at(a));
241// } else {
242// currentChar = " ";
243// }
244// clearText.append(currentChar.rightJustified(2, ' '));
245// hex.append(currentHexChar);
246// hex.append(' ');
247// clearText.append(' ');
248// }
249// int chunkSize = 102; // 12 == 4 bytes per line
250// for (int a = 0; a < hex.count(); a += chunkSize) {
251// qDebug() << hex.mid(a, chunkSize);
252// qDebug() << clearText.mid(a, chunkSize);
253// }
254//}
255
256QSpdyProtocolHandler::QSpdyProtocolHandler(QHttpNetworkConnectionChannel *channel)
257 : QObject(nullptr), QAbstractProtocolHandler(channel),
258 m_nextStreamID(-1),
259 m_maxConcurrentStreams(100), // 100 is recommended in the SPDY RFC
260 m_initialWindowSize(0),
261 m_waitingForCompleteStream(false)
262{
263 m_inflateStream.zalloc = Z_NULL;
264 m_inflateStream.zfree = Z_NULL;
265 m_inflateStream.opaque = Z_NULL;
266 int zlibRet = inflateInit(&m_inflateStream);
267 Q_ASSERT(zlibRet == Z_OK);
268
269 m_deflateStream.zalloc = Z_NULL;
270 m_deflateStream.zfree = Z_NULL;
271 m_deflateStream.opaque = Z_NULL;
272
273 // Do actually not compress (i.e. compression level = 0)
274 // when sending the headers because of the CRIME attack
275 zlibRet = deflateInit(&m_deflateStream, /* compression level = */ 0);
276 Q_ASSERT(zlibRet == Z_OK);
277 Q_UNUSED(zlibRet); // silence -Wunused-variable
278}
279
280QSpdyProtocolHandler::~QSpdyProtocolHandler()
281{
282 deflateEnd(strm: &m_deflateStream);
283 deflateEnd(strm: &m_inflateStream);
284}
285
286bool QSpdyProtocolHandler::sendRequest()
287{
288 Q_ASSERT(!m_reply);
289
290 int maxPossibleRequests = m_maxConcurrentStreams - m_inFlightStreams.count();
291 Q_ASSERT(maxPossibleRequests >= 0);
292 if (maxPossibleRequests == 0)
293 return true; // return early if max concurrent requests are exceeded
294
295 m_channel->state = QHttpNetworkConnectionChannel::WritingState;
296
297 int requestsToSend = qMin(a: m_channel->spdyRequestsToSend.size(), b: maxPossibleRequests);
298
299 QMultiMap<int, HttpMessagePair>::iterator it = m_channel->spdyRequestsToSend.begin();
300 // requests will be ordered by priority (see QMultiMap doc)
301 for (int a = 0; a < requestsToSend; ++a) {
302 HttpMessagePair currentPair = *it;
303 QHttpNetworkRequest currentRequest = currentPair.first;
304 QHttpNetworkReply *currentReply = currentPair.second;
305
306 currentReply->setSpdyWasUsed(true);
307 qint32 streamID = generateNextStreamID();
308 m_streamIDs.insert(akey: currentReply, avalue: streamID);
309
310 currentReply->setRequest(currentRequest);
311 currentReply->d_func()->connection = m_connection;
312 currentReply->d_func()->connectionChannel = m_channel;
313 m_inFlightStreams.insert(akey: streamID, avalue: currentPair);
314 connect(sender: currentReply, SIGNAL(destroyed(QObject*)), receiver: this, SLOT(_q_replyDestroyed(QObject*)));
315
316 sendSYN_STREAM(pair: currentPair, streamID, /* associatedToStreamID = */ 0);
317 m_channel->spdyRequestsToSend.erase(it: it++);
318 }
319 m_channel->state = QHttpNetworkConnectionChannel::IdleState;
320 return true;
321}
322
323void QSpdyProtocolHandler::_q_replyDestroyed(QObject* reply)
324{
325 qint32 streamID = m_streamIDs.take(akey: reply);
326 if (m_inFlightStreams.remove(akey: streamID))
327 sendRST_STREAM(streamID, statusCode: RST_STREAM_CANCEL);
328}
329
330void QSpdyProtocolHandler::_q_receiveReply()
331{
332 Q_ASSERT(m_socket);
333
334 // only run when the QHttpNetworkConnection is not currently being destructed, e.g.
335 // this function is called from _q_disconnected which is called because
336 // of ~QHttpNetworkConnectionPrivate
337 if (!qobject_cast<QHttpNetworkConnection*>(object: m_connection)) {
338 return;
339 }
340
341 if (bytesAvailable() < 8)
342 return; // cannot read frame headers, wait for more data
343
344 char frameHeadersRaw[8];
345 if (!readNextChunk(length: 8, sink: frameHeadersRaw))
346 return; // this should not happen, we just checked
347
348 const QByteArray frameHeaders(frameHeadersRaw, 8); // ### try without memcpy
349 if (frameHeadersRaw[0] & 0x80) {
350 handleControlFrame(frameHeaders);
351 } else {
352 handleDataFrame(frameHeaders);
353 }
354
355 // after handling the current frame, check whether there is more data waiting
356 if (m_socket->bytesAvailable() > 0)
357 QMetaObject::invokeMethod(obj: m_channel, member: "_q_receiveReply", type: Qt::QueuedConnection);
358}
359
360void QSpdyProtocolHandler::_q_readyRead()
361{
362 _q_receiveReply();
363}
364
365static qint16 twoBytesToInt(const char *bytes)
366{
367 return qFromBigEndian<qint16>(src: bytes);
368}
369
370static qint32 threeBytesToInt(const char *bytes)
371{
372 return qFromBigEndian<qint32>(src: bytes) >> 8;
373}
374
375static qint32 fourBytesToInt(const char *bytes)
376{
377 return qFromBigEndian<qint32>(src: bytes);
378}
379
380static void appendIntToThreeBytes(char *output, qint32 number)
381{
382 qToBigEndian<qint16>(src: number, dest: output + 1);
383 qToBigEndian<qint8>(src: number >> 16, dest: output);
384}
385
386static void appendIntToFourBytes(char *output, qint32 number)
387{
388 qToBigEndian<qint32>(src: number, dest: output);
389}
390
391static QByteArray intToFourBytes(qint32 number) // ### try to use appendIntToFourBytes where possible
392{
393 char data[4];
394 qToBigEndian<qint32>(src: number, dest: data);
395 QByteArray ret(data, 4);
396 return ret;
397}
398
399static QByteArray intToThreeBytes(qint32 number)
400{
401 char data[4];
402 qToBigEndian<qint32>(src: number << 8, dest: data);
403 QByteArray ret(data, 3);
404 return ret;
405}
406
407static qint32 getStreamID(const char *bytes)
408{
409 // eliminate most significant bit; it might be 0 or 1 depending on whether
410 // we are dealing with a control or data frame
411 return fourBytesToInt(bytes) & 0x3fffffff;
412}
413
414static QByteArray headerField(const QByteArray &name, const QByteArray &value)
415{
416 QByteArray ret;
417 ret.reserve(asize: name.count() + value.count() + 8); // 4 byte for length each
418 ret.append(a: intToFourBytes(number: name.count()));
419 ret.append(a: name);
420 ret.append(a: intToFourBytes(number: value.count()));
421 ret.append(a: value);
422 return ret;
423}
424
425bool QSpdyProtocolHandler::uncompressHeader(const QByteArray &input, QByteArray *output)
426{
427 const size_t chunkSize = 1024;
428 char outputRaw[chunkSize];
429 // input bytes will not be changed by zlib, so it is safe to const_cast here
430 m_inflateStream.next_in = const_cast<Bytef *>(reinterpret_cast<const Bytef *>(input.constData()));
431 m_inflateStream.avail_in = input.count();
432 m_inflateStream.total_in = input.count();
433 int zlibRet;
434
435 do {
436 m_inflateStream.next_out = reinterpret_cast<Bytef *>(outputRaw);
437 m_inflateStream.avail_out = chunkSize;
438 zlibRet = inflate(strm: &m_inflateStream, Z_SYNC_FLUSH);
439 if (zlibRet == Z_NEED_DICT) {
440 zlibRet = inflateSetDictionary(strm: &m_inflateStream,
441 dictionary: reinterpret_cast<const Bytef*>(spdyDictionary),
442 /* dictionaryLength = */ dictLength: 1423);
443 Q_ASSERT(zlibRet == Z_OK);
444 continue;
445 }
446 switch (zlibRet) {
447 case Z_BUF_ERROR: {
448 if (m_inflateStream.avail_in == 0) {
449 int outputSize = chunkSize - m_inflateStream.avail_out;
450 output->append(s: outputRaw, len: outputSize);
451 m_inflateStream.avail_out = chunkSize;
452 }
453 break;
454 }
455 case Z_OK: {
456 int outputSize = chunkSize - m_inflateStream.avail_out;
457 output->append(s: outputRaw, len: outputSize);
458 break;
459 }
460 default: {
461 qWarning(msg: "got unexpected zlib return value: %d", zlibRet);
462 return false;
463 }
464 }
465 } while (m_inflateStream.avail_in > 0 && zlibRet != Z_STREAM_END);
466
467 Q_ASSERT(m_inflateStream.avail_in == 0);
468 return true;
469}
470
471QByteArray QSpdyProtocolHandler::composeHeader(const QHttpNetworkRequest &request)
472{
473 QByteArray uncompressedHeader;
474 uncompressedHeader.reserve(asize: 300); // rough estimate
475
476 // calculate additional headers first, because we need to know the size
477 // ### do not partially copy the list, but restrict the set header fields
478 // in QHttpNetworkConnection
479 QVector<QPair<QByteArray, QByteArray> > additionalHeaders;
480 for (int a = 0; a < request.header().count(); ++a) {
481 QByteArray key = request.header().at(i: a).first;
482 if (key == "Connection" || key == "Host" || key == "Keep-Alive"
483 || key == "Proxy-Connection" || key == "Transfer-Encoding")
484 continue; // those headers are not valid (section 3.2.1)
485 additionalHeaders.append(t: request.header().at(i: a));
486 }
487
488 qint32 numberOfHeaderPairs = 5 + additionalHeaders.count(); // 5 mandatory below + the additional ones
489 uncompressedHeader.append(a: intToFourBytes(number: numberOfHeaderPairs));
490
491 // mandatory header fields:
492
493 uncompressedHeader.append(a: headerField(name: ":method", value: request.methodName()));
494#ifndef QT_NO_NETWORKPROXY
495 bool useProxy = m_connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy;
496 uncompressedHeader.append(a: headerField(name: ":path", value: request.uri(throughProxy: useProxy)));
497#else
498 uncompressedHeader.append(headerField(":path", request.uri(false)));
499#endif
500 uncompressedHeader.append(a: headerField(name: ":version", value: "HTTP/1.1"));
501
502 uncompressedHeader.append(a: headerField(name: ":host", value: request.url().authority(options: QUrl::FullyEncoded | QUrl::RemoveUserInfo).toLatin1()));
503
504 uncompressedHeader.append(a: headerField(name: ":scheme", value: request.url().scheme().toLatin1()));
505
506 // end of mandatory header fields
507
508 // now add the additional headers
509 for (int a = 0; a < additionalHeaders.count(); ++a) {
510 uncompressedHeader.append(a: headerField(name: additionalHeaders.at(i: a).first.toLower(),
511 value: additionalHeaders.at(i: a).second));
512 }
513
514 m_deflateStream.total_in = uncompressedHeader.count();
515 m_deflateStream.avail_in = uncompressedHeader.count();
516 m_deflateStream.next_in = reinterpret_cast<unsigned char *>(uncompressedHeader.data());
517 int outputBytes = uncompressedHeader.count() + 30; // 30 bytes of compression header overhead
518 m_deflateStream.avail_out = outputBytes;
519 unsigned char *out = new unsigned char[outputBytes];
520 m_deflateStream.next_out = out;
521 int availOutBefore = m_deflateStream.avail_out;
522 int zlibRet = deflate(strm: &m_deflateStream, Z_SYNC_FLUSH); // do everything in one go since we use no compression
523 int compressedHeaderSize = availOutBefore - m_deflateStream.avail_out;
524 Q_ASSERT(zlibRet == Z_OK); // otherwise, we need to allocate more outputBytes
525 Q_UNUSED(zlibRet); // silence -Wunused-variable
526 Q_ASSERT(m_deflateStream.avail_in == 0);
527 QByteArray compressedHeader(reinterpret_cast<char *>(out), compressedHeaderSize);
528 delete[] out;
529
530 return compressedHeader;
531}
532
533quint64 QSpdyProtocolHandler::bytesAvailable() const
534{
535 Q_ASSERT(m_socket);
536 return m_spdyBuffer.byteAmount() + m_socket->bytesAvailable();
537}
538
539bool QSpdyProtocolHandler::readNextChunk(qint64 length, char *sink)
540{
541 qint64 expectedReadBytes = length;
542 qint64 requiredBytesFromBuffer = 0;
543
544 if (m_waitingForCompleteStream) {
545 requiredBytesFromBuffer = qMin(a: length, b: m_spdyBuffer.byteAmount());
546 // ### if next chunk from buffer bigger than what we want to read,
547 // we have to call read() (which memcpy's). Otherwise, we can just
548 // read the next chunk without memcpy'ing.
549 qint64 bytesReadFromBuffer = m_spdyBuffer.read(dst: sink, amount: requiredBytesFromBuffer);
550 Q_ASSERT(bytesReadFromBuffer == requiredBytesFromBuffer);
551 if (length <= bytesReadFromBuffer) {
552 return true; // buffer > required size -> no need to read from socket
553 }
554 expectedReadBytes -= requiredBytesFromBuffer;
555 }
556 qint64 readBytes = m_socket->read(data: sink + requiredBytesFromBuffer, maxlen: expectedReadBytes);
557
558 if (readBytes < expectedReadBytes) {
559 m_waitingForCompleteStream = true;
560 // ### this is inefficient, we should not put back so much data into the buffer
561 QByteArray temp(sink, requiredBytesFromBuffer + readBytes);
562 m_spdyBuffer.append(bd: temp);
563 return false;
564 } else {
565 return true; // buffer must be cleared by calling function
566 }
567}
568
569void QSpdyProtocolHandler::sendControlFrame(FrameType type,
570 ControlFrameFlags flags,
571 const char *data,
572 quint32 length)
573{
574 // frame type and stream ID
575 char header[8];
576 header[0] = 0x80u; // leftmost bit == 1 -> is a control frame
577 header[1] = 0x03; // 3 bit == version 3
578 header[2] = 0;
579 switch (type) {
580 case FrameType_CREDENTIAL: {
581 qWarning(msg: "sending SPDY CREDENTIAL frame is not yet implemented"); // QTBUG-36188
582 return;
583 }
584 default:
585 header[3] = type;
586 }
587
588 // flags
589 header[4] = 0;
590 if (flags & ControlFrame_FLAG_FIN || length == 0) {
591 Q_ASSERT(type == FrameType_SYN_STREAM || type == FrameType_SYN_REPLY
592 || type == FrameType_HEADERS || length == 0);
593 header[4] |= ControlFrame_FLAG_FIN;
594 }
595 if (flags & ControlFrame_FLAG_UNIDIRECTIONAL) {
596 Q_ASSERT(type == FrameType_SYN_STREAM);
597 header[4] |= ControlFrame_FLAG_UNIDIRECTIONAL;
598 }
599
600 // length
601 appendIntToThreeBytes(output: header + 5, number: length);
602
603 qint64 written = m_socket->write(data: header, len: 8);
604 Q_ASSERT(written == 8);
605 written = m_socket->write(data, len: length);
606 Q_ASSERT(written == length);
607 Q_UNUSED(written); // silence -Wunused-variable
608}
609
610void QSpdyProtocolHandler::sendSYN_STREAM(const HttpMessagePair &messagePair,
611 qint32 streamID, qint32 associatedToStreamID)
612{
613 QHttpNetworkRequest request = messagePair.first;
614 QHttpNetworkReply *reply = messagePair.second;
615
616 ControlFrameFlags flags;
617
618 if (!request.uploadByteDevice()) {
619 // no upload -> this is the last frame, send the FIN flag
620 flags |= ControlFrame_FLAG_FIN;
621 reply->d_func()->state = QHttpNetworkReplyPrivate::SPDYHalfClosed;
622 } else {
623 reply->d_func()->state = QHttpNetworkReplyPrivate::SPDYUploading;
624
625 // hack: set the stream ID on the device directly, so when we get
626 // the signal for uploading we know which stream we are sending on
627 m_streamIDs.insert(akey: request.uploadByteDevice(), avalue: streamID);
628
629 QObject::connect(sender: request.uploadByteDevice(), SIGNAL(readyRead()), receiver: this,
630 SLOT(_q_uploadDataReadyRead()), Qt::QueuedConnection);
631 QObject::connect(sender: request.uploadByteDevice(), SIGNAL(destroyed(QObject*)), receiver: this,
632 SLOT(_q_uploadDataDestroyed(QObject *)));
633 }
634
635 QByteArray namesAndValues = composeHeader(request);
636 quint32 length = namesAndValues.count() + 10; // 10 == 4 for Stream-ID + 4 for Associated-To-Stream-ID
637 // + 2 for Priority, Unused and Slot
638
639 QByteArray wireData;
640 wireData.reserve(asize: length);
641 wireData.append(a: intToFourBytes(number: streamID));
642 wireData.append(a: intToFourBytes(number: associatedToStreamID));
643
644 // priority (3 bits) / unused (5 bits) / slot (8 bits)
645 char prioAndSlot[2];
646 switch (request.priority()) {
647 case QHttpNetworkRequest::HighPriority:
648 prioAndSlot[0] = 0x00; // == prio 0 (highest)
649 break;
650 case QHttpNetworkRequest::NormalPriority:
651 prioAndSlot[0] = 0x80u; // == prio 4
652 break;
653 case QHttpNetworkRequest::LowPriority:
654 prioAndSlot[0] = 0xe0u; // == prio 7 (lowest)
655 break;
656 }
657 prioAndSlot[1] = 0x00; // slot in client certificates (not supported currently)
658 wireData.append(s: prioAndSlot, len: 2);
659
660 wireData.append(a: namesAndValues);
661
662 sendControlFrame(type: FrameType_SYN_STREAM, flags, data: wireData.constData(), length);
663
664 if (reply->d_func()->state == QHttpNetworkReplyPrivate::SPDYUploading)
665 uploadData(streamID);
666}
667
668void QSpdyProtocolHandler::_q_uploadDataDestroyed(QObject *uploadData)
669{
670 m_streamIDs.remove(akey: uploadData);
671}
672
673void QSpdyProtocolHandler::sendRST_STREAM(qint32 streamID, RST_STREAM_STATUS_CODE statusCode)
674{
675 char wireData[8];
676 appendIntToFourBytes(output: wireData, number: streamID);
677 appendIntToFourBytes(output: wireData + 4, number: statusCode);
678 sendControlFrame(type: FrameType_RST_STREAM, /* flags = */ { }, data: wireData, /* length = */ 8);
679}
680
681void QSpdyProtocolHandler::sendPING(quint32 pingID)
682{
683 char rawData[4];
684 appendIntToFourBytes(output: rawData, number: pingID);
685 sendControlFrame(type: FrameType_PING, /* flags = */ { }, data: rawData, /* length = */ 4);
686}
687
688bool QSpdyProtocolHandler::uploadData(qint32 streamID)
689{
690 // we only rely on SPDY flow control here and don't care about TCP buffers
691 if (!m_inFlightStreams.contains(akey: streamID)) {
692 sendRST_STREAM(streamID, statusCode: RST_STREAM_INVALID_STREAM);
693 return false;
694 }
695
696 HttpMessagePair messagePair = m_inFlightStreams.value(akey: streamID);
697 QHttpNetworkRequest request = messagePair.first;
698 QHttpNetworkReply *reply = messagePair.second;
699 Q_ASSERT(reply);
700 QHttpNetworkReplyPrivate *replyPrivate = reply->d_func();
701 Q_ASSERT(replyPrivate);
702
703 if (reply->d_func()->state == QHttpNetworkReplyPrivate::SPDYHalfClosed || reply->d_func()->state == QHttpNetworkReplyPrivate::SPDYClosed) {
704 qWarning(msg: "Trying to upload to closed stream");
705 return false;
706 }
707
708 qint32 dataLeftInWindow = replyPrivate->windowSizeUpload
709 - replyPrivate->currentlyUploadedDataInWindow;
710
711 while (dataLeftInWindow > 0 && !request.uploadByteDevice()->atEnd()) {
712
713 // get pointer to upload data
714 qint64 currentReadSize = 0;
715 const char *readPointer = request.uploadByteDevice()->readPointer(maximumLength: dataLeftInWindow,
716 len&: currentReadSize);
717
718 if (currentReadSize == -1) {
719 // premature eof happened
720 m_connection->d_func()->emitReplyError(socket: m_socket, reply,
721 errorCode: QNetworkReply::UnknownNetworkError);
722 return false;
723 } else if (readPointer == nullptr || currentReadSize == 0) {
724 // nothing to read currently, break the loop
725 break;
726 } else {
727 DataFrameFlags flags;
728 // we will send the FIN flag later if appropriate
729 qint64 currentWriteSize = sendDataFrame(streamID, flags, length: currentReadSize, data: readPointer);
730 if (currentWriteSize == -1 || currentWriteSize != currentReadSize) {
731 // socket broke down
732 m_connection->d_func()->emitReplyError(socket: m_socket, reply,
733 errorCode: QNetworkReply::UnknownNetworkError);
734 return false;
735 } else {
736 replyPrivate->currentlyUploadedDataInWindow += currentWriteSize;
737 replyPrivate->totallyUploadedData += currentWriteSize;
738 dataLeftInWindow = replyPrivate->windowSizeUpload
739 - replyPrivate->currentlyUploadedDataInWindow;
740 request.uploadByteDevice()->advanceReadPointer(amount: currentWriteSize);
741
742 emit reply->dataSendProgress(done: replyPrivate->totallyUploadedData,
743 total: request.contentLength());
744 }
745 }
746 }
747 if (replyPrivate->totallyUploadedData == request.contentLength()) {
748 DataFrameFlags finFlag = DataFrame_FLAG_FIN;
749 qint64 writeSize = sendDataFrame(streamID, flags: finFlag, length: 0, data: nullptr);
750 Q_ASSERT(writeSize == 0);
751 Q_UNUSED(writeSize); // silence -Wunused-variable
752 replyPrivate->state = QHttpNetworkReplyPrivate::SPDYHalfClosed;
753 if (reply->request().uploadByteDevice())
754 reply->request().uploadByteDevice()->disconnect(receiver: this);
755 // ### this will not work if the content length is not known, but
756 // then again many servers will fail in this case anyhow according
757 // to the SPDY RFC
758 }
759 return true;
760}
761
762void QSpdyProtocolHandler::_q_uploadDataReadyRead()
763{
764 QNonContiguousByteDevice *device = qobject_cast<QNonContiguousByteDevice *>(object: sender());
765 if (!device)
766 return;
767 qint32 streamID = m_streamIDs.value(akey: device);
768 Q_ASSERT(streamID > 0);
769 uploadData(streamID);
770}
771
772void QSpdyProtocolHandler::sendWINDOW_UPDATE(qint32 streamID, quint32 deltaWindowSize)
773{
774 char windowUpdateData[8];
775 appendIntToFourBytes(output: windowUpdateData, number: streamID);
776 appendIntToFourBytes(output: windowUpdateData + 4, number: deltaWindowSize);
777
778 sendControlFrame(type: FrameType_WINDOW_UPDATE, /* flags = */ { }, data: windowUpdateData, /* length = */ 8);
779}
780
781qint64 QSpdyProtocolHandler::sendDataFrame(qint32 streamID, DataFrameFlags flags,
782 quint32 length, const char *data)
783{
784 QByteArray wireData;
785 wireData.reserve(asize: 8);
786
787 wireData.append(a: intToFourBytes(number: streamID));
788 wireData.append(c: flags);
789 wireData.append(a: intToThreeBytes(number: length));
790
791 Q_ASSERT(m_socket);
792 m_socket->write(data: wireData);
793
794 if (data) {
795 qint64 ret = m_socket->write(data, len: length);
796 return ret;
797 } else {
798 return 0; // nothing to write, e.g. FIN flag
799 }
800}
801
802void QSpdyProtocolHandler::handleControlFrame(const QByteArray &frameHeaders) // ### make it char *
803{
804 Q_ASSERT(frameHeaders.count() >= 8);
805 qint16 version = twoBytesToInt(bytes: frameHeaders.constData());
806 version &= 0x3fff; // eliminate most significant bit to determine version
807 Q_ASSERT(version == 3);
808
809 qint16 type = twoBytesToInt(bytes: frameHeaders.constData() + 2);
810
811 char flags = frameHeaders.at(i: 4);
812 qint32 length = threeBytesToInt(bytes: frameHeaders.constData() + 5);
813 Q_ASSERT(length > 0);
814
815 QByteArray frameData;
816 frameData.resize(size: length);
817 if (!readNextChunk(length, sink: frameData.data())) {
818 // put back the frame headers to the buffer
819 m_spdyBuffer.prepend(bd: frameHeaders);
820 return; // we couldn't read the whole frame and need to wait
821 } else {
822 m_spdyBuffer.clear();
823 m_waitingForCompleteStream = false;
824 }
825
826 switch (type) {
827 case FrameType_SYN_STREAM: {
828 handleSYN_STREAM(flags, length, frameData);
829 break;
830 }
831 case FrameType_SYN_REPLY: {
832 handleSYN_REPLY(flags, length, frameData);
833 break;
834 }
835 case FrameType_RST_STREAM: {
836 handleRST_STREAM(flags, length, frameData);
837 break;
838 }
839 case FrameType_SETTINGS: {
840 handleSETTINGS(flags, length, frameData);
841 break;
842 }
843 case FrameType_PING: {
844 handlePING(flags, length, frameData);
845 break;
846 }
847 case FrameType_GOAWAY: {
848 handleGOAWAY(flags, length, frameData);
849 break;
850 }
851 case FrameType_HEADERS: {
852 handleHEADERS(flags, length, frameData);
853 break;
854 }
855 case FrameType_WINDOW_UPDATE: {
856 handleWINDOW_UPDATE(flags, length, frameData);
857 break;
858 }
859 default:
860 qWarning(msg: "cannot handle frame of type %d", int(type));
861 }
862}
863
864void QSpdyProtocolHandler::handleSYN_STREAM(char /*flags*/, quint32 /*length*/,
865 const QByteArray &frameData)
866{
867 // not implemented; will be implemented when servers start using it
868 // we just tell the server that we do not accept that
869
870 qint32 streamID = getStreamID(bytes: frameData.constData());
871
872 sendRST_STREAM(streamID, statusCode: RST_STREAM_REFUSED_STREAM);
873}
874
875void QSpdyProtocolHandler::handleSYN_REPLY(char flags, quint32 /*length*/, const QByteArray &frameData)
876{
877 parseHttpHeaders(flags, frameData);
878}
879
880void QSpdyProtocolHandler::parseHttpHeaders(char flags, const QByteArray &frameData)
881{
882 qint32 streamID = getStreamID(bytes: frameData.constData());
883 const auto it = m_inFlightStreams.constFind(akey: streamID);
884 if (it == m_inFlightStreams.cend()) {
885 sendRST_STREAM(streamID, statusCode: RST_STREAM_INVALID_STREAM);
886 return;
887 }
888
889 flags &= 0x3f;
890 bool flag_fin = flags & 0x01;
891
892 QByteArray headerValuePairs = frameData.mid(index: 4);
893
894 HttpMessagePair pair = it.value();
895 QHttpNetworkReply *httpReply = pair.second;
896 Q_ASSERT(httpReply != nullptr);
897
898 if (httpReply->d_func()->state == QHttpNetworkReplyPrivate::SPDYClosed) {
899 sendRST_STREAM(streamID, statusCode: RST_STREAM_STREAM_ALREADY_CLOSED);
900 return;
901 }
902
903 QByteArray uncompressedHeader;
904 if (!uncompressHeader(input: headerValuePairs, output: &uncompressedHeader)) {
905 qWarning(msg: "error reading header from SYN_REPLY message");
906 return;
907 }
908
909 qint32 headerCount = fourBytesToInt(bytes: uncompressedHeader.constData());
910 if (headerCount * 8 > uncompressedHeader.size()) {
911 qWarning(msg: "error parsing header from SYN_REPLY message");
912 sendRST_STREAM(streamID, statusCode: RST_STREAM_PROTOCOL_ERROR);
913 return;
914 }
915 qint32 readPointer = 4;
916 for (qint32 a = 0; a < headerCount; ++a) {
917 qint32 count = fourBytesToInt(bytes: uncompressedHeader.constData() + readPointer);
918 readPointer += 4;
919 QByteArray name = uncompressedHeader.mid(index: readPointer, len: count);
920 readPointer += count;
921 if (readPointer > uncompressedHeader.size()) {
922 qWarning(msg: "error parsing header from SYN_REPLY message");
923 sendRST_STREAM(streamID, statusCode: RST_STREAM_PROTOCOL_ERROR);
924 return;
925 }
926 count = fourBytesToInt(bytes: uncompressedHeader.constData() + readPointer);
927 readPointer += 4;
928 QByteArray value = uncompressedHeader.mid(index: readPointer, len: count);
929 readPointer += count;
930 if (readPointer > uncompressedHeader.size()) {
931 qWarning(msg: "error parsing header from SYN_REPLY message");
932 sendRST_STREAM(streamID, statusCode: RST_STREAM_PROTOCOL_ERROR);
933 return;
934 }
935 if (name == ":status") {
936 httpReply->setStatusCode(value.left(len: 3).toInt());
937 httpReply->d_func()->reasonPhrase = QString::fromLatin1(str: value.mid(index: 4));
938 } else if (name == ":version") {
939 int majorVersion = value.at(i: 5) - 48;
940 int minorVersion = value.at(i: 7) - 48;
941 httpReply->d_func()->majorVersion = majorVersion;
942 httpReply->d_func()->minorVersion = minorVersion;
943 } else if (name == "content-length") {
944 httpReply->setContentLength(value.toLongLong());
945 } else {
946 value.replace(before: '\0', c: name == "set-cookie" ? "\n" : ", ");
947 httpReply->setHeaderField(name, data: value);
948 }
949 }
950 emit httpReply->headerChanged();
951
952 if (flag_fin) {
953 if (httpReply->d_func()->state != QHttpNetworkReplyPrivate::SPDYHalfClosed)
954 sendDataFrame(streamID, flags: DataFrame_FLAG_FIN, length: 0, data: nullptr);
955 replyFinished(httpReply, streamID);
956 }
957}
958
959void QSpdyProtocolHandler::handleRST_STREAM(char /*flags*/, quint32 length,
960 const QByteArray &frameData)
961{
962 // flags are ignored
963
964 Q_ASSERT(length == 8);
965 Q_UNUSED(length); // silence -Wunused-parameter
966 qint32 streamID = getStreamID(bytes: frameData.constData());
967 QHttpNetworkReply *httpReply = m_inFlightStreams.value(akey: streamID).second;
968
969 qint32 statusCodeInt = fourBytesToInt(bytes: frameData.constData() + 4);
970 RST_STREAM_STATUS_CODE statusCode = static_cast<RST_STREAM_STATUS_CODE>(statusCodeInt);
971 QNetworkReply::NetworkError errorCode;
972 QByteArray errorMessage;
973
974 switch (statusCode) {
975 case RST_STREAM_PROTOCOL_ERROR:
976 errorCode = QNetworkReply::ProtocolFailure;
977 errorMessage = "SPDY protocol error";
978 break;
979 case RST_STREAM_INVALID_STREAM:
980 errorCode = QNetworkReply::ProtocolFailure;
981 errorMessage = "SPDY stream is not active";
982 break;
983 case RST_STREAM_REFUSED_STREAM:
984 errorCode = QNetworkReply::ProtocolFailure;
985 errorMessage = "SPDY stream was refused";
986 break;
987 case RST_STREAM_UNSUPPORTED_VERSION:
988 errorCode = QNetworkReply::ProtocolUnknownError;
989 errorMessage = "SPDY version is unknown to the server";
990 break;
991 case RST_STREAM_CANCEL:
992 errorCode = QNetworkReply::ProtocolFailure;
993 errorMessage = "SPDY stream is no longer needed";
994 break;
995 case RST_STREAM_INTERNAL_ERROR:
996 errorCode = QNetworkReply::InternalServerError;
997 errorMessage = "Internal server error";
998 break;
999 case RST_STREAM_FLOW_CONTROL_ERROR:
1000 errorCode = QNetworkReply::ProtocolFailure;
1001 errorMessage = "peer violated the flow control protocol";
1002 break;
1003 case RST_STREAM_STREAM_IN_USE:
1004 errorCode = QNetworkReply::ProtocolFailure;
1005 errorMessage = "server received a SYN_REPLY for an already open stream";
1006 break;
1007 case RST_STREAM_STREAM_ALREADY_CLOSED:
1008 errorCode = QNetworkReply::ProtocolFailure;
1009 errorMessage = "server received data or a SYN_REPLY for an already half-closed stream";
1010 break;
1011 case RST_STREAM_INVALID_CREDENTIALS:
1012 errorCode = QNetworkReply::ContentAccessDenied;
1013 errorMessage = "server received invalid credentials";
1014 break;
1015 case RST_STREAM_FRAME_TOO_LARGE:
1016 errorCode = QNetworkReply::ProtocolFailure;
1017 errorMessage = "server cannot process the frame because it is too large";
1018 break;
1019 default:
1020 qWarning(msg: "could not understand servers RST_STREAM status code");
1021 errorCode = QNetworkReply::ProtocolFailure;
1022 errorMessage = "got SPDY RST_STREAM message with unknown error code";
1023 }
1024 if (httpReply)
1025 replyFinishedWithError(httpReply, streamID, errorCode, errorMessage: errorMessage.constData());
1026}
1027
1028void QSpdyProtocolHandler::handleSETTINGS(char flags, quint32 /*length*/, const QByteArray &frameData)
1029{
1030 Q_ASSERT(frameData.count() > 0);
1031
1032 SETTINGS_Flags settingsFlags = static_cast<SETTINGS_Flags>(flags);
1033 if (settingsFlags & FLAG_SETTINGS_CLEAR_SETTINGS) {
1034 // ### clear all persistent settings; since we do not persist settings
1035 // as of now, we don't need to clear anything either
1036 }
1037
1038 qint32 numberOfEntries = fourBytesToInt(bytes: frameData.constData());
1039 Q_ASSERT(numberOfEntries > 0);
1040 for (int a = 0, frameDataIndex = 4; a < numberOfEntries; ++a, frameDataIndex += 8) {
1041 SETTINGS_ID_Flag idFlag = static_cast<SETTINGS_ID_Flag>(frameData[frameDataIndex]);
1042 if (idFlag & FLAG_SETTINGS_PERSIST_VALUE) {
1043 // ### we SHOULD persist the settings here according to the RFC, but we don't have to,
1044 // so implement that later
1045 } // the other value is only sent by us, but not received
1046
1047 quint32 uniqueID = static_cast<SETTINGS_ID>(
1048 threeBytesToInt(bytes: frameData.constData() + frameDataIndex + 1));
1049 quint32 value = fourBytesToInt(bytes: frameData.constData() + frameDataIndex + 4);
1050 switch (uniqueID) {
1051 case SETTINGS_UPLOAD_BANDWIDTH: {
1052 // ignored for now, just an estimated informative value
1053 break;
1054 }
1055 case SETTINGS_DOWNLOAD_BANDWIDTH: {
1056 // ignored for now, just an estimated informative value
1057 break;
1058 }
1059 case SETTINGS_ROUND_TRIP_TIME: {
1060 // ignored for now, just an estimated informative value
1061 break;
1062 }
1063 case SETTINGS_MAX_CONCURRENT_STREAMS: {
1064 m_maxConcurrentStreams = value;
1065 break;
1066 }
1067 case SETTINGS_CURRENT_CWND: {
1068 // ignored for now, just an informative value
1069 break;
1070 }
1071 case SETTINGS_DOWNLOAD_RETRANS_RATE: {
1072 // ignored for now, just an estimated informative value
1073 break;
1074 }
1075 case SETTINGS_INITIAL_WINDOW_SIZE: {
1076 m_initialWindowSize = value;
1077 break;
1078 }
1079 case SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE: {
1080 // client certificates are not supported
1081 break;
1082 }
1083 default:
1084 qWarning(msg: "found unknown settings value %u", uint(value));
1085 }
1086 }
1087}
1088
1089void QSpdyProtocolHandler::handlePING(char /*flags*/, quint32 length, const QByteArray &frameData)
1090{
1091 // flags are ignored
1092
1093 Q_ASSERT(length == 4);
1094 Q_UNUSED(length); // silence -Wunused-parameter
1095 quint32 pingID = fourBytesToInt(bytes: frameData.constData());
1096
1097 // odd numbered IDs must be ignored
1098 if ((pingID & 1) == 0) // is even?
1099 sendPING(pingID);
1100}
1101
1102void QSpdyProtocolHandler::handleGOAWAY(char /*flags*/, quint32 /*length*/,
1103 const QByteArray &frameData)
1104{
1105 // flags are ignored
1106
1107 qint32 statusCode = static_cast<GOAWAY_STATUS>(fourBytesToInt(bytes: frameData.constData() + 4));
1108 QNetworkReply::NetworkError errorCode;
1109 switch (statusCode) {
1110 case GOAWAY_OK: {
1111 errorCode = QNetworkReply::NoError;
1112 break;
1113 }
1114 case GOAWAY_PROTOCOL_ERROR: {
1115 errorCode = QNetworkReply::ProtocolFailure;
1116 break;
1117 }
1118 case GOAWAY_INTERNAL_ERROR: {
1119 errorCode = QNetworkReply::InternalServerError;
1120 break;
1121 }
1122 default:
1123 qWarning(msg: "unexpected status code %d", int(statusCode));
1124 errorCode = QNetworkReply::ProtocolUnknownError;
1125 }
1126
1127 qint32 lastGoodStreamID = getStreamID(bytes: frameData.constData());
1128
1129 // emit errors for all replies after the last good stream ID
1130 Q_ASSERT(m_connection);
1131 for (qint32 currentStreamID = lastGoodStreamID + 2; currentStreamID <= m_nextStreamID;
1132 ++currentStreamID) {
1133 QHttpNetworkReply *reply = m_inFlightStreams.value(akey: currentStreamID).second;
1134 Q_ASSERT(reply);
1135 m_connection->d_func()->emitReplyError(socket: m_socket, reply, errorCode);
1136 }
1137 // ### we could make sure a new session is initiated anyhow
1138}
1139
1140void QSpdyProtocolHandler::handleHEADERS(char flags, quint32 /*length*/,
1141 const QByteArray &frameData)
1142{
1143 parseHttpHeaders(flags, frameData);
1144}
1145
1146void QSpdyProtocolHandler::handleWINDOW_UPDATE(char /*flags*/, quint32 /*length*/,
1147 const QByteArray &frameData)
1148{
1149 qint32 streamID = getStreamID(bytes: frameData.constData());
1150 qint32 deltaWindowSize = fourBytesToInt(bytes: frameData.constData() + 4);
1151
1152 const auto it = m_inFlightStreams.constFind(akey: streamID);
1153 if (it == m_inFlightStreams.cend()) {
1154 sendRST_STREAM(streamID, statusCode: RST_STREAM_INVALID_STREAM);
1155 return;
1156 }
1157
1158 QHttpNetworkReply *reply = it.value().second;
1159 Q_ASSERT(reply);
1160 QHttpNetworkReplyPrivate *replyPrivate = reply->d_func();
1161 Q_ASSERT(replyPrivate);
1162
1163 // Ignore WINDOW_UPDATE if we are already done.
1164 if (replyPrivate->state == QHttpNetworkReplyPrivate::SPDYHalfClosed || replyPrivate->state == QHttpNetworkReplyPrivate::SPDYClosed)
1165 return;
1166
1167 replyPrivate->currentlyUploadedDataInWindow = replyPrivate->windowSizeUpload - deltaWindowSize;
1168 uploadData(streamID); // we hopefully can continue to upload
1169}
1170
1171
1172void QSpdyProtocolHandler::handleDataFrame(const QByteArray &frameHeaders)
1173{
1174 Q_ASSERT(frameHeaders.count() >= 8);
1175
1176 qint32 streamID = getStreamID(bytes: frameHeaders.constData());
1177 const auto it = m_inFlightStreams.constFind(akey: streamID);
1178 if (it == m_inFlightStreams.cend()) {
1179 sendRST_STREAM(streamID, statusCode: RST_STREAM_INVALID_STREAM);
1180 return;
1181 }
1182
1183 unsigned char flags = static_cast<unsigned char>(frameHeaders.at(i: 4));
1184 flags &= 0x3f;
1185 bool flag_fin = flags & 0x01;
1186 bool flag_compress = flags & 0x02;
1187 qint32 length = threeBytesToInt(bytes: frameHeaders.constData() + 5);
1188
1189 QByteArray data;
1190 data.resize(size: length);
1191 if (!readNextChunk(length, sink: data.data())) {
1192 // put back the frame headers to the buffer
1193 m_spdyBuffer.prepend(bd: frameHeaders);
1194 return; // we couldn't read the whole frame and need to wait
1195 } else {
1196 m_spdyBuffer.clear();
1197 m_waitingForCompleteStream = false;
1198 }
1199
1200 HttpMessagePair pair = it.value();
1201 QHttpNetworkRequest httpRequest = pair.first;
1202 QHttpNetworkReply *httpReply = pair.second;
1203 Q_ASSERT(httpReply != nullptr);
1204
1205 QHttpNetworkReplyPrivate *replyPrivate = httpReply->d_func();
1206
1207 if (replyPrivate->state == QHttpNetworkReplyPrivate::SPDYClosed) {
1208 sendRST_STREAM(streamID, statusCode: RST_STREAM_STREAM_ALREADY_CLOSED);
1209 return;
1210 }
1211
1212 // check whether we need to send WINDOW_UPDATE (i.e. tell the sender it can send more)
1213 replyPrivate->currentlyReceivedDataInWindow += length;
1214 qint32 dataLeftInWindow = replyPrivate->windowSizeDownload - replyPrivate->currentlyReceivedDataInWindow;
1215
1216 if (replyPrivate->currentlyReceivedDataInWindow > 0
1217 && dataLeftInWindow < replyPrivate->windowSizeDownload / 2) {
1218
1219 // socket read buffer size is 64K actually, hard coded in the channel
1220 // We can read way more than 64K per socket, because the window size
1221 // here is per stream.
1222 if (replyPrivate->windowSizeDownload >= m_socket->readBufferSize()) {
1223 replyPrivate->windowSizeDownload = m_socket->readBufferSize();
1224 } else {
1225 replyPrivate->windowSizeDownload *= 1.5;
1226 }
1227 QMetaObject::invokeMethod(obj: this, member: "sendWINDOW_UPDATE", type: Qt::QueuedConnection,
1228 Q_ARG(qint32, streamID),
1229 Q_ARG(quint32, replyPrivate->windowSizeDownload));
1230 // setting the current data count to 0 is a race condition,
1231 // because we call sendWINDOW_UPDATE through the event loop.
1232 // But then again, the whole situation is a race condition because
1233 // we don't know when the packet will arrive at the server; so
1234 // this is most likely good enough here.
1235 replyPrivate->currentlyReceivedDataInWindow = 0;
1236 }
1237
1238 httpReply->d_func()->compressedData.append(a: data);
1239
1240
1241 replyPrivate->totalProgress += length;
1242
1243 if (httpRequest.d->autoDecompress && httpReply->d_func()->isCompressed()) {
1244 QByteDataBuffer inDataBuffer; // ### should we introduce one in the http reply?
1245 inDataBuffer.append(bd: data);
1246 qint64 compressedCount = httpReply->d_func()->uncompressBodyData(in: &inDataBuffer,
1247 out: &replyPrivate->responseData);
1248 Q_ASSERT(compressedCount >= 0);
1249 Q_UNUSED(compressedCount); // silence -Wunused-variable
1250 } else {
1251 replyPrivate->responseData.append(bd: data);
1252 }
1253
1254 if (replyPrivate->shouldEmitSignals()) {
1255 emit httpReply->readyRead();
1256 emit httpReply->dataReadProgress(done: replyPrivate->totalProgress, total: replyPrivate->bodyLength);
1257 }
1258
1259 if (flag_compress) {
1260 qWarning(msg: "SPDY level compression is not supported");
1261 }
1262
1263 if (flag_fin) {
1264 if (httpReply->d_func()->state != QHttpNetworkReplyPrivate::SPDYHalfClosed)
1265 sendDataFrame(streamID, flags: DataFrame_FLAG_FIN, length: 0, data: nullptr);
1266 replyFinished(httpReply, streamID);
1267 }
1268}
1269
1270void QSpdyProtocolHandler::replyFinished(QHttpNetworkReply *httpReply, qint32 streamID)
1271{
1272 httpReply->d_func()->state = QHttpNetworkReplyPrivate::SPDYClosed;
1273 httpReply->disconnect(receiver: this);
1274 if (httpReply->request().uploadByteDevice())
1275 httpReply->request().uploadByteDevice()->disconnect(receiver: this);
1276 int streamsRemoved = m_inFlightStreams.remove(akey: streamID);
1277 Q_ASSERT(streamsRemoved == 1);
1278 Q_UNUSED(streamsRemoved); // silence -Wunused-variable
1279 emit httpReply->finished();
1280}
1281
1282void QSpdyProtocolHandler::replyFinishedWithError(QHttpNetworkReply *httpReply, qint32 streamID,
1283 QNetworkReply::NetworkError errorCode, const char *errorMessage)
1284{
1285 Q_ASSERT(httpReply);
1286 httpReply->d_func()->state = QHttpNetworkReplyPrivate::SPDYClosed;
1287 httpReply->disconnect(receiver: this);
1288 if (httpReply->request().uploadByteDevice())
1289 httpReply->request().uploadByteDevice()->disconnect(receiver: this);
1290 int streamsRemoved = m_inFlightStreams.remove(akey: streamID);
1291 Q_ASSERT(streamsRemoved == 1);
1292 Q_UNUSED(streamsRemoved); // silence -Wunused-variable
1293 emit httpReply->finishedWithError(errorCode, detail: QSpdyProtocolHandler::tr(s: errorMessage));
1294}
1295
1296qint32 QSpdyProtocolHandler::generateNextStreamID()
1297{
1298 // stream IDs initiated by the client must be odd
1299 m_nextStreamID += 2;
1300 return m_nextStreamID;
1301}
1302
1303QT_END_NAMESPACE
1304
1305#endif // !defined(QT_NO_SSL)
1306

source code of qtbase/src/network/access/qspdyprotocolhandler.cpp