Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(441)

Side by Side Diff: third_party/WebKit/Source/core/fetch/MultipartImageResourceParser.cpp

Issue 1808353003: Make multipart/x-mixed-replace parser more robust (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@multipart-3
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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"
(...skipping 17 matching lines...) Expand all
28 ASSERT(!isCancelled()); 28 ASSERT(!isCancelled());
29 // m_sawLastBoundary means that we've already received the final boundary 29 // m_sawLastBoundary means that we've already received the final boundary
30 // 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
31 // does, we just throw it away. 31 // does, we just throw it away.
32 if (m_sawLastBoundary) 32 if (m_sawLastBoundary)
33 return; 33 return;
34 m_data.append(bytes, size); 34 m_data.append(bytes, size);
35 35
36 if (m_isParsingTop) { 36 if (m_isParsingTop) {
37 // Eat leading \r\n 37 // Eat leading \r\n
38 size_t pos = pushOverLine(m_data, 0); 38 size_t pos = skippableLength(m_data, 0);
39 if (pos) 39 // +2 for "--"
40 m_data.remove(0, pos); 40 if (m_data.size() < m_boundary.size() + 2 + pos) {
41
42 if (m_data.size() < m_boundary.size() + 2) {
43 // 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
44 // wait until the next chunk of data arrives. 42 // wait until the next chunk of data arrives.
45 return; 43 return;
46 } 44 }
45 if (pos)
46 m_data.remove(0, pos);
47 47
48 // 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
49 // data. We handle this case anyway (Gecko does too). 49 // data. We handle this case anyway (Gecko does too).
50 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())) {
51 m_data.prepend("\n", 1); 51 m_data.prepend("\n", 1);
52 m_data.prependVector(m_boundary); 52 m_data.prependVector(m_boundary);
53 } 53 }
54 m_isParsingTop = false; 54 m_isParsingTop = false;
55 } 55 }
56 56
57 // Headers 57 // Headers
58 if (m_isParsingHeaders) { 58 if (m_isParsingHeaders) {
59 // Eat leading \r\n
60 size_t pos = pushOverLine(m_data, 0);
61 if (pos)
62 m_data.remove(0, pos);
63
64 if (!parseHeaders()) { 59 if (!parseHeaders()) {
65 // Get more data before trying again. 60 // Get more data before trying again.
66 return; 61 return;
67 } 62 }
68 // Successfully parsed headers. 63 // Successfully parsed headers.
69 m_isParsingHeaders = false; 64 m_isParsingHeaders = false;
70 if (isCancelled()) 65 if (isCancelled())
71 return; 66 return;
72 } 67 }
73 68
(...skipping 15 matching lines...) Expand all
89 } 84 }
90 size_t boundaryEndPosition = boundaryPosition + m_boundary.size(); 85 size_t boundaryEndPosition = boundaryPosition + m_boundary.size();
91 if (boundaryEndPosition < m_data.size() && '-' == m_data[boundaryEndPosi tion]) { 86 if (boundaryEndPosition < m_data.size() && '-' == m_data[boundaryEndPosi tion]) {
92 // This was the last boundary so we can stop processing. 87 // This was the last boundary so we can stop processing.
93 m_sawLastBoundary = true; 88 m_sawLastBoundary = true;
94 m_data.clear(); 89 m_data.clear();
95 return; 90 return;
96 } 91 }
97 92
98 // We can now throw out data up through the boundary 93 // We can now throw out data up through the boundary
99 size_t offset = pushOverLine(m_data, boundaryEndPosition); 94 m_data.remove(0, boundaryEndPosition);
100 m_data.remove(0, boundaryEndPosition + offset);
101 95
102 // Ok, back to parsing headers 96 // Ok, back to parsing headers
103 if (!parseHeaders()) { 97 if (!parseHeaders()) {
104 m_isParsingHeaders = true; 98 m_isParsingHeaders = true;
105 break; 99 break;
106 } 100 }
107 if (isCancelled()) 101 if (isCancelled())
108 return; 102 return;
109 } 103 }
110 104
111 // At this point, we should send over any data we have, but keep enough data 105 // At this point, we should send over any data we have, but keep enough
112 // buffered to handle a boundary that may have been truncated. 106 // data buffered to handle a boundary that may have been truncated.
113 if (!m_isParsingHeaders && m_data.size() > m_boundary.size()) { 107 // "+2" for CRLF, as we may ignore the last CRLF.
114 // If the last character is a new line character, go ahead and just send 108 if (!m_isParsingHeaders && m_data.size() > m_boundary.size() + 2) {
115 // everything we have buffered. This matches an optimization in Gecko. 109 size_t sendLength = m_data.size() - m_boundary.size() - 2;
116 size_t sendLength = m_data.size() - m_boundary.size();
117 if (m_data.last() == '\n')
118 sendLength = m_data.size();
119 m_client->multipartDataReceived(m_data.data(), sendLength); 110 m_client->multipartDataReceived(m_data.data(), sendLength);
120 m_data.remove(0, sendLength); 111 m_data.remove(0, sendLength);
121 } 112 }
122 } 113 }
123 114
124 void MultipartImageResourceParser::finish() 115 void MultipartImageResourceParser::finish()
125 { 116 {
126 ASSERT(!isCancelled()); 117 ASSERT(!isCancelled());
127 if (m_sawLastBoundary) 118 if (m_sawLastBoundary)
128 return; 119 return;
129 // If we have any pending data and we're not in a header, go ahead and send 120 // If we have any pending data and we're not in a header, go ahead and send
130 // it to the client. 121 // it to the client.
131 if (!m_isParsingHeaders && !m_data.isEmpty()) 122 if (!m_isParsingHeaders && !m_data.isEmpty())
132 m_client->multipartDataReceived(m_data.data(), m_data.size()); 123 m_client->multipartDataReceived(m_data.data(), m_data.size());
133 m_data.clear(); 124 m_data.clear();
134 m_sawLastBoundary = true; 125 m_sawLastBoundary = true;
135 } 126 }
136 127
137 size_t MultipartImageResourceParser::pushOverLine(const Vector<char>& data, size _t pos) 128 size_t MultipartImageResourceParser::skippableLength(const Vector<char>& data, s ize_t pos)
138 { 129 {
139 size_t offset = 0; 130 if (data.size() >= pos + 2 && data[pos] == '\r' && data[pos + 1] == '\n')
140 // TODO(yhirano): This function has two problems. Fix them. 131 return 2;
141 // 1. It eats "\n\n". 132 if (data.size() >= pos + 1 && data[pos] == '\n')
142 // 2. When the incoming data is not sufficient (i.e. data[pos] == '\r' 133 return 1;
143 // && data.size() == pos + 1), it should notify the caller. 134 return 0;
144 if (pos < data.size() && (data[pos] == '\r' || data[pos] == '\n')) {
145 ++offset;
146 if (pos + 1 < data.size() && data[pos + 1] == '\n')
147 ++offset;
148 }
149 return offset;
150 } 135 }
151 136
152 bool MultipartImageResourceParser::parseHeaders() 137 bool MultipartImageResourceParser::parseHeaders()
153 { 138 {
139 // Eat leading \r\n
140 size_t pos = skippableLength(m_data, 0);
141
154 // Create a WebURLResponse based on the original set of headers + the 142 // Create a WebURLResponse based on the original set of headers + the
155 // replacement headers. We only replace the same few headers that gecko 143 // replacement headers. We only replace the same few headers that gecko
156 // does. See netwerk/streamconv/converters/nsMultiMixedConv.cpp. 144 // does. See netwerk/streamconv/converters/nsMultiMixedConv.cpp.
157 WebURLResponse response(m_originalResponse.url()); 145 WebURLResponse response(m_originalResponse.url());
158 for (const auto& header : m_originalResponse.httpHeaderFields()) 146 for (const auto& header : m_originalResponse.httpHeaderFields())
159 response.addHTTPHeaderField(header.key, header.value); 147 response.addHTTPHeaderField(header.key, header.value);
160 148
161 size_t end = 0; 149 size_t end = 0;
162 if (!Platform::current()->parseMultipartHeadersFromBody(m_data.data(), m_dat a.size(), &response, &end)) 150 if (!Platform::current()->parseMultipartHeadersFromBody(m_data.data() + pos, m_data.size() - pos, &response, &end))
163 return false; 151 return false;
164 m_data.remove(0, end); 152 m_data.remove(0, end + pos);
165 // Send the response! 153 // Send the response!
166 m_client->onePartInMultipartReceived(response.toResourceResponse()); 154 m_client->onePartInMultipartReceived(response.toResourceResponse());
167 return true; 155 return true;
168 } 156 }
169 157
170 // 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
171 // doesn't require the dashes to exist. See nsMultiMixedConv::FindToken. 159 // doesn't require the dashes to exist. See nsMultiMixedConv::FindToken.
172 size_t MultipartImageResourceParser::findBoundary(const Vector<char>& data, Vect or<char>* boundary) 160 size_t MultipartImageResourceParser::findBoundary(const Vector<char>& data, Vect or<char>* boundary)
173 { 161 {
174 auto it = std::search(data.data(), data.data() + data.size(), boundary->data (), boundary->data() + boundary->size()); 162 auto it = std::search(data.data(), data.data() + data.size(), boundary->data (), boundary->data() + boundary->size());
(...skipping 14 matching lines...) Expand all
189 } 177 }
190 return boundaryPosition; 178 return boundaryPosition;
191 } 179 }
192 180
193 DEFINE_TRACE(MultipartImageResourceParser) 181 DEFINE_TRACE(MultipartImageResourceParser)
194 { 182 {
195 visitor->trace(m_client); 183 visitor->trace(m_client);
196 } 184 }
197 185
198 } // namespace blink 186 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698