~gabriel1984sibiu/minitube/qt5.6

« back to all changes in this revision

Viewing changes to src/network/access/qspdyprotocolhandler.cpp

  • Committer: Grevutiu Gabriel
  • Date: 2017-06-13 08:43:17 UTC
  • Revision ID: gabriel1984sibiu@gmail.com-20170613084317-ek0zqe0u9g3ocvi8
OriginalĀ upstreamĀ code

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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_HTTP) && !defined(QT_NO_SSL)
 
47
 
 
48
QT_BEGIN_NAMESPACE
 
49
 
 
50
static 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
 
 
256
QSpdyProtocolHandler::QSpdyProtocolHandler(QHttpNetworkConnectionChannel *channel)
 
257
    : QObject(0), 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
 
 
280
QSpdyProtocolHandler::~QSpdyProtocolHandler()
 
281
{
 
282
    deflateEnd(&m_deflateStream);
 
283
    deflateEnd(&m_inflateStream);
 
284
}
 
285
 
 
286
bool 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(m_channel->spdyRequestsToSend.size(), 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
        currentReply->setProperty("SPDYStreamID", streamID);
 
309
 
 
310
        currentReply->setRequest(currentRequest);
 
311
        currentReply->d_func()->connection = m_connection;
 
312
        currentReply->d_func()->connectionChannel = m_channel;
 
313
        m_inFlightStreams.insert(streamID, currentPair);
 
314
        connect(currentReply, SIGNAL(destroyed(QObject*)), this, SLOT(_q_replyDestroyed(QObject*)));
 
315
 
 
316
        sendSYN_STREAM(currentPair, streamID, /* associatedToStreamID = */ 0);
 
317
        m_channel->spdyRequestsToSend.erase(it++);
 
318
    }
 
319
    m_channel->state = QHttpNetworkConnectionChannel::IdleState;
 
320
    return true;
 
321
}
 
322
 
 
323
void QSpdyProtocolHandler::_q_replyDestroyed(QObject* reply)
 
324
{
 
325
    qint32 streamID = reply->property("SPDYStreamID").toInt();
 
326
    if (m_inFlightStreams.remove(streamID))
 
327
        sendRST_STREAM(streamID, RST_STREAM_CANCEL);
 
328
}
 
