OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/fetch/MultipartImageResourceParser.h" | 5 #include "core/fetch/MultipartImageResourceParser.h" |
6 | 6 |
7 #include "public/platform/Platform.h" | 7 #include "public/platform/Platform.h" |
8 #include "public/platform/WebURLResponse.h" | 8 #include "public/platform/WebURLResponse.h" |
9 #include "wtf/NotFound.h" | 9 #include "wtf/NotFound.h" |
10 #include "wtf/text/WTFString.h" | 10 #include "wtf/text/WTFString.h" |
11 | 11 |
12 #include <algorithm> | 12 #include <algorithm> |
13 | 13 |
14 namespace blink { | 14 namespace blink { |
15 | 15 |
16 MultipartImageResourceParser::MultipartImageResourceParser( | 16 MultipartImageResourceParser::MultipartImageResourceParser( |
17 const ResourceResponse& response, | 17 const ResourceResponse& response, |
18 const Vector<char>& boundary, | 18 const Vector<char>& boundary, |
19 Client* client) | 19 Client* client) |
20 : m_originalResponse(response), m_boundary(boundary), m_client(client) { | 20 : m_originalResponse(response), m_boundary(boundary), m_client(client) { |
21 // Some servers report a boundary prefixed with "--". See https://crbug.com/5
786. | 21 // Some servers report a boundary prefixed with "--". See |
| 22 // https://crbug.com/5786. |
22 if (m_boundary.size() < 2 || m_boundary[0] != '-' || m_boundary[1] != '-') | 23 if (m_boundary.size() < 2 || m_boundary[0] != '-' || m_boundary[1] != '-') |
23 m_boundary.prepend("--", 2); | 24 m_boundary.prepend("--", 2); |
24 } | 25 } |
25 | 26 |
26 void MultipartImageResourceParser::appendData(const char* bytes, size_t size) { | 27 void MultipartImageResourceParser::appendData(const char* bytes, size_t size) { |
27 DCHECK(!isCancelled()); | 28 DCHECK(!isCancelled()); |
28 // m_sawLastBoundary means that we've already received the final boundary | 29 // m_sawLastBoundary means that we've already received the final boundary |
29 // token. The server should stop sending us data at this point, but if it | 30 // token. The server should stop sending us data at this point, but if it |
30 // does, we just throw it away. | 31 // does, we just throw it away. |
31 if (m_sawLastBoundary) | 32 if (m_sawLastBoundary) |
32 return; | 33 return; |
33 m_data.append(bytes, size); | 34 m_data.append(bytes, size); |
34 | 35 |
35 if (m_isParsingTop) { | 36 if (m_isParsingTop) { |
36 // Eat leading \r\n | 37 // Eat leading \r\n |
37 size_t pos = skippableLength(m_data, 0); | 38 size_t pos = skippableLength(m_data, 0); |
38 // +2 for "--" | 39 // +2 for "--" |
39 if (m_data.size() < m_boundary.size() + 2 + pos) { | 40 if (m_data.size() < m_boundary.size() + 2 + pos) { |
40 // We don't have enough data yet to make a boundary token. Just | 41 // We don't have enough data yet to make a boundary token. Just wait |
41 // wait until the next chunk of data arrives. | 42 // until the next chunk of data arrives. |
42 return; | 43 return; |
43 } | 44 } |
44 if (pos) | 45 if (pos) |
45 m_data.remove(0, pos); | 46 m_data.remove(0, pos); |
46 | 47 |
47 // Some servers don't send a boundary token before the first chunk of | 48 // Some servers don't send a boundary token before the first chunk of |
48 // data. We handle this case anyway (Gecko does too). | 49 // data. We handle this case anyway (Gecko does too). |
49 if (0 != memcmp(m_data.data(), m_boundary.data(), m_boundary.size())) { | 50 if (0 != memcmp(m_data.data(), m_boundary.data(), m_boundary.size())) { |
50 m_data.prepend("\n", 1); | 51 m_data.prepend("\n", 1); |
51 m_data.prependVector(m_boundary); | 52 m_data.prependVector(m_boundary); |
52 } | 53 } |
53 m_isParsingTop = false; | 54 m_isParsingTop = false; |
54 } | 55 } |
55 | 56 |
56 // Headers | 57 // Headers |
57 if (m_isParsingHeaders) { | 58 if (m_isParsingHeaders) { |
58 if (!parseHeaders()) { | 59 if (!parseHeaders()) { |
59 // Get more data before trying again. | 60 // Get more data before trying again. |
60 return; | 61 return; |
61 } | 62 } |
62 // Successfully parsed headers. | 63 // Successfully parsed headers. |
63 m_isParsingHeaders = false; | 64 m_isParsingHeaders = false; |
64 if (isCancelled()) | 65 if (isCancelled()) |
65 return; | 66 return; |
66 } | 67 } |
67 | 68 |
68 size_t boundaryPosition; | 69 size_t boundaryPosition; |
69 while ((boundaryPosition = findBoundary(m_data, &m_boundary)) != kNotFound) { | 70 while ((boundaryPosition = findBoundary(m_data, &m_boundary)) != kNotFound) { |
70 // Strip out trailing \r\n characters in the buffer preceding the | 71 // Strip out trailing \r\n characters in the buffer preceding the boundary |
71 // boundary on the same lines as does Firefox. | 72 // on the same lines as does Firefox. |
72 size_t dataSize = boundaryPosition; | 73 size_t dataSize = boundaryPosition; |
73 if (boundaryPosition > 0 && m_data[boundaryPosition - 1] == '\n') { | 74 if (boundaryPosition > 0 && m_data[boundaryPosition - 1] == '\n') { |
74 dataSize--; | 75 dataSize--; |
75 if (boundaryPosition > 1 && m_data[boundaryPosition - 2] == '\r') { | 76 if (boundaryPosition > 1 && m_data[boundaryPosition - 2] == '\r') { |
76 dataSize--; | 77 dataSize--; |
77 } | 78 } |
78 } | 79 } |
79 if (dataSize) { | 80 if (dataSize) { |
80 m_client->multipartDataReceived(m_data.data(), dataSize); | 81 m_client->multipartDataReceived(m_data.data(), dataSize); |
81 if (isCancelled()) | 82 if (isCancelled()) |
(...skipping 13 matching lines...) Expand all Loading... |
95 | 96 |
96 // Ok, back to parsing headers | 97 // Ok, back to parsing headers |
97 if (!parseHeaders()) { | 98 if (!parseHeaders()) { |
98 m_isParsingHeaders = true; | 99 m_isParsingHeaders = true; |
99 break; | 100 break; |
100 } | 101 } |
101 if (isCancelled()) | 102 if (isCancelled()) |
102 return; | 103 return; |
103 } | 104 } |
104 | 105 |
105 // At this point, we should send over any data we have, but keep enough | 106 // At this point, we should send over any data we have, but keep enough data |
106 // data buffered to handle a boundary that may have been truncated. | 107 // buffered to handle a boundary that may have been truncated. "+2" for CRLF, |
107 // "+2" for CRLF, as we may ignore the last CRLF. | 108 // as we may ignore the last CRLF. |
108 if (!m_isParsingHeaders && m_data.size() > m_boundary.size() + 2) { | 109 if (!m_isParsingHeaders && m_data.size() > m_boundary.size() + 2) { |
109 size_t sendLength = m_data.size() - m_boundary.size() - 2; | 110 size_t sendLength = m_data.size() - m_boundary.size() - 2; |
110 m_client->multipartDataReceived(m_data.data(), sendLength); | 111 m_client->multipartDataReceived(m_data.data(), sendLength); |
111 m_data.remove(0, sendLength); | 112 m_data.remove(0, sendLength); |
112 } | 113 } |
113 } | 114 } |
114 | 115 |
115 void MultipartImageResourceParser::finish() { | 116 void MultipartImageResourceParser::finish() { |
116 DCHECK(!isCancelled()); | 117 DCHECK(!isCancelled()); |
117 if (m_sawLastBoundary) | 118 if (m_sawLastBoundary) |
(...skipping 13 matching lines...) Expand all Loading... |
131 if (data.size() >= pos + 1 && data[pos] == '\n') | 132 if (data.size() >= pos + 1 && data[pos] == '\n') |
132 return 1; | 133 return 1; |
133 return 0; | 134 return 0; |
134 } | 135 } |
135 | 136 |
136 bool MultipartImageResourceParser::parseHeaders() { | 137 bool MultipartImageResourceParser::parseHeaders() { |
137 // Eat leading \r\n | 138 // Eat leading \r\n |
138 size_t pos = skippableLength(m_data, 0); | 139 size_t pos = skippableLength(m_data, 0); |
139 | 140 |
140 // Create a WebURLResponse based on the original set of headers + the | 141 // Create a WebURLResponse based on the original set of headers + the |
141 // replacement headers. We only replace the same few headers that gecko | 142 // replacement headers. We only replace the same few headers that gecko does. |
142 // does. See netwerk/streamconv/converters/nsMultiMixedConv.cpp. | 143 // See netwerk/streamconv/converters/nsMultiMixedConv.cpp. |
143 WebURLResponse response(m_originalResponse.url()); | 144 WebURLResponse response(m_originalResponse.url()); |
144 for (const auto& header : m_originalResponse.httpHeaderFields()) | 145 for (const auto& header : m_originalResponse.httpHeaderFields()) |
145 response.addHTTPHeaderField(header.key, header.value); | 146 response.addHTTPHeaderField(header.key, header.value); |
146 | 147 |
147 size_t end = 0; | 148 size_t end = 0; |
148 if (!Platform::current()->parseMultipartHeadersFromBody( | 149 if (!Platform::current()->parseMultipartHeadersFromBody( |
149 m_data.data() + pos, m_data.size() - pos, &response, &end)) | 150 m_data.data() + pos, m_data.size() - pos, &response, &end)) |
150 return false; | 151 return false; |
151 m_data.remove(0, end + pos); | 152 m_data.remove(0, end + pos); |
152 // Send the response! | 153 // Send the response! |
153 m_client->onePartInMultipartReceived(response.toResourceResponse()); | 154 m_client->onePartInMultipartReceived(response.toResourceResponse()); |
154 return true; | 155 return true; |
155 } | 156 } |
156 | 157 |
157 // Boundaries are supposed to be preceeded with --, but it looks like gecko | 158 // Boundaries are supposed to be preceeded with --, but it looks like gecko |
158 // doesn't require the dashes to exist. See nsMultiMixedConv::FindToken. | 159 // doesn't require the dashes to exist. See nsMultiMixedConv::FindToken. |
159 size_t MultipartImageResourceParser::findBoundary(const Vector<char>& data, | 160 size_t MultipartImageResourceParser::findBoundary(const Vector<char>& data, |
160 Vector<char>* boundary) { | 161 Vector<char>* boundary) { |
161 auto it = std::search(data.data(), data.data() + data.size(), | 162 auto it = std::search(data.data(), data.data() + data.size(), |
162 boundary->data(), boundary->data() + boundary->size()); | 163 boundary->data(), boundary->data() + boundary->size()); |
163 if (it == data.data() + data.size()) | 164 if (it == data.data() + data.size()) |
164 return kNotFound; | 165 return kNotFound; |
165 | 166 |
166 size_t boundaryPosition = it - data.data(); | 167 size_t boundaryPosition = it - data.data(); |
167 // Back up over -- for backwards compat | 168 // Back up over -- for backwards compat |
168 // TODO(tc): Don't we only want to do this once? Gecko code doesn't | 169 // TODO(tc): Don't we only want to do this once? Gecko code doesn't seem to |
169 // seem to care. | 170 // care. |
170 if (boundaryPosition >= 2) { | 171 if (boundaryPosition >= 2) { |
171 if (data[boundaryPosition - 1] == '-' && | 172 if (data[boundaryPosition - 1] == '-' && |
172 data[boundaryPosition - 2] == '-') { | 173 data[boundaryPosition - 2] == '-') { |
173 boundaryPosition -= 2; | 174 boundaryPosition -= 2; |
174 Vector<char> v(2, '-'); | 175 Vector<char> v(2, '-'); |
175 v.appendVector(*boundary); | 176 v.appendVector(*boundary); |
176 *boundary = v; | 177 *boundary = v; |
177 } | 178 } |
178 } | 179 } |
179 return boundaryPosition; | 180 return boundaryPosition; |
180 } | 181 } |
181 | 182 |
182 DEFINE_TRACE(MultipartImageResourceParser) { | 183 DEFINE_TRACE(MultipartImageResourceParser) { |
183 visitor->trace(m_client); | 184 visitor->trace(m_client); |
184 } | 185 } |
185 | 186 |
186 } // namespace blink | 187 } // namespace blink |
OLD | NEW |