329
 
 
330
void 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*>(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(8, 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(m_channel, "_q_receiveReply", Qt::QueuedConnection);
 
358
}
 
359
 
 
360
void QSpdyProtocolHandler::_q_readyRead()
 
361
{
 
362
    _q_receiveReply();
 
363
}
 
364
 
 
365
static qint16 twoBytesToInt(const char *bytes)
 
366
{
 
367
    return qFromBigEndian<qint16>(bytes);
 
368
}
 
369
 
 
370
static qint32 threeBytesToInt(const char *bytes)
 
371
{
 
372
    return qFromBigEndian<qint32>(bytes) >> 8;
 
373
}
 
374
 
 
375
static qint32 fourBytesToInt(const char *bytes)
 
376
{
 
377
    return qFromBigEndian<qint32>(bytes);
 
378
}
 
379
 
 
380
static void appendIntToThreeBytes(char *output, qint32 number)
 
381
{
 
382
    qToBigEndian<qint16>(number, output + 1);
 
383
    qToBigEndian<qint8>(number >> 16, output);
 
384
}
 
385
 
 
386
static void appendIntToFourBytes(char *output, qint32 number)
 
387
{
 
388
    qToBigEndian<qint32>(number, output);
 
389
}
 
390
 
 
391
static QByteArray intToFourBytes(qint32 number) // ### try to use appendIntToFourBytes where possible
 
392
{
 
393
    char data[4];
 
394
    qToBigEndian<qint32>(number, data);
 
395
    QByteArray ret(data, 4);
 
396
    return ret;
 
397
}
 
398
 
 
399
static QByteArray intToThreeBytes(qint32 number)
 
400
{
 
401
    char data[4];
 
402
    qToBigEndian<qint32>(number << 8, data);
 
403
    QByteArray ret(data, 3);
 
404
    return ret;
 
405
}
 
406
 
 
407
static 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
 
 
414
static QByteArray headerField(const QByteArray &name, const QByteArray &value)
 
415
{
 
416
    QByteArray ret;
 
417
    ret.reserve(name.count() + value.count() + 8); // 4 byte for length each
 
418
    ret.append(intToFourBytes(name.count()));
 
419
    ret.append(name);
 
420
    ret.append(intToFourBytes(value.count()));
 
421
    ret.append(value);
 
422
    return ret;
 
423
}
 
424
 
 
425
bool 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(&m_inflateStream, Z_SYNC_FLUSH);
 
439
        if (zlibRet == Z_NEED_DICT) {
 
440
            zlibRet = inflateSetDictionary(&m_inflateStream,
 
441
                                           reinterpret_cast<const Bytef*>(spdyDictionary),
 
442
                                           /* dictionaryLength = */ 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(outputRaw, 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(outputRaw, outputSize);
 
458
            break;
 
459
        }
 
460
        default: {
 
461
            qWarning() << "got unexpected zlib return value:" << 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
 
 
471
QByteArray QSpdyProtocolHandler::composeHeader(const QHttpNetworkRequest &request)
 
472
{
 
473
    QByteArray uncompressedHeader;
 
474
    uncompressedHeader.reserve(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(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(request.header().at(a));
 
486
    }
 
487
 
 
488
    qint32 numberOfHeaderPairs = 5 + additionalHeaders.count(); // 5 mandatory below + the additional ones
 
489
    uncompressedHeader.append(intToFourBytes(numberOfHeaderPairs));
 
490
 
 
491
    // mandatory header fields:
 
492
 
 
493
    uncompressedHeader.append(headerField(":method", request.methodName()));
 
494
#ifndef QT_NO_NETWORKPROXY
 
495
    bool useProxy = m_connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy;
 
496
    uncompressedHeader.append(headerField(":path", request.uri(useProxy)));
 
497
#else
 
498
    uncompressedHeader.append(headerField(":path", request.uri(false)));
 
499
#endif
 
500
    uncompressedHeader.append(headerField(":version", "HTTP/1.1"));
 
501
 
 
502
    uncompressedHeader.append(headerField(":host", request.url().authority(QUrl::FullyEncoded | QUrl::RemoveUserInfo).toLatin1()));
 
503
 
 
504
    uncompressedHeader.append(headerField(":scheme", 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(headerField(additionalHeaders.at(a).first.toLower(),
 
511
                                              additionalHeaders.at(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(&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
 
 
533
quint64 QSpdyProtocolHandler::bytesAvailable() const
 
534
{
 
535
    Q_ASSERT(m_socket);
 
536
    return m_spdyBuffer.byteAmount() + m_socket->bytesAvailable();
 
537
}
 
538
 
 
539
bool QSpdyProtocolHandler::readNextChunk(qint64 length, char *sink)
 
540
{
 
541
    qint64 expectedReadBytes = length;
 
542
    qint64 requiredBytesFromBuffer = 0;
 
543
 
 
544
    if (m_waitingForCompleteStream) {
 
545
        requiredBytesFromBuffer = qMin(length, 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(sink, 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(sink + requiredBytesFromBuffer, 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(temp);
 
563
        return false;
 
564
    } else {
 
565
        return true; // buffer must be cleared by calling function
 
566
    }
 
567
}
 
568
 
 
569
void 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("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(header + 5, length);
 
602
 
 
603
    qint64 written = m_socket->write(header, 8);
 
604
    Q_ASSERT(written == 8);
 
605
    written = m_socket->write(data, length);
 
606
    Q_ASSERT(written == length);
 
607
    Q_UNUSED(written); // silence -Wunused-variable
 
608
}
 
609
 
 
610
void 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 = 0;
 
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
        request.uploadByteDevice()->setProperty("SPDYStreamID", streamID);
 
628
 
 
629
        QObject::connect(request.uploadByteDevice(), SIGNAL(readyRead()), this,
 
630
                         SLOT(_q_uploadDataReadyRead()), Qt::QueuedConnection);
 
631
    }
 
632
 
 
633
    QByteArray namesAndValues = composeHeader(request);
 
634
    quint32 length = namesAndValues.count() + 10; // 10 == 4 for Stream-ID + 4 for Associated-To-Stream-ID
 
635
    // + 2 for Priority, Unused and Slot
 
636
 
 
637
    QByteArray wireData;
 
638
    wireData.reserve(length);
 
639
    wireData.append(intToFourBytes(streamID));
 
640
    wireData.append(intToFourBytes(associatedToStreamID));
 
641
 
 
642
    // priority (3 bits) / unused (5 bits) / slot (8 bits)
 
643
    char prioAndSlot[2];
 
644
    switch (request.priority()) {
 
645
    case QHttpNetworkRequest::HighPriority:
 
646
        prioAndSlot[0] = 0x00; // == prio 0 (highest)
 
647
        break;
 
648
    case QHttpNetworkRequest::NormalPriority:
 
649
        prioAndSlot[0] = 0x80u; // == prio 4
 
650
        break;
 
651
    case QHttpNetworkRequest::LowPriority:
 
652
        prioAndSlot[0] = 0xe0u; // == prio 7 (lowest)
 
653
        break;
 
654
    }
 
655
    prioAndSlot[1] = 0x00; // slot in client certificates (not supported currently)
 
656
    wireData.append(prioAndSlot, 2);
 
657
 
 
658
    wireData.append(namesAndValues);
 
659
 
 
660
    sendControlFrame(FrameType_SYN_STREAM, flags, wireData.constData(), length);
 
661
 
 
662
    if (reply->d_func()->state == QHttpNetworkReplyPrivate::SPDYUploading)
 
663
        uploadData(streamID);
 
664
}
 
665
 
 
666
void QSpdyProtocolHandler::sendRST_STREAM(qint32 streamID, RST_STREAM_STATUS_CODE statusCode)
 
667
{
 
668
    char wireData[8];
 
669
    appendIntToFourBytes(wireData, streamID);
 
670
    appendIntToFourBytes(wireData + 4, statusCode);
 
671
    sendControlFrame(FrameType_RST_STREAM, /* flags = */ 0, wireData, /* length = */ 8);
 
672
}
 
673
 
 
674
void QSpdyProtocolHandler::sendPING(quint32 pingID)
 
675
{
 
676
    char rawData[4];
 
677
    appendIntToFourBytes(rawData, pingID);
 
678
    sendControlFrame(FrameType_PING, /* flags = */ 0, rawData, /* length = */ 4);
 
679
}
 
680
 
 
681
bool QSpdyProtocolHandler::uploadData(qint32 streamID)
 
682
{
 
683
    // we only rely on SPDY flow control here and don't care about TCP buffers
 
684
    if (!m_inFlightStreams.contains(streamID)) {
 
685
        sendRST_STREAM(streamID, RST_STREAM_INVALID_STREAM);
 
686
        return false;
 
687
    }
 
688
 
 
689
    HttpMessagePair messagePair = m_inFlightStreams.value(streamID);
 
690
    QHttpNetworkRequest request = messagePair.first;
 
691
    QHttpNetworkReply *reply = messagePair.second;
 
692
    Q_ASSERT(reply);
 
693
    QHttpNetworkReplyPrivate *replyPrivate = reply->d_func();
 
694
    Q_ASSERT(replyPrivate);
 
695
 
 
696
    if (reply->d_func()->state == QHttpNetworkReplyPrivate::SPDYHalfClosed || reply->d_func()->state == QHttpNetworkReplyPrivate::SPDYClosed) {
 
697
        qWarning("Trying to upload to closed stream");
 
698
        return false;
 
699
    }
 
700
 
 
701
    qint32 dataLeftInWindow = replyPrivate->windowSizeUpload
 
702
            - replyPrivate->currentlyUploadedDataInWindow;
 
703
 
 
704
    while (dataLeftInWindow > 0 && !request.uploadByteDevice()->atEnd()) {
 
705
 
 
706
        // get pointer to upload data
 
707
        qint64 currentReadSize = 0;
 
708
        const char *readPointer = request.uploadByteDevice()->readPointer(dataLeftInWindow,
 
709
                                                                          currentReadSize);
 
710
 
 
711
        if (currentReadSize == -1) {
 
712
            // premature eof happened
 
713
            m_connection->d_func()->emitReplyError(m_socket, reply,
 
714
                                                   QNetworkReply::UnknownNetworkError);
 
715
            return false;
 
716
        } else if (readPointer == 0 || currentReadSize == 0) {
 
717
            // nothing to read currently, break the loop
 
718
            break;
 
719
        } else {
 
720
            DataFrameFlags flags = 0;
 
721
            // we will send the FIN flag later if appropriate
 
722
            qint64 currentWriteSize = sendDataFrame(streamID, flags, currentReadSize, readPointer);
 
723
            if (currentWriteSize == -1 || currentWriteSize != currentReadSize) {
 
724
                // socket broke down
 
725
                m_connection->d_func()->emitReplyError(m_socket, reply,
 
726
                                                       QNetworkReply::UnknownNetworkError);
 
727
                return false;
 
728
            } else {
 
729
                replyPrivate->currentlyUploadedDataInWindow += currentWriteSize;
 
730
                replyPrivate->totallyUploadedData += currentWriteSize;
 
731
                dataLeftInWindow = replyPrivate->windowSizeUpload
 
732
                        - replyPrivate->currentlyUploadedDataInWindow;
 
733
                request.uploadByteDevice()->advanceReadPointer(currentWriteSize);
 
734
 
 
735
                emit reply->dataSendProgress(replyPrivate->totallyUploadedData,
 
736
                                             request.contentLength());
 
737
            }
 
738
        }
 
739
    }
 
740
    if (replyPrivate->totallyUploadedData == request.contentLength()) {
 
741
        DataFrameFlags finFlag = DataFrame_FLAG_FIN;
 
742
        qint64 writeSize = sendDataFrame(streamID, finFlag, 0, 0);
 
743
        Q_ASSERT(writeSize == 0);
 
744
        Q_UNUSED(writeSize); // silence -Wunused-variable
 
745
        replyPrivate->state = QHttpNetworkReplyPrivate::SPDYHalfClosed;
 
746
        if (reply->request().uploadByteDevice())
 
747
            reply->request().uploadByteDevice()->disconnect(this);
 
748
        // ### this will not work if the content length is not known, but
 
749
        // then again many servers will fail in this case anyhow according
 
750
        // to the SPDY RFC
 
751
    }
 
752
    return true;
 
753
}
 
754
 
 
755
void QSpdyProtocolHandler::_q_uploadDataReadyRead()
 
756
{
 
757
    QNonContiguousByteDevice *device = qobject_cast<QNonContiguousByteDevice *>(sender());
 
758
    Q_ASSERT(device);
 
759
    qint32 streamID = device->property("SPDYStreamID").toInt();
 
760
    Q_ASSERT(streamID > 0);
 
761
    uploadData(streamID);
 
762
}
 
763
 
 
764
void QSpdyProtocolHandler::sendWINDOW_UPDATE(qint32 streamID, quint32 deltaWindowSize)
 
765
{
 
766
    char windowUpdateData[8];
 
767
    appendIntToFourBytes(windowUpdateData, streamID);
 
768
    appendIntToFourBytes(windowUpdateData + 4, deltaWindowSize);
 
769
 
 
770
    sendControlFrame(FrameType_WINDOW_UPDATE, /* flags = */ 0, windowUpdateData, /* length = */ 8);
 
771
}
 
772
 
 
773
qint64 QSpdyProtocolHandler::sendDataFrame(qint32 streamID, DataFrameFlags flags,
 
774
                                           quint32 length, const char *data)
 
775
{
 
776
    QByteArray wireData;
 
777
    wireData.reserve(8);
 
778
 
 
779
    wireData.append(intToFourBytes(streamID));
 
780
    wireData.append(flags);
 
781
    wireData.append(intToThreeBytes(length));
 
782
 
 
783
    Q_ASSERT(m_socket);
 
784
    m_socket->write(wireData);
 
785
 
 
786
    if (data) {
 
787
        qint64 ret = m_socket->write(data, length);
 
788
        return ret;
 
789
    } else {
 
790
        return 0; // nothing to write, e.g. FIN flag
 
791
    }
 
792
}
 
793
 
 
794
void QSpdyProtocolHandler::handleControlFrame(const QByteArray &frameHeaders) // ### make it char *
 
795
{
 
796
    Q_ASSERT(frameHeaders.count() >= 8);
 
797
    qint16 version = twoBytesToInt(frameHeaders.constData());
 
798
    version &= 0x3fff; // eliminate most significant bit to determine version
 
799
    Q_ASSERT(version == 3);
 
800
 
 
801
    qint16 type = twoBytesToInt(frameHeaders.constData() + 2);
 
802
 
 
803
    char flags = frameHeaders.at(4);
 
804
    qint32 length = threeBytesToInt(frameHeaders.constData() + 5);
 
805
    Q_ASSERT(length > 0);
 
806
 
 
807
    QByteArray frameData;
 
808
    frameData.resize(length);
 
809
    if (!readNextChunk(length, frameData.data())) {
 
810
        // put back the frame headers to the buffer
 
811
        m_spdyBuffer.prepend(frameHeaders);
 
812
        return; // we couldn't read the whole frame and need to wait
 
813
    } else {
 
814
        m_spdyBuffer.clear();
 
815
        m_waitingForCompleteStream = false;
 
816
    }
 
817
 
 
818
    switch (type) {
 
819
    case FrameType_SYN_STREAM: {
 
820
        handleSYN_STREAM(flags, length, frameData);
 
821
        break;
 
822
    }
 
823
    case FrameType_SYN_REPLY: {
 
824
        handleSYN_REPLY(flags, length, frameData);
 
825
        break;
 
826
    }
 
827
    case FrameType_RST_STREAM: {
 
828
        handleRST_STREAM(flags, length, frameData);
 
829
        break;
 
830
    }
 
831
    case FrameType_SETTINGS: {
 
832
        handleSETTINGS(flags, length, frameData);
 
833
        break;
 
834
    }
 
835
    case FrameType_PING: {
 
836
        handlePING(flags, length, frameData);
 
837
        break;
 
838
    }
 
839
    case FrameType_GOAWAY: {
 
840
        handleGOAWAY(flags, length, frameData);
 
841
        break;
 
842
    }
 
843
    case FrameType_HEADERS: {
 
844
        handleHEADERS(flags, length, frameData);
 
845
        break;
 
846
    }
 
847
    case FrameType_WINDOW_UPDATE: {
 
848
        handleWINDOW_UPDATE(flags, length, frameData);
 
849
        break;
 
850
    }
 
851
    default:
 
852
        qWarning() << "cannot handle frame of type" << type;
 
853
    }
 
854
}
 
855
 
 
856
void QSpdyProtocolHandler::handleSYN_STREAM(char /*flags*/, quint32 /*length*/,
 
857
                                            const QByteArray &frameData)
 
858
{
 
859
    // not implemented; will be implemented when servers start using it
 
860
    // we just tell the server that we do not accept that
 
861
 
 
862
    qint32 streamID = getStreamID(frameData.constData());
 
863
 
 
864
    sendRST_STREAM(streamID, RST_STREAM_REFUSED_STREAM);
 
865
}
 
866
 
 
867
void QSpdyProtocolHandler::handleSYN_REPLY(char flags, quint32 /*length*/, const QByteArray &frameData)
 
868
{
 
869
    parseHttpHeaders(flags, frameData);
 
870
}
 
871
 
 
872
void QSpdyProtocolHandler::parseHttpHeaders(char flags, const QByteArray &frameData)
 
873
{
 
874
    qint32 streamID = getStreamID(frameData.constData());
 
875
    const auto it = m_inFlightStreams.constFind(streamID);
 
876
    if (it == m_inFlightStreams.cend()) {
 
877
        sendRST_STREAM(streamID, RST_STREAM_INVALID_STREAM);
 
878
        return;
 
879
    }
 
880
 
 
881
    flags &= 0x3f;
 
882
    bool flag_fin = flags & 0x01;
 
883
 
 
884
    QByteArray headerValuePairs = frameData.mid(4);
 
885
 
 
886
    HttpMessagePair pair = it.value();
 
887
    QHttpNetworkReply *httpReply = pair.second;
 
888
    Q_ASSERT(httpReply != 0);
 
889
 
 
890
    if (httpReply->d_func()->state == QHttpNetworkReplyPrivate::SPDYClosed) {
 
891
        sendRST_STREAM(streamID, RST_STREAM_STREAM_ALREADY_CLOSED);
 
892
        return;
 
893
    }
 
894
 
 
895
    QByteArray uncompressedHeader;
 
896
    if (!uncompressHeader(headerValuePairs, &uncompressedHeader)) {
 
897
        qWarning("error reading header from SYN_REPLY message");
 
898
        return;
 
899
    }
 
900
 
 
901
    qint32 headerCount = fourBytesToInt(uncompressedHeader.constData());
 
902
    if (headerCount * 8 > uncompressedHeader.size()) {
 
903
        qWarning("error parsing header from SYN_REPLY message");
 
904
        sendRST_STREAM(streamID, RST_STREAM_PROTOCOL_ERROR);
 
905
        return;
 
906
    }
 
907
    qint32 readPointer = 4;
 
908
    for (qint32 a = 0; a < headerCount; ++a) {
 
909
        qint32 count = fourBytesToInt(uncompressedHeader.constData() + readPointer);
 
910
        readPointer += 4;
 
911
        QByteArray name = uncompressedHeader.mid(readPointer, count);
 
912
        readPointer += count;
 
913
        if (readPointer > uncompressedHeader.size()) {
 
914
            qWarning("error parsing header from SYN_REPLY message");
 
915
            sendRST_STREAM(streamID, RST_STREAM_PROTOCOL_ERROR);
 
916
            return;
 
917
        }
 
918
        count = fourBytesToInt(uncompressedHeader.constData() + readPointer);
 
919
        readPointer += 4;
 
920
        QByteArray value = uncompressedHeader.mid(readPointer, count);
 
921
        readPointer += count;
 
922
        if (readPointer > uncompressedHeader.size()) {
 
923
            qWarning("error parsing header from SYN_REPLY message");
 
924
            sendRST_STREAM(streamID, RST_STREAM_PROTOCOL_ERROR);
 
925
            return;
 
926
        }
 
927
        if (name == ":status") {
 
928
            httpReply->setStatusCode(value.left(3).toInt());
 
929
            httpReply->d_func()->reasonPhrase = QString::fromLatin1(value.mid(4));
 
930
        } else if (name == ":version") {
 
931
            int majorVersion = value.at(5) - 48;
 
932
            int minorVersion = value.at(7) - 48;
 
933
            httpReply->d_func()->majorVersion = majorVersion;
 
934
            httpReply->d_func()->minorVersion = minorVersion;
 
935
        } else if (name == "content-length") {
 
936
            httpReply->setContentLength(value.toLongLong());
 
937
        } else {
 
938
            value.replace('\0', name == "set-cookie" ? "\n" : ", ");
 
939
            httpReply->setHeaderField(name, value);
 
940
        }
 
941
    }
 
942
    emit httpReply->headerChanged();
 
943
 
 
944
    if (flag_fin) {
 
945
        if (httpReply->d_func()->state != QHttpNetworkReplyPrivate::SPDYHalfClosed)
 
946
            sendDataFrame(streamID, DataFrame_FLAG_FIN, 0, 0);
 
947
        replyFinished(httpReply, streamID);
 
948
    }
 
949
}
 
950
 
 
951
void QSpdyProtocolHandler::handleRST_STREAM(char /*flags*/, quint32 length,
 
952
                                            const QByteArray &frameData)
 
953
{
 
954
    // flags are ignored
 
955
 
 
956
    Q_ASSERT(length == 8);
 
957
    Q_UNUSED(length); // silence -Wunused-parameter
 
958
    qint32 streamID = getStreamID(frameData.constData());
 
959
    QHttpNetworkReply *httpReply = m_inFlightStreams.value(streamID).second;
 
960
 
 
961
    qint32 statusCodeInt = fourBytesToInt(frameData.constData() + 4);
 
962
    RST_STREAM_STATUS_CODE statusCode = static_cast<RST_STREAM_STATUS_CODE>(statusCodeInt);
 
963
    QNetworkReply::NetworkError errorCode;
 
964
    QByteArray errorMessage;
 
965
 
 
966
    switch (statusCode) {
 
967
    case RST_STREAM_PROTOCOL_ERROR:
 
968
        errorCode = QNetworkReply::ProtocolFailure;
 
969
        errorMessage = "SPDY protocol error";
 
970
        break;
 
971
    case RST_STREAM_INVALID_STREAM:
 
972
        errorCode = QNetworkReply::ProtocolFailure;
 
973
        errorMessage = "SPDY stream is not active";
 
974
        break;
 
975
    case RST_STREAM_REFUSED_STREAM:
 
976
        errorCode = QNetworkReply::ProtocolFailure;
 
977
        errorMessage = "SPDY stream was refused";
 
978
        break;
 
979
    case RST_STREAM_UNSUPPORTED_VERSION:
 
980
        errorCode = QNetworkReply::ProtocolUnknownError;
 
981
        errorMessage = "SPDY version is unknown to the server";
 
982
        break;
 
983
    case RST_STREAM_CANCEL:
 
984
        errorCode = QNetworkReply::ProtocolFailure;
 
985
        errorMessage = "SPDY stream is no longer needed";
 
986
        break;
 
987
    case RST_STREAM_INTERNAL_ERROR:
 
988
        errorCode = QNetworkReply::InternalServerError;
 
989
        errorMessage = "Internal server error";
 
990
        break;
 
991
    case RST_STREAM_FLOW_CONTROL_ERROR:
 
992
        errorCode = QNetworkReply::ProtocolFailure;
 
993
        errorMessage = "peer violated the flow control protocol";
 
994
        break;
 
995
    case RST_STREAM_STREAM_IN_USE:
 
996
        errorCode = QNetworkReply::ProtocolFailure;
 
997
        errorMessage = "server received a SYN_REPLY for an already open stream";
 
998
        break;
 
999
    case RST_STREAM_STREAM_ALREADY_CLOSED:
 
1000
        errorCode = QNetworkReply::ProtocolFailure;
 
1001
        errorMessage = "server received data or a SYN_REPLY for an already half-closed stream";
 
1002
        break;
 
1003
    case RST_STREAM_INVALID_CREDENTIALS:
 
1004
        errorCode = QNetworkReply::ContentAccessDenied;
 
1005
        errorMessage = "server received invalid credentials";
 
1006
        break;
 
1007
    case RST_STREAM_FRAME_TOO_LARGE:
 
1008
        errorCode = QNetworkReply::ProtocolFailure;
 
1009
        errorMessage = "server cannot process the frame because it is too large";
 
1010
        break;
 
1011
    default:
 
1012
        qWarning("could not understand servers RST_STREAM status code");
 
1013
        errorCode = QNetworkReply::ProtocolFailure;
 
1014
        errorMessage = "got SPDY RST_STREAM message with unknown error code";
 
1015
    }
 
1016
    if (httpReply)
 
1017
        replyFinishedWithError(httpReply, streamID, errorCode, errorMessage.constData());
 
1018
}
 
1019
 
 
1020
void QSpdyProtocolHandler::handleSETTINGS(char flags, quint32 /*length*/, const QByteArray &frameData)
 
1021
{
 
1022
    Q_ASSERT(frameData.count() > 0);
 
1023
 
 
1024
    SETTINGS_Flags settingsFlags = static_cast<SETTINGS_Flags>(flags);
 
1025
    if (settingsFlags & FLAG_SETTINGS_CLEAR_SETTINGS) {
 
1026
        // ### clear all persistent settings; since we do not persist settings
 
1027
        // as of now, we don't need to clear anything either
 
1028
    }
 
1029
 
 
1030
    qint32 numberOfEntries = fourBytesToInt(frameData.constData());
 
1031
    Q_ASSERT(numberOfEntries > 0);
 
1032
    for (int a = 0, frameDataIndex = 4; a < numberOfEntries; ++a, frameDataIndex += 8) {
 
1033
        SETTINGS_ID_Flag idFlag = static_cast<SETTINGS_ID_Flag>(frameData[frameDataIndex]);
 
1034
        if (idFlag & FLAG_SETTINGS_PERSIST_VALUE) {
 
1035
            // ### we SHOULD persist the settings here according to the RFC, but we don't have to,
 
1036
            // so implement that later
 
1037
        } // the other value is only sent by us, but not received
 
1038
 
 
1039
        quint32 uniqueID = static_cast<SETTINGS_ID>(
 
1040
                    threeBytesToInt(frameData.constData() + frameDataIndex + 1));
 
1041
        quint32 value = fourBytesToInt(frameData.constData() + frameDataIndex + 4);
 
1042
        switch (uniqueID) {
 
1043
        case SETTINGS_UPLOAD_BANDWIDTH: {
 
1044
            // ignored for now, just an estimated informative value
 
1045
            break;
 
1046
        }
 
1047
        case SETTINGS_DOWNLOAD_BANDWIDTH: {
 
1048
            // ignored for now, just an estimated informative value
 
1049
            break;
 
1050
        }
 
1051
        case SETTINGS_ROUND_TRIP_TIME: {
 
1052
            // ignored for now, just an estimated informative value
 
1053
            break;
 
1054
        }
 
1055
        case SETTINGS_MAX_CONCURRENT_STREAMS: {
 
1056
            m_maxConcurrentStreams = value;
 
1057
            break;
 
1058
        }
 
1059
        case SETTINGS_CURRENT_CWND: {
 
1060
            // ignored for now, just an informative value
 
1061
            break;
 
1062
        }
 
1063
        case SETTINGS_DOWNLOAD_RETRANS_RATE: {
 
1064
            // ignored for now, just an estimated informative value
 
1065
            break;
 
1066
        }
 
1067
        case SETTINGS_INITIAL_WINDOW_SIZE: {
 
1068
            m_initialWindowSize = value;
 
1069
            break;
 
1070
        }
 
1071
        case SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE: {
 
1072
            // client certificates are not supported
 
1073
            break;
 
1074
        }
 
1075
        default:
 
1076
            qWarning() << "found unknown settings value" << value;
 
1077
        }
 
1078
    }
 
1079
}
 
1080
 
 
1081
void QSpdyProtocolHandler::handlePING(char /*flags*/, quint32 length, const QByteArray &frameData)
 
1082
{
 
1083
    // flags are ignored
 
1084
 
 
1085
    Q_ASSERT(length == 4);
 
1086
    Q_UNUSED(length); // silence -Wunused-parameter
 
1087
    quint32 pingID = fourBytesToInt(frameData.constData());
 
1088
 
 
1089
    // odd numbered IDs must be ignored
 
1090
    if ((pingID & 1) == 0) // is even?
 
1091
        sendPING(pingID);
 
1092
}
 
1093
 
 
1094
void QSpdyProtocolHandler::handleGOAWAY(char /*flags*/, quint32 /*length*/,
 
1095
                                        const QByteArray &frameData)
 
1096
{
 
1097
    // flags are ignored
 
1098
 
 
1099
    qint32 statusCode = static_cast<GOAWAY_STATUS>(fourBytesToInt(frameData.constData() + 4));
 
1100
    QNetworkReply::NetworkError errorCode;
 
1101
    switch (statusCode) {
 
1102
    case GOAWAY_OK: {
 
1103
        errorCode = QNetworkReply::NoError;
 
1104
        break;
 
1105
    }
 
1106
    case GOAWAY_PROTOCOL_ERROR: {
 
1107
        errorCode = QNetworkReply::ProtocolFailure;
 
1108
        break;
 
1109
    }
 
1110
    case GOAWAY_INTERNAL_ERROR: {
 
1111
        errorCode = QNetworkReply::InternalServerError;
 
1112
        break;
 
1113
    }
 
1114
    default:
 
1115
        qWarning() << "unexpected status code" << statusCode;
 
1116
        errorCode = QNetworkReply::ProtocolUnknownError;
 
1117
    }
 
1118
 
 
1119
    qint32 lastGoodStreamID = getStreamID(frameData.constData());
 
1120
 
 
1121
    // emit errors for all replies after the last good stream ID
 
1122
    Q_ASSERT(m_connection);
 
1123
    for (qint32 currentStreamID = lastGoodStreamID + 2; currentStreamID <= m_nextStreamID;
 
1124
         ++currentStreamID) {
 
1125
        QHttpNetworkReply *reply = m_inFlightStreams.value(currentStreamID).second;
 
1126
        Q_ASSERT(reply);
 
1127
        m_connection->d_func()->emitReplyError(m_socket, reply, errorCode);
 
1128
    }
 
1129
    // ### we could make sure a new session is initiated anyhow
 
1130
}
 
1131
 
 
1132
void QSpdyProtocolHandler::handleHEADERS(char flags, quint32 /*length*/,
 
1133
                                         const QByteArray &frameData)
 
1134
{
 
1135
    parseHttpHeaders(flags, frameData);
 
1136
}
 
1137
 
 
1138
void QSpdyProtocolHandler::handleWINDOW_UPDATE(char /*flags*/, quint32 /*length*/,
 
1139
                                               const QByteArray &frameData)
 
1140
{
 
1141
    qint32 streamID = getStreamID(frameData.constData());
 
1142
    qint32 deltaWindowSize = fourBytesToInt(frameData.constData() + 4);
 
1143
 
 
1144
    const auto it = m_inFlightStreams.constFind(streamID);
 
1145
    if (it == m_inFlightStreams.cend()) {
 
1146
        sendRST_STREAM(streamID, RST_STREAM_INVALID_STREAM);
 
1147
        return;
 
1148
    }
 
1149
 
 
1150
    QHttpNetworkReply *reply = it.value().second;
 
1151
    Q_ASSERT(reply);
 
1152
    QHttpNetworkReplyPrivate *replyPrivate = reply->d_func();
 
1153
    Q_ASSERT(replyPrivate);
 
1154
 
 
1155
    // Ignore WINDOW_UPDATE if we are already done.
 
1156
    if (replyPrivate->state == QHttpNetworkReplyPrivate::SPDYHalfClosed || replyPrivate->state == QHttpNetworkReplyPrivate::SPDYClosed)
 
1157
        return;
 
1158
 
 
1159
    replyPrivate->currentlyUploadedDataInWindow = replyPrivate->windowSizeUpload - deltaWindowSize;
 
1160
    uploadData(streamID); // we hopefully can continue to upload
 
1161
}
 
1162
 
 
1163
 
 
1164
void QSpdyProtocolHandler::handleDataFrame(const QByteArray &frameHeaders)
 
1165
{
 
1166
    Q_ASSERT(frameHeaders.count() >= 8);
 
1167
 
 
1168
    qint32 streamID = getStreamID(frameHeaders.constData());
 
1169
    const auto it = m_inFlightStreams.constFind(streamID);
 
1170
    if (it == m_inFlightStreams.cend()) {
 
1171
        sendRST_STREAM(streamID, RST_STREAM_INVALID_STREAM);
 
1172
        return;
 
1173
    }
 
1174
 
 
1175
    unsigned char flags = static_cast<unsigned char>(frameHeaders.at(4));
 
1176
    flags &= 0x3f;
 
1177
    bool flag_fin = flags & 0x01;
 
1178
    bool flag_compress = flags & 0x02;
 
1179
    qint32 length = threeBytesToInt(frameHeaders.constData() + 5);
 
1180
 
 
1181
    QByteArray data;
 
1182
    data.resize(length);
 
1183
    if (!readNextChunk(length, data.data())) {
 
1184
        // put back the frame headers to the buffer
 
1185
        m_spdyBuffer.prepend(frameHeaders);
 
1186
        return; // we couldn't read the whole frame and need to wait
 
1187
    } else {
 
1188
        m_spdyBuffer.clear();
 
1189
        m_waitingForCompleteStream = false;
 
1190
    }
 
1191
 
 
1192
    HttpMessagePair pair = it.value();
 
1193
    QHttpNetworkRequest httpRequest = pair.first;
 
1194
    QHttpNetworkReply *httpReply = pair.second;
 
1195
    Q_ASSERT(httpReply != 0);
 
1196
 
 
1197
    QHttpNetworkReplyPrivate *replyPrivate = httpReply->d_func();
 
1198
 
 
1199
    if (replyPrivate->state == QHttpNetworkReplyPrivate::SPDYClosed) {
 
1200
        sendRST_STREAM(streamID, RST_STREAM_STREAM_ALREADY_CLOSED);
 
1201
        return;
 
1202
    }
 
1203
 
 
1204
    // check whether we need to send WINDOW_UPDATE (i.e. tell the sender it can send more)
 
1205
    replyPrivate->currentlyReceivedDataInWindow += length;
 
1206
    qint32 dataLeftInWindow = replyPrivate->windowSizeDownload - replyPrivate->currentlyReceivedDataInWindow;
 
1207
 
 
1208
    if (replyPrivate->currentlyReceivedDataInWindow > 0
 
1209
            && dataLeftInWindow < replyPrivate->windowSizeDownload / 2) {
 
1210
 
 
1211
        // socket read buffer size is 64K actually, hard coded in the channel
 
1212
        // We can read way more than 64K per socket, because the window size
 
1213
        // here is per stream.
 
1214
        if (replyPrivate->windowSizeDownload >= m_socket->readBufferSize()) {
 
1215
            replyPrivate->windowSizeDownload = m_socket->readBufferSize();
 
1216
        } else {
 
1217
            replyPrivate->windowSizeDownload *= 1.5;
 
1218
        }
 
1219
        QMetaObject::invokeMethod(this, "sendWINDOW_UPDATE", Qt::QueuedConnection,
 
1220
                                  Q_ARG(qint32, streamID),
 
1221
                                  Q_ARG(quint32, replyPrivate->windowSizeDownload));
 
1222
        // setting the current data count to 0 is a race condition,
 
1223
        // because we call sendWINDOW_UPDATE through the event loop.
 
1224
        // But then again, the whole situation is a race condition because
 
1225
        // we don't know when the packet will arrive at the server; so
 
1226
        // this is most likely good enough here.
 
1227
        replyPrivate->currentlyReceivedDataInWindow = 0;
 
1228
    }
 
1229
 
 
1230
    httpReply->d_func()->compressedData.append(data);
 
1231
 
 
1232
 
 
1233
    replyPrivate->totalProgress += length;
 
1234
 
 
1235
    if (httpRequest.d->autoDecompress && httpReply->d_func()->isCompressed()) {
 
1236
        QByteDataBuffer inDataBuffer; // ### should we introduce one in the http reply?
 
1237
        inDataBuffer.append(data);
 
1238
        qint64 compressedCount = httpReply->d_func()->uncompressBodyData(&inDataBuffer,
 
1239
                                                                         &replyPrivate->responseData);
 
1240
        Q_ASSERT(compressedCount >= 0);
 
1241
        Q_UNUSED(compressedCount); // silence -Wunused-variable
 
1242
    } else {
 
1243
        replyPrivate->responseData.append(data);
 
1244
    }
 
1245
 
 
1246
    if (replyPrivate->shouldEmitSignals()) {
 
1247
        emit httpReply->readyRead();
 
1248
        emit httpReply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
 
1249
    }
 
1250
 
 
1251
    if (flag_compress) {
 
1252
        qWarning("SPDY level compression is not supported");
 
1253
    }
 
1254
 
 
1255
    if (flag_fin) {
 
1256
        if (httpReply->d_func()->state != QHttpNetworkReplyPrivate::SPDYHalfClosed)
 
1257
            sendDataFrame(streamID, DataFrame_FLAG_FIN, 0, 0);
 
1258
        replyFinished(httpReply, streamID);
 
1259
    }
 
1260
}
 
1261
 
 
1262
void QSpdyProtocolHandler::replyFinished(QHttpNetworkReply *httpReply, qint32 streamID)
 
1263
{
 
1264
    httpReply->d_func()->state = QHttpNetworkReplyPrivate::SPDYClosed;
 
1265
    httpReply->disconnect(this);
 
1266
    if (httpReply->request().uploadByteDevice())
 
1267
        httpReply->request().uploadByteDevice()->disconnect(this);
 
1268
    int streamsRemoved = m_inFlightStreams.remove(streamID);
 
1269
    Q_ASSERT(streamsRemoved == 1);
 
1270
    Q_UNUSED(streamsRemoved); // silence -Wunused-variable
 
1271
    emit httpReply->finished();
 
1272
}
 
1273
 
 
1274
void QSpdyProtocolHandler::replyFinishedWithError(QHttpNetworkReply *httpReply, qint32 streamID,
 
1275
                                                  QNetworkReply::NetworkError errorCode, const char *errorMessage)
 
1276
{
 
1277
    Q_ASSERT(httpReply);
 
1278
    httpReply->d_func()->state = QHttpNetworkReplyPrivate::SPDYClosed;
 
1279
    httpReply->disconnect(this);
 
1280
    if (httpReply->request().uploadByteDevice())
 
1281
        httpReply->request().uploadByteDevice()->disconnect(this);
 
1282
    int streamsRemoved = m_inFlightStreams.remove(streamID);
 
1283
    Q_ASSERT(streamsRemoved == 1);
 
1284
    Q_UNUSED(streamsRemoved); // silence -Wunused-variable
 
1285
    emit httpReply->finishedWithError(errorCode, QSpdyProtocolHandler::tr(errorMessage));
 
1286
}
 
1287
 
 
1288
qint32 QSpdyProtocolHandler::generateNextStreamID()
 
1289
{
 
1290
    // stream IDs initiated by the client must be odd
 
1291
    m_nextStreamID += 2;
 
1292
    return m_nextStreamID;
 
1293
}
 
1294
 
 
1295
QT_END_NAMESPACE
 
1296
 
 
1297
#endif // !defined(QT_NO_HTTP) && !defined(QT_NO_SSL)